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

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 /* DAC Offsets */
 51 #define ADC_TRIG 0
 52 #define DAC0_OFFSET 2
 53 #define DAC1_OFFSET 4
 54 
 55 /* AI and Counter Constants */
 56 #define MUX_LIMITS 0
 57 #define MAIN_CONN_DIO 1
 58 #define ADC_STAT 2
 59 #define ADC_CONV_STAT 3
 60 #define ADC_INT 4
 61 #define ADC_PACER 5
 62 #define BURST_MODE 6
 63 #define PROG_GAIN 7
 64 #define CLK8254_1_DATA 8
 65 #define CLK8254_2_DATA 9
 66 #define CLK8254_3_DATA 10
 67 #define CLK8254_CONTROL 11
 68 #define USER_COUNTER 12
 69 #define RESID_COUNT_H 13
 70 #define RESID_COUNT_L 14
 71 
 72 /*
 73  * this structure is for data unique to this hardware driver.  If
 74  * several hardware drivers keep similar information in this structure,
 75  * feel free to suggest moving the variable to the struct comedi_device
 76  * struct.
 77  */
 78 struct cb_pcimdas_private {
 79         /* base addresses */
 80         unsigned long daqio;
 81         unsigned long BADR3;
 82 };
 83 
 84 static int cb_pcimdas_ai_eoc(struct comedi_device *dev,
 85                              struct comedi_subdevice *s,
 86                              struct comedi_insn *insn,
 87                              unsigned long context)
 88 {
 89         struct cb_pcimdas_private *devpriv = dev->private;
 90         unsigned int status;
 91 
 92         status = inb(devpriv->BADR3 + 2);
 93         if ((status & 0x80) == 0)
 94                 return 0;
 95         return -EBUSY;
 96 }
 97 
 98 static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
 99                                struct comedi_subdevice *s,
100                                struct comedi_insn *insn, unsigned int *data)
101 {
102         struct cb_pcimdas_private *devpriv = dev->private;
103         int n;
104         unsigned int d;
105         int chan = CR_CHAN(insn->chanspec);
106         unsigned short chanlims;
107         int maxchans;
108         int ret;
109 
110         /*  only support sw initiated reads from a single channel */
111 
112         /* check channel number */
113         if ((inb(devpriv->BADR3 + 2) & 0x20) == 0)      /* differential mode */
114                 maxchans = s->n_chan / 2;
115         else
116                 maxchans = s->n_chan;
117 
118         if (chan > (maxchans - 1))
119                 return -ETIMEDOUT;      /* *** Wrong error code. Fixme. */
120 
121         /* configure for sw initiated read */
122         d = inb(devpriv->BADR3 + 5);
123         if ((d & 0x03) > 0) {   /* only reset if needed. */
124                 d = d & 0xfd;
125                 outb(d, devpriv->BADR3 + 5);
126         }
127 
128         /* set bursting off, conversions on */
129         outb(0x01, devpriv->BADR3 + 6);
130 
131         /* set range to 10V. UP/BP is controlled by a switch on the board */
132         outb(0x00, devpriv->BADR3 + 7);
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, devpriv->daqio + 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(devpriv->daqio + 0);
153         }
154 
155         /* return the number of samples read/written */
156         return n;
157 }
158 
159 static int cb_pcimdas_ao_insn_write(struct comedi_device *dev,
160                                     struct comedi_subdevice *s,
161                                     struct comedi_insn *insn,
162                                     unsigned int *data)
163 {
164         struct cb_pcimdas_private *devpriv = dev->private;
165         unsigned int chan = CR_CHAN(insn->chanspec);
166         unsigned int val = s->readback[chan];
167         unsigned int reg = (chan) ? DAC1_OFFSET : DAC0_OFFSET;
168         int i;
169 
170         for (i = 0; i < insn->n; i++) {
171                 val = data[i];
172                 outw(val, devpriv->daqio + reg);
173         }
174         s->readback[chan] = val;
175 
176         return insn->n;
177 }
178 
179 static int cb_pcimdas_auto_attach(struct comedi_device *dev,
180                                             unsigned long context_unused)
181 {
182         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
183         struct cb_pcimdas_private *devpriv;
184         struct comedi_subdevice *s;
185         int ret;
186 
187         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
188         if (!devpriv)
189                 return -ENOMEM;
190 
191         ret = comedi_pci_enable(dev);
192         if (ret)
193                 return ret;
194 
195         devpriv->daqio = pci_resource_start(pcidev, 2);
196         devpriv->BADR3 = pci_resource_start(pcidev, 3);
197         dev->iobase = pci_resource_start(pcidev, 4);
198 
199         ret = comedi_alloc_subdevices(dev, 3);
200         if (ret)
201                 return ret;
202 
203         s = &dev->subdevices[0];
204         /* dev->read_subdev=s; */
205         /*  analog input subdevice */
206         s->type = COMEDI_SUBD_AI;
207         s->subdev_flags = SDF_READABLE | SDF_GROUND;
208         s->n_chan = 16;
209         s->maxdata = 0xffff;
210         s->range_table = &range_unknown;
211         s->len_chanlist = 1;    /*  This is the maximum chanlist length that */
212         /*  the board can handle */
213         s->insn_read = cb_pcimdas_ai_rinsn;
214 
215         s = &dev->subdevices[1];
216         /*  analog output subdevice */
217         s->type = COMEDI_SUBD_AO;
218         s->subdev_flags = SDF_WRITABLE;
219         s->n_chan = 2;
220         s->maxdata = 0xfff;
221         /* ranges are hardware settable, but not software readable. */
222         s->range_table = &range_unknown;
223         s->insn_write = cb_pcimdas_ao_insn_write;
224         s->insn_read = comedi_readback_insn_read;
225 
226         ret = comedi_alloc_subdev_readback(s);
227         if (ret)
228                 return ret;
229 
230         s = &dev->subdevices[2];
231         /* digital i/o subdevice */
232         ret = subdev_8255_init(dev, s, NULL, 0x00);
233         if (ret)
234                 return ret;
235 
236         return 0;
237 }
238 
239 static struct comedi_driver cb_pcimdas_driver = {
240         .driver_name    = "cb_pcimdas",
241         .module         = THIS_MODULE,
242         .auto_attach    = cb_pcimdas_auto_attach,
243         .detach         = comedi_pci_detach,
244 };
245 
246 static int cb_pcimdas_pci_probe(struct pci_dev *dev,
247                                 const struct pci_device_id *id)
248 {
249         return comedi_pci_auto_config(dev, &cb_pcimdas_driver,
250                                       id->driver_data);
251 }
252 
253 static const struct pci_device_id cb_pcimdas_pci_table[] = {
254         { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0056) },
255         { 0 }
256 };
257 MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
258 
259 static struct pci_driver cb_pcimdas_pci_driver = {
260         .name           = "cb_pcimdas",
261         .id_table       = cb_pcimdas_pci_table,
262         .probe          = cb_pcimdas_pci_probe,
263         .remove         = comedi_pci_auto_unconfig,
264 };
265 module_comedi_pci_driver(cb_pcimdas_driver, cb_pcimdas_pci_driver);
266 
267 MODULE_AUTHOR("Comedi http://www.comedi.org");
268 MODULE_DESCRIPTION("Comedi low-level driver");
269 MODULE_LICENSE("GPL");
270 

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