Version:  2.0.40 2.2.26 2.4.37 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 3.17 3.18 3.19 4.0

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

  1 /*
  2  * comedi/drivers/cb_pcimdas.c
  3  * Comedi driver for Computer Boards PCIM-DAS1602/16 and PCIe-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 /*
 20  * Driver: cb_pcimdas
 21  * Description: Measurement Computing PCI Migration series boards
 22  * Devices: [ComputerBoards] PCIM-DAS1602/16 (cb_pcimdas), PCIe-DAS1602/16
 23  * Author: Richard Bytheway
 24  * Updated: Mon, 13 Oct 2014 11:57:39 +0000
 25  * Status: experimental
 26  *
 27  * Written to support the PCIM-DAS1602/16 and PCIe-DAS1602/16.
 28  *
 29  * Configuration Options:
 30  *   none
 31  *
 32  * Manual configuration of PCI(e) cards is not supported; they are configured
 33  * automatically.
 34  *
 35  * Developed from cb_pcidas and skel by Richard Bytheway (mocelet@sucs.org).
 36  * Only supports DIO, AO and simple AI in it's present form.
 37  * No interrupts, multi channel or FIFO AI,
 38  * although the card looks like it could support this.
 39  *
 40  * http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf
 41  * http://www.mccdaq.com/PDFs/Manuals/pcie-das1602-16.pdf
 42  */
 43 
 44 #include <linux/module.h>
 45 #include <linux/pci.h>
 46 #include <linux/interrupt.h>
 47 
 48 #include "../comedidev.h"
 49 
 50 #include "plx9052.h"
 51 #include "8255.h"
 52 
 53 /* Registers for the PCIM-DAS1602/16 and PCIe-DAS1602/16 */
 54 
 55 /* DAC Offsets */
 56 #define ADC_TRIG 0
 57 #define DAC0_OFFSET 2
 58 #define DAC1_OFFSET 4
 59 
 60 /* AI and Counter Constants */
 61 #define MUX_LIMITS 0
 62 #define MAIN_CONN_DIO 1
 63 #define ADC_STAT 2
 64 #define ADC_CONV_STAT 3
 65 #define ADC_INT 4
 66 #define ADC_PACER 5
 67 #define BURST_MODE 6
 68 #define PROG_GAIN 7
 69 #define CLK8254_1_DATA 8
 70 #define CLK8254_2_DATA 9
 71 #define CLK8254_3_DATA 10
 72 #define CLK8254_CONTROL 11
 73 #define USER_COUNTER 12
 74 #define RESID_COUNT_H 13
 75 #define RESID_COUNT_L 14
 76 
 77 /*
 78  * this structure is for data unique to this hardware driver.  If
 79  * several hardware drivers keep similar information in this structure,
 80  * feel free to suggest moving the variable to the struct comedi_device
 81  * struct.
 82  */
 83 struct cb_pcimdas_private {
 84         /* base addresses */
 85         unsigned long daqio;
 86         unsigned long BADR3;
 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, devpriv->daqio + 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(devpriv->daqio + 0);
158         }
159 
160         /* return the number of samples read/written */
161         return n;
162 }
163 
164 static int cb_pcimdas_ao_insn_write(struct comedi_device *dev,
165                                     struct comedi_subdevice *s,
166                                     struct comedi_insn *insn,
167                                     unsigned int *data)
168 {
169         struct cb_pcimdas_private *devpriv = dev->private;
170         unsigned int chan = CR_CHAN(insn->chanspec);
171         unsigned int val = s->readback[chan];
172         unsigned int reg = (chan) ? DAC1_OFFSET : DAC0_OFFSET;
173         int i;
174 
175         for (i = 0; i < insn->n; i++) {
176                 val = data[i];
177                 outw(val, devpriv->daqio + reg);
178         }
179         s->readback[chan] = val;
180 
181         return insn->n;
182 }
183 
184 static int cb_pcimdas_auto_attach(struct comedi_device *dev,
185                                             unsigned long context_unused)
186 {
187         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
188         struct cb_pcimdas_private *devpriv;
189         struct comedi_subdevice *s;
190         int ret;
191 
192         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
193         if (!devpriv)
194                 return -ENOMEM;
195 
196         ret = comedi_pci_enable(dev);
197         if (ret)
198                 return ret;
199 
200         devpriv->daqio = pci_resource_start(pcidev, 2);
201         devpriv->BADR3 = pci_resource_start(pcidev, 3);
202         dev->iobase = pci_resource_start(pcidev, 4);
203 
204         ret = comedi_alloc_subdevices(dev, 3);
205         if (ret)
206                 return ret;
207 
208         s = &dev->subdevices[0];
209         /* dev->read_subdev=s; */
210         /*  analog input subdevice */
211         s->type = COMEDI_SUBD_AI;
212         s->subdev_flags = SDF_READABLE | SDF_GROUND;
213         s->n_chan = 16;
214         s->maxdata = 0xffff;
215         s->range_table = &range_unknown;
216         s->len_chanlist = 1;    /*  This is the maximum chanlist length that */
217         /*  the board can handle */
218         s->insn_read = cb_pcimdas_ai_rinsn;
219 
220         s = &dev->subdevices[1];
221         /*  analog output subdevice */
222         s->type = COMEDI_SUBD_AO;
223         s->subdev_flags = SDF_WRITABLE;
224         s->n_chan = 2;
225         s->maxdata = 0xfff;
226         /* ranges are hardware settable, but not software readable. */
227         s->range_table = &range_unknown;
228         s->insn_write = cb_pcimdas_ao_insn_write;
229 
230         ret = comedi_alloc_subdev_readback(s);
231         if (ret)
232                 return ret;
233 
234         s = &dev->subdevices[2];
235         /* digital i/o subdevice */
236         ret = subdev_8255_init(dev, s, NULL, 0x00);
237         if (ret)
238                 return ret;
239 
240         return 0;
241 }
242 
243 static struct comedi_driver cb_pcimdas_driver = {
244         .driver_name    = "cb_pcimdas",
245         .module         = THIS_MODULE,
246         .auto_attach    = cb_pcimdas_auto_attach,
247         .detach         = comedi_pci_detach,
248 };
249 
250 static int cb_pcimdas_pci_probe(struct pci_dev *dev,
251                                 const struct pci_device_id *id)
252 {
253         return comedi_pci_auto_config(dev, &cb_pcimdas_driver,
254                                       id->driver_data);
255 }
256 
257 static const struct pci_device_id cb_pcimdas_pci_table[] = {
258         { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0056) },       /* PCIM-DAS1602/16 */
259         { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0115) },       /* PCIe-DAS1602/16 */
260         { 0 }
261 };
262 MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
263 
264 static struct pci_driver cb_pcimdas_pci_driver = {
265         .name           = "cb_pcimdas",
266         .id_table       = cb_pcimdas_pci_table,
267         .probe          = cb_pcimdas_pci_probe,
268         .remove         = comedi_pci_auto_unconfig,
269 };
270 module_comedi_pci_driver(cb_pcimdas_driver, cb_pcimdas_pci_driver);
271 
272 MODULE_AUTHOR("Comedi http://www.comedi.org");
273 MODULE_DESCRIPTION("Comedi driver for PCIM-DAS1602/16 and PCIe-DAS1602/16");
274 MODULE_LICENSE("GPL");
275 

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