Version:  2.0.40 2.2.26 2.4.37 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 3.16

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

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