Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

Linux/drivers/staging/comedi/drivers/cb_pcimdas.c

  1 /*
  2     comedi/drivers/cb_pcimdas.c
  3     Comedi driver for Computer Boards PCIM-DAS1602/16
  4 
  5     COMEDI - Linux Control and Measurement Device Interface
  6     Copyright (C) 2000 David A. Schleef <ds@schleef.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 /*
 19 Driver: cb_pcimdas
 20 Description: Measurement Computing PCI Migration series boards
 21 Devices: [ComputerBoards] PCIM-DAS1602/16 (cb_pcimdas)
 22 Author: Richard Bytheway
 23 Updated: Wed, 13 Nov 2002 12:34:56 +0000
 24 Status: experimental
 25 
 26 Written to support the PCIM-DAS1602/16 on a 2.4 series kernel.
 27 
 28 Configuration Options:
 29     [0] - PCI bus number
 30     [1] - PCI slot number
 31 
 32 Developed from cb_pcidas and skel by Richard Bytheway (mocelet@sucs.org).
 33 Only supports DIO, AO and simple AI in it's present form.
 34 No interrupts, multi channel or FIFO AI, although the card looks like it could support this.
 35 See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details.
 36 */
 37 
 38 #include <linux/module.h>
 39 #include <linux/pci.h>
 40 #include <linux/interrupt.h>
 41 
 42 #include "../comedidev.h"
 43 
 44 #include "plx9052.h"
 45 #include "8255.h"
 46 
 47 /* Registers for the PCIM-DAS1602/16 */
 48 
 49 /* sizes of io regions (bytes) */
 50 #define BADR3_SIZE 16
 51 
 52 /* DAC Offsets */
 53 #define ADC_TRIG 0
 54 #define DAC0_OFFSET 2
 55 #define DAC1_OFFSET 4
 56 
 57 /* AI and Counter Constants */
 58 #define MUX_LIMITS 0
 59 #define MAIN_CONN_DIO 1
 60 #define ADC_STAT 2
 61 #define ADC_CONV_STAT 3
 62 #define ADC_INT 4
 63 #define ADC_PACER 5
 64 #define BURST_MODE 6
 65 #define PROG_GAIN 7
 66 #define CLK8254_1_DATA 8
 67 #define CLK8254_2_DATA 9
 68 #define CLK8254_3_DATA 10
 69 #define CLK8254_CONTROL 11
 70 #define USER_COUNTER 12
 71 #define RESID_COUNT_H 13
 72 #define RESID_COUNT_L 14
 73 
 74 /*
 75  * this structure is for data unique to this hardware driver.  If
 76  * several hardware drivers keep similar information in this structure,
 77  * feel free to suggest moving the variable to the struct comedi_device
 78  * struct.
 79  */
 80 struct cb_pcimdas_private {
 81         /* base addresses */
 82         unsigned long BADR3;
 83 
 84         /* Used for AO readback */
 85         unsigned int ao_readback[2];
 86 };
 87 
 88 static int cb_pcimdas_ai_eoc(struct comedi_device *dev,
 89                              struct comedi_subdevice *s,
 90                              struct comedi_insn *insn,
 91                              unsigned long context)
 92 {
 93         struct cb_pcimdas_private *devpriv = dev->private;
 94         unsigned int status;
 95 
 96         status = inb(devpriv->BADR3 + 2);
 97         if ((status & 0x80) == 0)
 98                 return 0;
 99         return -EBUSY;
100 }
101 
102 static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
103                                struct comedi_subdevice *s,
104                                struct comedi_insn *insn, unsigned int *data)
105 {
106         struct cb_pcimdas_private *devpriv = dev->private;
107         int n;
108         unsigned int d;
109         int chan = CR_CHAN(insn->chanspec);
110         unsigned short chanlims;
111         int maxchans;
112         int ret;
113 
114         /*  only support sw initiated reads from a single channel */
115 
116         /* check channel number */
117         if ((inb(devpriv->BADR3 + 2) & 0x20) == 0)      /* differential mode */
118                 maxchans = s->n_chan / 2;
119         else
120                 maxchans = s->n_chan;
121 
122         if (chan > (maxchans - 1))
123                 return -ETIMEDOUT;      /* *** Wrong error code. Fixme. */
124 
125         /* configure for sw initiated read */
126         d = inb(devpriv->BADR3 + 5);
127         if ((d & 0x03) > 0) {   /* only reset if needed. */
128                 d = d & 0xfd;
129                 outb(d, devpriv->BADR3 + 5);
130         }
131         outb(0x01, devpriv->BADR3 + 6); /* set bursting off, conversions on */
132         outb(0x00, devpriv->BADR3 + 7); /* set range to 10V. UP/BP is controlled by a switch on the board */
133 
134         /*
135          * write channel limits to multiplexer, set Low (bits 0-3) and
136          * High (bits 4-7) channels to chan.
137          */
138         chanlims = chan | (chan << 4);
139         outb(chanlims, devpriv->BADR3 + 0);
140 
141         /* convert n samples */
142         for (n = 0; n < insn->n; n++) {
143                 /* trigger conversion */
144                 outw(0, dev->iobase + 0);
145 
146                 /* wait for conversion to end */
147                 ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0);
148                 if (ret)
149                         return ret;
150 
151                 /* read data */
152                 data[n] = inw(dev->iobase + 0);
153         }
154 
155         /* return the number of samples read/written */
156         return n;
157 }
158 
159 static int cb_pcimdas_ao_winsn(struct comedi_device *dev,
160                                struct comedi_subdevice *s,
161                                struct comedi_insn *insn, unsigned int *data)
162 {
163         struct cb_pcimdas_private *devpriv = dev->private;
164         int i;
165         int chan = CR_CHAN(insn->chanspec);
166 
167         /* Writing a list of values to an AO channel is probably not
168          * very useful, but that's how the interface is defined. */
169         for (i = 0; i < insn->n; i++) {
170                 switch (chan) {
171                 case 0:
172                         outw(data[i] & 0x0FFF, dev->iobase + DAC0_OFFSET);
173                         break;
174                 case 1:
175                         outw(data[i] & 0x0FFF, dev->iobase + DAC1_OFFSET);
176                         break;
177                 default:
178                         return -1;
179                 }
180                 devpriv->ao_readback[chan] = data[i];
181         }
182 
183         /* return the number of samples read/written */
184         return i;
185 }
186 
187 /* AO subdevices should have a read insn as well as a write insn.
188  * Usually this means copying a value stored in devpriv. */
189 static int cb_pcimdas_ao_rinsn(struct comedi_device *dev,
190                                struct comedi_subdevice *s,
191                                struct comedi_insn *insn, unsigned int *data)
192 {
193         struct cb_pcimdas_private *devpriv = dev->private;
194         int i;
195         int chan = CR_CHAN(insn->chanspec);
196 
197         for (i = 0; i < insn->n; i++)
198                 data[i] = devpriv->ao_readback[chan];
199 
200         return i;
201 }
202 
203 static int cb_pcimdas_auto_attach(struct comedi_device *dev,
204                                             unsigned long context_unused)
205 {
206         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
207         struct cb_pcimdas_private *devpriv;
208         struct comedi_subdevice *s;
209         unsigned long iobase_8255;
210         int ret;
211 
212         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
213         if (!devpriv)
214                 return -ENOMEM;
215 
216         ret = comedi_pci_enable(dev);
217         if (ret)
218                 return ret;
219 
220         dev->iobase = pci_resource_start(pcidev, 2);
221         devpriv->BADR3 = pci_resource_start(pcidev, 3);
222         iobase_8255 = pci_resource_start(pcidev, 4);
223 
224         ret = comedi_alloc_subdevices(dev, 3);
225         if (ret)
226                 return ret;
227 
228         s = &dev->subdevices[0];
229         /* dev->read_subdev=s; */
230         /*  analog input subdevice */
231         s->type = COMEDI_SUBD_AI;
232         s->subdev_flags = SDF_READABLE | SDF_GROUND;
233         s->n_chan = 16;
234         s->maxdata = 0xffff;
235         s->range_table = &range_unknown;
236         s->len_chanlist = 1;    /*  This is the maximum chanlist length that */
237         /*  the board can handle */
238         s->insn_read = cb_pcimdas_ai_rinsn;
239 
240         s = &dev->subdevices[1];
241         /*  analog output subdevice */
242         s->type = COMEDI_SUBD_AO;
243         s->subdev_flags = SDF_WRITABLE;
244         s->n_chan = 2;
245         s->maxdata = 0xfff;
246         /* ranges are hardware settable, but not software readable. */
247         s->range_table = &range_unknown;
248         s->insn_write = &cb_pcimdas_ao_winsn;
249         s->insn_read = &cb_pcimdas_ao_rinsn;
250 
251         s = &dev->subdevices[2];
252         /* digital i/o subdevice */
253         ret = subdev_8255_init(dev, s, NULL, iobase_8255);
254         if (ret)
255                 return ret;
256 
257         return 0;
258 }
259 
260 static void cb_pcimdas_detach(struct comedi_device *dev)
261 {
262         if (dev->irq)
263                 free_irq(dev->irq, dev);
264         comedi_pci_disable(dev);
265 }
266 
267 static struct comedi_driver cb_pcimdas_driver = {
268         .driver_name    = "cb_pcimdas",
269         .module         = THIS_MODULE,
270         .auto_attach    = cb_pcimdas_auto_attach,
271         .detach         = cb_pcimdas_detach,
272 };
273 
274 static int cb_pcimdas_pci_probe(struct pci_dev *dev,
275                                 const struct pci_device_id *id)
276 {
277         return comedi_pci_auto_config(dev, &cb_pcimdas_driver,
278                                       id->driver_data);
279 }
280 
281 static const struct pci_device_id cb_pcimdas_pci_table[] = {
282         { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0056) },
283         { 0 }
284 };
285 MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
286 
287 static struct pci_driver cb_pcimdas_pci_driver = {
288         .name           = "cb_pcimdas",
289         .id_table       = cb_pcimdas_pci_table,
290         .probe          = cb_pcimdas_pci_probe,
291         .remove         = comedi_pci_auto_unconfig,
292 };
293 module_comedi_pci_driver(cb_pcimdas_driver, cb_pcimdas_pci_driver);
294 
295 MODULE_AUTHOR("Comedi http://www.comedi.org");
296 MODULE_DESCRIPTION("Comedi low-level driver");
297 MODULE_LICENSE("GPL");
298 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us