staging: comedi das08_cs.c: Fix io_req_t conversion
[GitHub/mt8127/android_kernel_alcatel_ttab.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 /*
68 * Bords
69 */
70 struct pcmda12_board {
71 const char *name;
72 };
73
74 /* note these have no effect and are merely here for reference..
75 these are configured by jumpering the board! */
76 static const struct comedi_lrange pcmda12_ranges = {
77 3,
78 {
79 UNI_RANGE(5), UNI_RANGE(10), BIP_RANGE(5)
80 }
81 };
82
83 static const struct pcmda12_board pcmda12_boards[] = {
84 {
85 .name = "pcmda12",
86 },
87 };
88
89 /*
90 * Useful for shorthand access to the particular board structure
91 */
92 #define thisboard ((const struct pcmda12_board *)dev->board_ptr)
93
94 struct pcmda12_private {
95
96 unsigned int ao_readback[CHANS];
97 int simultaneous_xfer_mode;
98 };
99
100 #define devpriv ((struct pcmda12_private *)(dev->private))
101
102 /*
103 * The struct comedi_driver structure tells the Comedi core module
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 */
108 static int pcmda12_attach(struct comedi_device *dev,
109 struct comedi_devconfig *it);
110 static int pcmda12_detach(struct comedi_device *dev);
111
112 static void zero_chans(struct comedi_device *dev);
113
114 static struct comedi_driver driver = {
115 .driver_name = "pcmda12",
116 .module = THIS_MODULE,
117 .attach = pcmda12_attach,
118 .detach = pcmda12_detach,
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 */
137 .board_name = &pcmda12_boards[0].name,
138 .offset = sizeof(struct pcmda12_board),
139 .num_names = ARRAY_SIZE(pcmda12_boards),
140 };
141
142 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
143 struct comedi_insn *insn, unsigned int *data);
144 static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
145 struct comedi_insn *insn, unsigned int *data);
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 */
153 static int pcmda12_attach(struct comedi_device *dev,
154 struct comedi_devconfig *it)
155 {
156 struct comedi_subdevice *s;
157 unsigned long iobase;
158
159 iobase = it->options[0];
160 printk(KERN_INFO
161 "comedi%d: %s: io: %lx %s ", dev->minor, driver.driver_name,
162 iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
163
164 if (!request_region(iobase, IOSIZE, driver.driver_name)) {
165 printk("I/O port conflict\n");
166 return -EIO;
167 }
168 dev->iobase = iobase;
169
170 /*
171 * Initialize dev->board_name. Note that we can use the "thisboard"
172 * macro now, since we just initialized it in the last line.
173 */
174 dev->board_name = thisboard->name;
175
176 /*
177 * Allocate the private structure area. alloc_private() is a
178 * convenient macro defined in comedidev.h.
179 */
180 if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) {
181 printk(KERN_ERR "cannot allocate private data structure\n");
182 return -ENOMEM;
183 }
184
185 devpriv->simultaneous_xfer_mode = it->options[1];
186
187 /*
188 * Allocate the subdevice structures. alloc_subdevice() is a
189 * convenient macro defined in comedidev.h.
190 *
191 * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
192 * 96-channel version of the board.
193 */
194 if (alloc_subdevices(dev, 1) < 0) {
195 printk(KERN_ERR "cannot allocate subdevice data structures\n");
196 return -ENOMEM;
197 }
198
199 s = dev->subdevices;
200 s->private = NULL;
201 s->maxdata = (0x1 << BITS) - 1;
202 s->range_table = &pcmda12_ranges;
203 s->type = COMEDI_SUBD_AO;
204 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
205 s->n_chan = CHANS;
206 s->insn_write = &ao_winsn;
207 s->insn_read = &ao_rinsn;
208
209 zero_chans(dev); /* clear out all the registers, basically */
210
211 printk(KERN_INFO "attached\n");
212
213 return 1;
214 }
215
216 /*
217 * _detach is called to deconfigure a device. It should deallocate
218 * resources.
219 * This function is also called when _attach() fails, so it should be
220 * careful not to release resources that were not necessarily
221 * allocated by _attach(). dev->private and dev->subdevices are
222 * deallocated automatically by the core.
223 */
224 static int pcmda12_detach(struct comedi_device *dev)
225 {
226 printk(KERN_INFO
227 "comedi%d: %s: remove\n", dev->minor, driver.driver_name);
228 if (dev->iobase)
229 release_region(dev->iobase, IOSIZE);
230 return 0;
231 }
232
233 static void zero_chans(struct comedi_device *dev)
234 { /* sets up an
235 ASIC chip to defaults */
236 int i;
237 for (i = 0; i < CHANS; ++i) {
238 /* /\* do this as one instruction?? *\/ */
239 /* outw(0, LSB_PORT(chan)); */
240 outb(0, LSB_PORT(i));
241 outb(0, MSB_PORT(i));
242 }
243 inb(LSB_PORT(0)); /* update chans. */
244 }
245
246 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
247 struct comedi_insn *insn, unsigned int *data)
248 {
249 int i;
250 int chan = CR_CHAN(insn->chanspec);
251
252 /* Writing a list of values to an AO channel is probably not
253 * very useful, but that's how the interface is defined. */
254 for (i = 0; i < insn->n; ++i) {
255
256 /* /\* do this as one instruction?? *\/ */
257 /* outw(data[i], LSB_PORT(chan)); */
258
259 /* Need to do this as two instructions due to 8-bit bus?? */
260 /* first, load the low byte */
261 outb(LSB(data[i]), LSB_PORT(chan));
262 /* next, write the high byte */
263 outb(MSB(data[i]), MSB_PORT(chan));
264
265 /* save shadow register */
266 devpriv->ao_readback[chan] = data[i];
267
268 if (!devpriv->simultaneous_xfer_mode)
269 inb(LSB_PORT(chan));
270 }
271
272 /* return the number of samples written */
273 return i;
274 }
275
276 /* AO subdevices should have a read insn as well as a write insn.
277
278 Usually this means copying a value stored in devpriv->ao_readback.
279 However, since this driver supports simultaneous xfer then sometimes
280 this function actually accomplishes work.
281
282 Simultaneaous xfer mode is accomplished by loading ALL the values
283 you want for AO in all the channels, then READing off one of the AO
284 registers to initiate the instantaneous simultaneous update of all
285 DAC outputs, which makes all AO channels update simultaneously.
286 This is useful for some control applications, I would imagine.
287 */
288 static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
289 struct comedi_insn *insn, unsigned int *data)
290 {
291 int i;
292 int chan = CR_CHAN(insn->chanspec);
293
294 for (i = 0; i < insn->n; i++) {
295 if (devpriv->simultaneous_xfer_mode)
296 inb(LSB_PORT(chan));
297 /* read back shadow register */
298 data[i] = devpriv->ao_readback[chan];
299 }
300
301 return i;
302 }
303
304 /*
305 * A convenient macro that defines init_module() and cleanup_module(),
306 * as necessary.
307 */
308 static int __init driver_init_module(void)
309 {
310 return comedi_driver_register(&driver);
311 }
312
313 static void __exit driver_cleanup_module(void)
314 {
315 comedi_driver_unregister(&driver);
316 }
317
318 module_init(driver_init_module);
319 module_exit(driver_cleanup_module);
320
321 MODULE_AUTHOR("Comedi http://www.comedi.org");
322 MODULE_DESCRIPTION("Comedi low-level driver");
323 MODULE_LICENSE("GPL");