Merge remote-tracking branch 'upstream' into next
[cascardo/linux.git] / drivers / staging / comedi / drivers / cb_pcimdda.c
1 /*
2     comedi/drivers/cb_pcimdda.c
3     Computer Boards PCIM-DDA06-16 Comedi driver
4     Author: Calin Culianu <calin@ajvar.org>
5
6     COMEDI - Linux Control and Measurement Device Interface
7     Copyright (C) 2000 David A. Schleef <ds@schleef.org>
8
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23 */
24 /*
25 Driver: cb_pcimdda
26 Description: Measurement Computing PCIM-DDA06-16
27 Devices: [Measurement Computing] PCIM-DDA06-16 (cb_pcimdda)
28 Author: Calin Culianu <calin@ajvar.org>
29 Updated: Mon, 14 Apr 2008 15:15:51 +0100
30 Status: works
31
32 All features of the PCIM-DDA06-16 board are supported.  This board
33 has 6 16-bit AO channels, and the usual 8255 DIO setup.  (24 channels,
34 configurable in banks of 8 and 4, etc.).  This board does not support commands.
35
36 The board has a peculiar way of specifying AO gain/range settings -- You have
37 1 jumper bank on the card, which either makes all 6 AO channels either
38 5 Volt unipolar, 5V bipolar, 10 Volt unipolar or 10V bipolar.
39
40 Since there is absolutely _no_ way to tell in software how this jumper is set
41 (well, at least according  to the rather thin spec. from Measurement Computing
42  that comes with the board), the driver assumes the jumper is at its factory
43 default setting of +/-5V.
44
45 Also of note is the fact that this board features another jumper, whose
46 state is also completely invisible to software.  It toggles two possible AO
47 output modes on the board:
48
49   - Update Mode: Writing to an AO channel instantaneously updates the actual
50     signal output by the DAC on the board (this is the factory default).
51   - Simultaneous XFER Mode: Writing to an AO channel has no effect until
52     you read from any one of the AO channels.  This is useful for loading
53     all 6 AO values, and then reading from any one of the AO channels on the
54     device to instantly update all 6 AO values in unison.  Useful for some
55     control apps, I would assume?  If your jumper is in this setting, then you
56     need to issue your comedi_data_write()s to load all the values you want,
57     then issue one comedi_data_read() on any channel on the AO subdevice
58     to initiate the simultaneous XFER.
59
60 Configuration Options:
61   [0] PCI bus (optional)
62   [1] PCI slot (optional)
63   [2] analog output range jumper setting
64       0 == +/- 5 V
65       1 == +/- 10 V
66 */
67
68 /*
69     This is a driver for the Computer Boards PCIM-DDA06-16 Analog Output
70     card.  This board has a unique register layout and as such probably
71     deserves its own driver file.
72
73     It is theoretically possible to integrate this board into the cb_pcidda
74     file, but since that isn't my code, I didn't want to significantly
75     modify that file to support this board (I thought it impolite to do so).
76
77     At any rate, if you feel ambitious, please feel free to take
78     the code out of this file and combine it with a more unified driver
79     file.
80
81     I would like to thank Timothy Curry <Timothy.Curry@rdec.redstone.army.mil>
82     for lending me a board so that I could write this driver.
83
84     -Calin Culianu <calin@ajvar.org>
85  */
86
87 #include "../comedidev.h"
88
89 #include "8255.h"
90
91 /* device ids of the cards we support -- currently only 1 card supported */
92 #define PCI_VENDOR_ID_COMPUTERBOARDS    0x1307
93 #define PCI_ID_PCIM_DDA06_16            0x0053
94
95 /*
96  * This is straight from skel.c -- I did this in case this source file
97  * will someday support more than 1 board...
98  */
99 struct board_struct {
100         const char *name;
101         unsigned short device_id;
102         int ao_chans;
103         int ao_bits;
104         int dio_chans;
105         int dio_method;
106         /* how many bytes into the BADR are the DIO ports */
107         int dio_offset;
108         int regs_badrindex;     /* IO Region for the control, analog output,
109                                    and DIO registers */
110         int reg_sz;             /* number of bytes of registers in io region */
111 };
112
113 enum DIO_METHODS {
114         DIO_NONE = 0,
115         DIO_8255,
116         DIO_INTERNAL            /* unimplemented */
117 };
118
119 static const struct board_struct boards[] = {
120         {
121          .name = "cb_pcimdda06-16",
122          .device_id = PCI_ID_PCIM_DDA06_16,
123          .ao_chans = 6,
124          .ao_bits = 16,
125          .dio_chans = 24,
126          .dio_method = DIO_8255,
127          .dio_offset = 12,
128          .regs_badrindex = 3,
129          .reg_sz = 16,
130          }
131 };
132
133 /*
134  * Useful for shorthand access to the particular board structure
135  */
136 #define thisboard    ((const struct board_struct *)dev->board_ptr)
137
138 #define REG_SZ (thisboard->reg_sz)
139 #define REGS_BADRINDEX (thisboard->regs_badrindex)
140
141 /*
142  * this structure is for data unique to this hardware driver.  If
143  * several hardware drivers keep similar information in this structure,
144  * feel free to suggest moving the variable to the struct comedi_device
145  * struct.
146  */
147 struct board_private_struct {
148         unsigned long registers;        /* set by probe */
149         unsigned long dio_registers;
150         char attached_to_8255;  /* boolean */
151         /* would be useful for a PCI device */
152         struct pci_dev *pci_dev;
153
154 #define MAX_AO_READBACK_CHANNELS 6
155         /* Used for AO readback */
156         unsigned int ao_readback[MAX_AO_READBACK_CHANNELS];
157
158 };
159
160 /*
161  * most drivers define the following macro to make it easy to
162  * access the private structure.
163  */
164 #define devpriv ((struct board_private_struct *)dev->private)
165
166 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
167                     struct comedi_insn *insn, unsigned int *data);
168 static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
169                     struct comedi_insn *insn, unsigned int *data);
170
171 /*---------------------------------------------------------------------------
172   HELPER FUNCTION DECLARATIONS
173 -----------------------------------------------------------------------------*/
174
175 /* returns a maxdata value for a given n_bits */
176 static inline unsigned int figure_out_maxdata(int bits)
177 {
178         return ((unsigned int)1 << bits) - 1;
179 }
180
181 /*
182  *  Probes for a supported device.
183  *
184  *  Prerequisite: private be allocated already inside dev
185  *
186  *  If the device is found, it returns 0 and has the following side effects:
187  *
188  *  o  assigns a struct pci_dev * to dev->private->pci_dev
189  *  o  assigns a struct board * to dev->board_ptr
190  *  o  sets dev->private->registers
191  *  o  sets dev->private->dio_registers
192  *
193  *  Otherwise, returns a -errno on error
194  */
195 static int probe(struct comedi_device *dev, const struct comedi_devconfig *it);
196
197 /*---------------------------------------------------------------------------
198   FUNCTION DEFINITIONS
199 -----------------------------------------------------------------------------*/
200
201 /*
202  * Attach is called by the Comedi core to configure the driver
203  * for a particular board.  If you specified a board_name array
204  * in the driver structure, dev->board_ptr contains that
205  * address.
206  */
207 static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
208 {
209         struct comedi_subdevice *s;
210         int err;
211
212 /*
213  * Allocate the private structure area.  alloc_private() is a
214  * convenient macro defined in comedidev.h.
215  * if this function fails (returns negative) then the private area is
216  * kfree'd by comedi
217  */
218         if (alloc_private(dev, sizeof(struct board_private_struct)) < 0)
219                 return -ENOMEM;
220
221 /*
222  * If you can probe the device to determine what device in a series
223  * it is, this is the place to do it.  Otherwise, dev->board_ptr
224  * should already be initialized.
225  */
226         err = probe(dev, it);
227         if (err)
228                 return err;
229
230 /* Output some info */
231         printk("comedi%d: %s: ", dev->minor, thisboard->name);
232
233 /*
234  * Initialize dev->board_name.  Note that we can use the "thisboard"
235  * macro now, since we just initialized it in the last line.
236  */
237         dev->board_name = thisboard->name;
238
239         err = comedi_alloc_subdevices(dev, 2);
240         if (err)
241                 return err;
242
243         s = dev->subdevices + 0;
244
245         /* analog output subdevice */
246         s->type = COMEDI_SUBD_AO;
247         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
248         s->n_chan = thisboard->ao_chans;
249         s->maxdata = figure_out_maxdata(thisboard->ao_bits);
250         /* this is hard-coded here */
251         if (it->options[2])
252                 s->range_table = &range_bipolar10;
253         else
254                 s->range_table = &range_bipolar5;
255         s->insn_write = &ao_winsn;
256         s->insn_read = &ao_rinsn;
257
258         s = dev->subdevices + 1;
259         /* digital i/o subdevice */
260         if (thisboard->dio_chans) {
261                 switch (thisboard->dio_method) {
262                 case DIO_8255:
263                         /*
264                          * this is a straight 8255, so register us with
265                          * the 8255 driver
266                          */
267                         subdev_8255_init(dev, s, NULL, devpriv->dio_registers);
268                         devpriv->attached_to_8255 = 1;
269                         break;
270                 case DIO_INTERNAL:
271                 default:
272                         printk("DIO_INTERNAL not implemented yet!\n");
273                         return -ENXIO;
274                         break;
275                 }
276         } else {
277                 s->type = COMEDI_SUBD_UNUSED;
278         }
279
280         printk("attached\n");
281
282         return 1;
283 }
284
285 static void detach(struct comedi_device *dev)
286 {
287         if (devpriv) {
288                 if (dev->subdevices && devpriv->attached_to_8255) {
289                         subdev_8255_cleanup(dev, dev->subdevices + 2);
290                         devpriv->attached_to_8255 = 0;
291                 }
292                 if (devpriv->pci_dev) {
293                         if (devpriv->registers)
294                                 comedi_pci_disable(devpriv->pci_dev);
295                         pci_dev_put(devpriv->pci_dev);
296                 }
297         }
298 }
299
300 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
301                     struct comedi_insn *insn, unsigned int *data)
302 {
303         int i;
304         int chan = CR_CHAN(insn->chanspec);
305         unsigned long offset = devpriv->registers + chan * 2;
306
307         /* Writing a list of values to an AO channel is probably not
308          * very useful, but that's how the interface is defined. */
309         for (i = 0; i < insn->n; i++) {
310                 /*  first, load the low byte */
311                 outb((char)(data[i] & 0x00ff), offset);
312                 /*  next, write the high byte -- only after this is written is
313                    the channel voltage updated in the DAC, unless
314                    we're in simultaneous xfer mode (jumper on card)
315                    then a rinsn is necessary to actually update the DAC --
316                    see ao_rinsn() below... */
317                 outb((char)(data[i] >> 8 & 0x00ff), offset + 1);
318
319                 /* for testing only.. the actual rinsn SHOULD do an inw!
320                    (see the stuff about simultaneous XFER mode on this board) */
321                 devpriv->ao_readback[chan] = data[i];
322         }
323
324         /* return the number of samples read/written */
325         return i;
326 }
327
328 /* AO subdevices should have a read insn as well as a write insn.
329
330    Usually this means copying a value stored in devpriv->ao_readback.
331    However, since this board has this jumper setting called "Simultaneous
332    Xfer mode" (off by default), we will support it.  Simultaneaous xfer
333    mode is accomplished by loading ALL the values you want for AO in all the
334    channels, then READing off one of the AO registers to initiate the
335    instantaneous simultaneous update of all DAC outputs, which makes
336    all AO channels update simultaneously.  This is useful for some control
337    applications, I would imagine.
338 */
339 static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
340                     struct comedi_insn *insn, unsigned int *data)
341 {
342         int i;
343         int chan = CR_CHAN(insn->chanspec);
344
345         for (i = 0; i < insn->n; i++) {
346                 inw(devpriv->registers + chan * 2);
347                 /*
348                  * should I set data[i] to the result of the actual read
349                  * on the register or the cached unsigned int in
350                  * devpriv->ao_readback[]?
351                  */
352                 data[i] = devpriv->ao_readback[chan];
353         }
354
355         return i;
356 }
357
358 /*---------------------------------------------------------------------------
359   HELPER FUNCTION DEFINITIONS
360 -----------------------------------------------------------------------------*/
361
362 /*
363  *  Probes for a supported device.
364  *
365  *  Prerequisite: private be allocated already inside dev
366  *
367  *  If the device is found, it returns 0 and has the following side effects:
368  *
369  *  o  assigns a struct pci_dev * to dev->private->pci_dev
370  *  o  assigns a struct board * to dev->board_ptr
371  *  o  sets dev->private->registers
372  *  o  sets dev->private->dio_registers
373  *
374  *  Otherwise, returns a -errno on error
375  */
376 static int probe(struct comedi_device *dev, const struct comedi_devconfig *it)
377 {
378         struct pci_dev *pcidev = NULL;
379         int index;
380         unsigned long registers;
381
382         for_each_pci_dev(pcidev) {
383                 /*  is it not a computer boards card? */
384                 if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
385                         continue;
386                 /*  loop through cards supported by this driver */
387                 for (index = 0; index < ARRAY_SIZE(boards); index++) {
388                         if (boards[index].device_id != pcidev->device)
389                                 continue;
390                         /*  was a particular bus/slot requested? */
391                         if (it->options[0] || it->options[1]) {
392                                 /*  are we on the wrong bus/slot? */
393                                 if (pcidev->bus->number != it->options[0] ||
394                                     PCI_SLOT(pcidev->devfn) != it->options[1]) {
395                                         continue;
396                                 }
397                         }
398                         /* found ! */
399
400                         devpriv->pci_dev = pcidev;
401                         dev->board_ptr = boards + index;
402                         if (comedi_pci_enable(pcidev, thisboard->name)) {
403                                 printk
404                                     ("cb_pcimdda: Failed to enable PCI device and request regions\n");
405                                 return -EIO;
406                         }
407                         registers =
408                             pci_resource_start(devpriv->pci_dev,
409                                                REGS_BADRINDEX);
410                         devpriv->registers = registers;
411                         devpriv->dio_registers
412                             = devpriv->registers + thisboard->dio_offset;
413                         return 0;
414                 }
415         }
416
417         printk("cb_pcimdda: No supported ComputerBoards/MeasurementComputing "
418                "card found at the requested position\n");
419         return -ENODEV;
420 }
421
422 static struct comedi_driver cb_pcimdda_driver = {
423         .driver_name    = "cb_pcimdda",
424         .module         = THIS_MODULE,
425         .attach         = attach,
426         .detach         = detach,
427 };
428
429 static int __devinit cb_pcimdda_pci_probe(struct pci_dev *dev,
430                                           const struct pci_device_id *ent)
431 {
432         return comedi_pci_auto_config(dev, &cb_pcimdda_driver);
433 }
434
435 static void __devexit cb_pcimdda_pci_remove(struct pci_dev *dev)
436 {
437         comedi_pci_auto_unconfig(dev);
438 }
439
440 static DEFINE_PCI_DEVICE_TABLE(cb_pcimdda_pci_table) = {
441         { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) },
442         { 0 }
443 };
444 MODULE_DEVICE_TABLE(pci, cb_pcimdda_pci_table);
445
446 static struct pci_driver cb_pcimdda_driver_pci_driver = {
447         .name           = "cb_pcimdda",
448         .id_table       = cb_pcimdda_pci_table,
449         .probe          = cb_pcimdda_pci_probe,
450         .remove         = __devexit_p(cb_pcimdda_pci_remove),
451 };
452 module_comedi_pci_driver(cb_pcimdda_driver, cb_pcimdda_driver_pci_driver);
453
454 MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>");
455 MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
456                    "series.  Currently only supports PCIM-DDA06-16 (which "
457                    "also happens to be the only board in this series. :) ) ");
458 MODULE_LICENSE("GPL");