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_das16_cs.c

  1 /*
  2     comedi/drivers/das16cs.c
  3     Driver for Computer Boards PC-CARD DAS16/16.
  4 
  5     COMEDI - Linux Control and Measurement Device Interface
  6     Copyright (C) 2000, 2001, 2002 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     PCMCIA support code for this driver is adapted from the dummy_cs.c
 19     driver of the Linux PCMCIA Card Services package.
 20 
 21     The initial developer of the original code is David A. Hinds
 22     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
 23     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 24 
 25 */
 26 /*
 27 Driver: cb_das16_cs
 28 Description: Computer Boards PC-CARD DAS16/16
 29 Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO
 30 Author: ds
 31 Updated: Mon, 04 Nov 2002 20:04:21 -0800
 32 Status: experimental
 33 
 34 
 35 */
 36 
 37 #include <linux/module.h>
 38 #include <linux/interrupt.h>
 39 #include <linux/delay.h>
 40 
 41 #include "../comedi_pcmcia.h"
 42 
 43 #include "comedi_fc.h"
 44 #include "8253.h"
 45 
 46 #define DAS16CS_ADC_DATA                0
 47 #define DAS16CS_DIO_MUX                 2
 48 #define DAS16CS_MISC1                   4
 49 #define DAS16CS_MISC2                   6
 50 #define DAS16CS_CTR0                    8
 51 #define DAS16CS_CTR1                    10
 52 #define DAS16CS_CTR2                    12
 53 #define DAS16CS_CTR_CONTROL             14
 54 #define DAS16CS_DIO                     16
 55 
 56 struct das16cs_board {
 57         const char *name;
 58         int device_id;
 59         int n_ao_chans;
 60 };
 61 
 62 static const struct das16cs_board das16cs_boards[] = {
 63         {
 64                 .name           = "PC-CARD DAS16/16-AO",
 65                 .device_id      = 0x0039,
 66                 .n_ao_chans     = 2,
 67         }, {
 68                 .name           = "PCM-DAS16s/16",
 69                 .device_id      = 0x4009,
 70                 .n_ao_chans     = 0,
 71         }, {
 72                 .name           = "PC-CARD DAS16/16",
 73                 .device_id      = 0x0000,       /* unknown */
 74                 .n_ao_chans     = 0,
 75         },
 76 };
 77 
 78 struct das16cs_private {
 79         unsigned short status1;
 80         unsigned short status2;
 81 };
 82 
 83 static const struct comedi_lrange das16cs_ai_range = {
 84         4, {
 85                 BIP_RANGE(10),
 86                 BIP_RANGE(5),
 87                 BIP_RANGE(2.5),
 88                 BIP_RANGE(1.25),
 89         }
 90 };
 91 
 92 static int das16cs_ai_eoc(struct comedi_device *dev,
 93                           struct comedi_subdevice *s,
 94                           struct comedi_insn *insn,
 95                           unsigned long context)
 96 {
 97         unsigned int status;
 98 
 99         status = inw(dev->iobase + DAS16CS_MISC1);
100         if (status & 0x0080)
101                 return 0;
102         return -EBUSY;
103 }
104 
105 static int das16cs_ai_rinsn(struct comedi_device *dev,
106                             struct comedi_subdevice *s,
107                             struct comedi_insn *insn, unsigned int *data)
108 {
109         struct das16cs_private *devpriv = dev->private;
110         int chan = CR_CHAN(insn->chanspec);
111         int range = CR_RANGE(insn->chanspec);
112         int aref = CR_AREF(insn->chanspec);
113         int ret;
114         int i;
115 
116         outw(chan, dev->iobase + DAS16CS_DIO_MUX);
117 
118         devpriv->status1 &= ~0xf320;
119         devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020;
120         outw(devpriv->status1, dev->iobase + DAS16CS_MISC1);
121 
122         devpriv->status2 &= ~0xff00;
123         switch (range) {
124         case 0:
125                 devpriv->status2 |= 0x800;
126                 break;
127         case 1:
128                 devpriv->status2 |= 0x000;
129                 break;
130         case 2:
131                 devpriv->status2 |= 0x100;
132                 break;
133         case 3:
134                 devpriv->status2 |= 0x200;
135                 break;
136         }
137         outw(devpriv->status2, dev->iobase + DAS16CS_MISC2);
138 
139         for (i = 0; i < insn->n; i++) {
140                 outw(0, dev->iobase + DAS16CS_ADC_DATA);
141 
142                 ret = comedi_timeout(dev, s, insn, das16cs_ai_eoc, 0);
143                 if (ret)
144                         return ret;
145 
146                 data[i] = inw(dev->iobase + DAS16CS_ADC_DATA);
147         }
148 
149         return i;
150 }
151 
152 static int das16cs_ao_insn_write(struct comedi_device *dev,
153                                  struct comedi_subdevice *s,
154                                  struct comedi_insn *insn,
155                                  unsigned int *data)
156 {
157         struct das16cs_private *devpriv = dev->private;
158         unsigned int chan = CR_CHAN(insn->chanspec);
159         unsigned int val = s->readback[chan];
160         unsigned short status1;
161         int bit;
162         int i;
163 
164         for (i = 0; i < insn->n; i++) {
165                 val = data[i];
166 
167                 outw(devpriv->status1, dev->iobase + DAS16CS_MISC1);
168                 udelay(1);
169 
170                 status1 = devpriv->status1 & ~0xf;
171                 if (chan)
172                         status1 |= 0x0001;
173                 else
174                         status1 |= 0x0008;
175 
176                 outw(status1, dev->iobase + DAS16CS_MISC1);
177                 udelay(1);
178 
179                 for (bit = 15; bit >= 0; bit--) {
180                         int b = (val >> bit) & 0x1;
181 
182                         b <<= 1;
183                         outw(status1 | b | 0x0000, dev->iobase + DAS16CS_MISC1);
184                         udelay(1);
185                         outw(status1 | b | 0x0004, dev->iobase + DAS16CS_MISC1);
186                         udelay(1);
187                 }
188                 /*
189                  * Make both DAC0CS and DAC1CS high to load
190                  * the new data and update analog the output
191                  */
192                 outw(status1 | 0x9, dev->iobase + DAS16CS_MISC1);
193         }
194         s->readback[chan] = val;
195 
196         return insn->n;
197 }
198 
199 static int das16cs_dio_insn_bits(struct comedi_device *dev,
200                                  struct comedi_subdevice *s,
201                                  struct comedi_insn *insn,
202                                  unsigned int *data)
203 {
204         if (comedi_dio_update_state(s, data))
205                 outw(s->state, dev->iobase + DAS16CS_DIO);
206 
207         data[1] = inw(dev->iobase + DAS16CS_DIO);
208 
209         return insn->n;
210 }
211 
212 static int das16cs_dio_insn_config(struct comedi_device *dev,
213                                    struct comedi_subdevice *s,
214                                    struct comedi_insn *insn,
215                                    unsigned int *data)
216 {
217         struct das16cs_private *devpriv = dev->private;
218         unsigned int chan = CR_CHAN(insn->chanspec);
219         unsigned int mask;
220         int ret;
221 
222         if (chan < 4)
223                 mask = 0x0f;
224         else
225                 mask = 0xf0;
226 
227         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
228         if (ret)
229                 return ret;
230 
231         devpriv->status2 &= ~0x00c0;
232         devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0;
233         devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0;
234 
235         outw(devpriv->status2, dev->iobase + DAS16CS_MISC2);
236 
237         return insn->n;
238 }
239 
240 static const void *das16cs_find_boardinfo(struct comedi_device *dev,
241                                           struct pcmcia_device *link)
242 {
243         const struct das16cs_board *board;
244         int i;
245 
246         for (i = 0; i < ARRAY_SIZE(das16cs_boards); i++) {
247                 board = &das16cs_boards[i];
248                 if (board->device_id == link->card_id)
249                         return board;
250         }
251 
252         return NULL;
253 }
254 
255 static int das16cs_auto_attach(struct comedi_device *dev,
256                                unsigned long context)
257 {
258         struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
259         const struct das16cs_board *board;
260         struct das16cs_private *devpriv;
261         struct comedi_subdevice *s;
262         int ret;
263 
264         board = das16cs_find_boardinfo(dev, link);
265         if (!board)
266                 return -ENODEV;
267         dev->board_ptr = board;
268         dev->board_name = board->name;
269 
270         link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
271         ret = comedi_pcmcia_enable(dev, NULL);
272         if (ret)
273                 return ret;
274         dev->iobase = link->resource[0]->start;
275 
276         link->priv = dev;
277 
278         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
279         if (!devpriv)
280                 return -ENOMEM;
281 
282         ret = comedi_alloc_subdevices(dev, 3);
283         if (ret)
284                 return ret;
285 
286         s = &dev->subdevices[0];
287         /* analog input subdevice */
288         s->type         = COMEDI_SUBD_AI;
289         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
290         s->n_chan       = 16;
291         s->maxdata      = 0xffff;
292         s->range_table  = &das16cs_ai_range;
293         s->len_chanlist = 16;
294         s->insn_read    = das16cs_ai_rinsn;
295 
296         s = &dev->subdevices[1];
297         /* analog output subdevice */
298         if (board->n_ao_chans) {
299                 s->type         = COMEDI_SUBD_AO;
300                 s->subdev_flags = SDF_WRITABLE;
301                 s->n_chan       = board->n_ao_chans;
302                 s->maxdata      = 0xffff;
303                 s->range_table  = &range_bipolar10;
304                 s->insn_write   = &das16cs_ao_insn_write;
305 
306                 ret = comedi_alloc_subdev_readback(s);
307                 if (ret)
308                         return ret;
309         } else {
310                 s->type         = COMEDI_SUBD_UNUSED;
311         }
312 
313         s = &dev->subdevices[2];
314         /* digital i/o subdevice */
315         s->type         = COMEDI_SUBD_DIO;
316         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
317         s->n_chan       = 8;
318         s->maxdata      = 1;
319         s->range_table  = &range_digital;
320         s->insn_bits    = das16cs_dio_insn_bits;
321         s->insn_config  = das16cs_dio_insn_config;
322 
323         return 0;
324 }
325 
326 static struct comedi_driver driver_das16cs = {
327         .driver_name    = "cb_das16_cs",
328         .module         = THIS_MODULE,
329         .auto_attach    = das16cs_auto_attach,
330         .detach         = comedi_pcmcia_disable,
331 };
332 
333 static int das16cs_pcmcia_attach(struct pcmcia_device *link)
334 {
335         return comedi_pcmcia_auto_config(link, &driver_das16cs);
336 }
337 
338 static const struct pcmcia_device_id das16cs_id_table[] = {
339         PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
340         PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
341         PCMCIA_DEVICE_NULL
342 };
343 MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table);
344 
345 static struct pcmcia_driver das16cs_driver = {
346         .name           = "cb_das16_cs",
347         .owner          = THIS_MODULE,
348         .id_table       = das16cs_id_table,
349         .probe          = das16cs_pcmcia_attach,
350         .remove         = comedi_pcmcia_auto_unconfig,
351 };
352 module_comedi_pcmcia_driver(driver_das16cs, das16cs_driver);
353 
354 MODULE_AUTHOR("David A. Schleef <ds@schleef.org>");
355 MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16");
356 MODULE_LICENSE("GPL");
357 

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