Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-2.6] / 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 MIN(a,b) ( ((a) < (b)) ? (a) : (b) )
59 #define SDEV_NO ((int)(s - dev->subdevices))
60 #define CHANS 8
61 #define IOSIZE 16
62 #define LSB(x) ((unsigned char)((x) & 0xff))
63 #define MSB(x) ((unsigned char)((((unsigned short)(x))>>8) & 0xff))
64 #define LSB_PORT(chan) (dev->iobase + (chan)*2)
65 #define MSB_PORT(chan) (LSB_PORT(chan)+1)
66 #define BITS 12
67
68 /*
69  * Bords
70  */
71 struct pcmda12_board {
72         const char *name;
73 };
74
75 /* note these have no effect and are merely here for reference..
76    these are configured by jumpering the board! */
77 static const struct comedi_lrange pcmda12_ranges = {
78         3,
79         {
80                         UNI_RANGE(5), UNI_RANGE(10), BIP_RANGE(5)
81                 }
82 };
83
84 static const struct pcmda12_board pcmda12_boards[] = {
85         {
86               name:     "pcmda12",
87                 },
88 };
89
90 /*
91  * Useful for shorthand access to the particular board structure
92  */
93 #define thisboard ((const struct pcmda12_board *)dev->board_ptr)
94
95 struct pcmda12_private {
96
97         unsigned int ao_readback[CHANS];
98         int simultaneous_xfer_mode;
99 };
100
101
102 #define devpriv ((struct pcmda12_private *)(dev->private))
103
104 /*
105  * The struct comedi_driver structure tells the Comedi core module
106  * which functions to call to configure/deconfigure (attach/detach)
107  * the board, and also about the kernel module that contains
108  * the device code.
109  */
110 static int pcmda12_attach(struct comedi_device * dev, struct comedi_devconfig * it);
111 static int pcmda12_detach(struct comedi_device * dev);
112
113 static void zero_chans(struct comedi_device * dev);
114
115 static struct comedi_driver driver = {
116       driver_name:"pcmda12",
117       module:THIS_MODULE,
118       attach:pcmda12_attach,
119       detach:pcmda12_detach,
120 /* It is not necessary to implement the following members if you are
121  * writing a driver for a ISA PnP or PCI card */
122         /* Most drivers will support multiple types of boards by
123          * having an array of board structures.  These were defined
124          * in pcmda12_boards[] above.  Note that the element 'name'
125          * was first in the structure -- Comedi uses this fact to
126          * extract the name of the board without knowing any details
127          * about the structure except for its length.
128          * When a device is attached (by comedi_config), the name
129          * of the device is given to Comedi, and Comedi tries to
130          * match it by going through the list of board names.  If
131          * there is a match, the address of the pointer is put
132          * into dev->board_ptr and driver->attach() is called.
133          *
134          * Note that these are not necessary if you can determine
135          * the type of board in software.  ISA PnP, PCI, and PCMCIA
136          * devices are such boards.
137          */
138       board_name:&pcmda12_boards[0].name,
139       offset:sizeof(struct pcmda12_board),
140       num_names:sizeof(pcmda12_boards) / sizeof(struct pcmda12_board),
141 };
142
143 static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
144         struct comedi_insn * insn, unsigned int * data);
145 static int ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
146         struct comedi_insn * insn, unsigned int * data);
147
148 /*
149  * Attach is called by the Comedi core to configure the driver
150  * for a particular board.  If you specified a board_name array
151  * in the driver structure, dev->board_ptr contains that
152  * address.
153  */
154 static int pcmda12_attach(struct comedi_device * dev, struct comedi_devconfig * it)
155 {
156         struct comedi_subdevice *s;
157         unsigned long iobase;
158
159         iobase = it->options[0];
160         printk("comedi%d: %s: io: %lx %s ", dev->minor, driver.driver_name,
161                 iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
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  */
179         if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) {
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  */
223 static int pcmda12_detach(struct comedi_device * dev)
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
231 static void zero_chans(struct comedi_device * dev)
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
244 static int ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
245         struct comedi_insn * insn, unsigned int * data)
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 */
286 static int ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
287         struct comedi_insn * insn, unsigned int * data)
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  */
306 COMEDI_INITCLEANUP(driver);