Version:  2.0.40 2.2.26 2.4.37 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9

Linux/drivers/staging/comedi/drivers/ni_670x.c

  1 /*
  2  * Comedi driver for NI 670x devices
  3  *
  4  * COMEDI - Linux Control and Measurement Device Interface
  5  * Copyright (C) 1997-2001 David A. Schleef <ds@schleef.org>
  6  *
  7  * This program is free software; you can redistribute it and/or modify
  8  * it under the terms of the GNU General Public License as published by
  9  * the Free Software Foundation; either version 2 of the License, or
 10  * (at your option) any later version.
 11  *
 12  * This program is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  * GNU General Public License for more details.
 16  */
 17 
 18 /*
 19  * Driver: ni_670x
 20  * Description: National Instruments 670x
 21  * Author: Bart Joris <bjoris@advalvas.be>
 22  * Updated: Wed, 11 Dec 2002 18:25:35 -0800
 23  * Devices: [National Instruments] PCI-6703 (ni_670x), PCI-6704
 24  * Status: unknown
 25  *
 26  * Commands are not supported.
 27  *
 28  * Manuals:
 29  *   322110a.pdf        PCI/PXI-6704 User Manual
 30  *   322110b.pdf        PCI/PXI-6703/6704 User Manual
 31  */
 32 
 33 #include <linux/module.h>
 34 #include <linux/interrupt.h>
 35 #include <linux/slab.h>
 36 
 37 #include "../comedi_pci.h"
 38 
 39 #define AO_VALUE_OFFSET                 0x00
 40 #define AO_CHAN_OFFSET                  0x0c
 41 #define AO_STATUS_OFFSET                0x10
 42 #define AO_CONTROL_OFFSET               0x10
 43 #define DIO_PORT0_DIR_OFFSET    0x20
 44 #define DIO_PORT0_DATA_OFFSET   0x24
 45 #define DIO_PORT1_DIR_OFFSET    0x28
 46 #define DIO_PORT1_DATA_OFFSET   0x2c
 47 #define MISC_STATUS_OFFSET              0x14
 48 #define MISC_CONTROL_OFFSET             0x14
 49 
 50 enum ni_670x_boardid {
 51         BOARD_PCI6703,
 52         BOARD_PXI6704,
 53         BOARD_PCI6704,
 54 };
 55 
 56 struct ni_670x_board {
 57         const char *name;
 58         unsigned short ao_chans;
 59 };
 60 
 61 static const struct ni_670x_board ni_670x_boards[] = {
 62         [BOARD_PCI6703] = {
 63                 .name           = "PCI-6703",
 64                 .ao_chans       = 16,
 65         },
 66         [BOARD_PXI6704] = {
 67                 .name           = "PXI-6704",
 68                 .ao_chans       = 32,
 69         },
 70         [BOARD_PCI6704] = {
 71                 .name           = "PCI-6704",
 72                 .ao_chans       = 32,
 73         },
 74 };
 75 
 76 struct ni_670x_private {
 77         int boardtype;
 78         int dio;
 79 };
 80 
 81 static int ni_670x_ao_insn_write(struct comedi_device *dev,
 82                                  struct comedi_subdevice *s,
 83                                  struct comedi_insn *insn,
 84                                  unsigned int *data)
 85 {
 86         unsigned int chan = CR_CHAN(insn->chanspec);
 87         unsigned int val = s->readback[chan];
 88         int i;
 89 
 90         /*
 91          * Channel number mapping:
 92          *
 93          * NI 6703/ NI 6704 | NI 6704 Only
 94          * -------------------------------
 95          * vch(0)  :  0     | ich(16) :  1
 96          * vch(1)  :  2     | ich(17) :  3
 97          * ...              | ...
 98          * vch(15) : 30     | ich(31) : 31
 99          */
100         for (i = 0; i < insn->n; i++) {
101                 val = data[i];
102                 /* First write in channel register which channel to use */
103                 writel(((chan & 15) << 1) | ((chan & 16) >> 4),
104                        dev->mmio + AO_CHAN_OFFSET);
105                 /* write channel value */
106                 writel(val, dev->mmio + AO_VALUE_OFFSET);
107         }
108         s->readback[chan] = val;
109 
110         return insn->n;
111 }
112 
113 static int ni_670x_dio_insn_bits(struct comedi_device *dev,
114                                  struct comedi_subdevice *s,
115                                  struct comedi_insn *insn,
116                                  unsigned int *data)
117 {
118         if (comedi_dio_update_state(s, data))
119                 writel(s->state, dev->mmio + DIO_PORT0_DATA_OFFSET);
120 
121         data[1] = readl(dev->mmio + DIO_PORT0_DATA_OFFSET);
122 
123         return insn->n;
124 }
125 
126 static int ni_670x_dio_insn_config(struct comedi_device *dev,
127                                    struct comedi_subdevice *s,
128                                    struct comedi_insn *insn,
129                                    unsigned int *data)
130 {
131         int ret;
132 
133         ret = comedi_dio_insn_config(dev, s, insn, data, 0);
134         if (ret)
135                 return ret;
136 
137         writel(s->io_bits, dev->mmio + DIO_PORT0_DIR_OFFSET);
138 
139         return insn->n;
140 }
141 
142 /* ripped from mite.h and mite_setup2() to avoid mite dependency */
143 #define MITE_IODWBSR    0xc0     /* IO Device Window Base Size Register */
144 #define WENAB           (1 << 7) /* window enable */
145 
146 static int ni_670x_mite_init(struct pci_dev *pcidev)
147 {
148         void __iomem *mite_base;
149         u32 main_phys_addr;
150 
151         /* ioremap the MITE registers (BAR 0) temporarily */
152         mite_base = pci_ioremap_bar(pcidev, 0);
153         if (!mite_base)
154                 return -ENOMEM;
155 
156         /* set data window to main registers (BAR 1) */
157         main_phys_addr = pci_resource_start(pcidev, 1);
158         writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR);
159 
160         /* finished with MITE registers */
161         iounmap(mite_base);
162         return 0;
163 }
164 
165 static int ni_670x_auto_attach(struct comedi_device *dev,
166                                unsigned long context)
167 {
168         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
169         const struct ni_670x_board *board = NULL;
170         struct ni_670x_private *devpriv;
171         struct comedi_subdevice *s;
172         int ret;
173         int i;
174 
175         if (context < ARRAY_SIZE(ni_670x_boards))
176                 board = &ni_670x_boards[context];
177         if (!board)
178                 return -ENODEV;
179         dev->board_ptr = board;
180         dev->board_name = board->name;
181 
182         ret = comedi_pci_enable(dev);
183         if (ret)
184                 return ret;
185 
186         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
187         if (!devpriv)
188                 return -ENOMEM;
189 
190         ret = ni_670x_mite_init(pcidev);
191         if (ret)
192                 return ret;
193 
194         dev->mmio = pci_ioremap_bar(pcidev, 1);
195         if (!dev->mmio)
196                 return -ENOMEM;
197 
198         ret = comedi_alloc_subdevices(dev, 2);
199         if (ret)
200                 return ret;
201 
202         s = &dev->subdevices[0];
203         /* analog output subdevice */
204         s->type = COMEDI_SUBD_AO;
205         s->subdev_flags = SDF_WRITABLE;
206         s->n_chan = board->ao_chans;
207         s->maxdata = 0xffff;
208         if (s->n_chan == 32) {
209                 const struct comedi_lrange **range_table_list;
210 
211                 range_table_list = kmalloc_array(32,
212                                                  sizeof(struct comedi_lrange *),
213                                                  GFP_KERNEL);
214                 if (!range_table_list)
215                         return -ENOMEM;
216                 s->range_table_list = range_table_list;
217                 for (i = 0; i < 16; i++) {
218                         range_table_list[i] = &range_bipolar10;
219                         range_table_list[16 + i] = &range_0_20mA;
220                 }
221         } else {
222                 s->range_table = &range_bipolar10;
223         }
224         s->insn_write = ni_670x_ao_insn_write;
225 
226         ret = comedi_alloc_subdev_readback(s);
227         if (ret)
228                 return ret;
229 
230         s = &dev->subdevices[1];
231         /* digital i/o subdevice */
232         s->type = COMEDI_SUBD_DIO;
233         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
234         s->n_chan = 8;
235         s->maxdata = 1;
236         s->range_table = &range_digital;
237         s->insn_bits = ni_670x_dio_insn_bits;
238         s->insn_config = ni_670x_dio_insn_config;
239 
240         /* Config of misc registers */
241         writel(0x10, dev->mmio + MISC_CONTROL_OFFSET);
242         /* Config of ao registers */
243         writel(0x00, dev->mmio + AO_CONTROL_OFFSET);
244 
245         return 0;
246 }
247 
248 static void ni_670x_detach(struct comedi_device *dev)
249 {
250         struct comedi_subdevice *s;
251 
252         comedi_pci_detach(dev);
253         if (dev->n_subdevices) {
254                 s = &dev->subdevices[0];
255                 if (s)
256                         kfree(s->range_table_list);
257         }
258 }
259 
260 static struct comedi_driver ni_670x_driver = {
261         .driver_name    = "ni_670x",
262         .module         = THIS_MODULE,
263         .auto_attach    = ni_670x_auto_attach,
264         .detach         = ni_670x_detach,
265 };
266 
267 static int ni_670x_pci_probe(struct pci_dev *dev,
268                              const struct pci_device_id *id)
269 {
270         return comedi_pci_auto_config(dev, &ni_670x_driver, id->driver_data);
271 }
272 
273 static const struct pci_device_id ni_670x_pci_table[] = {
274         { PCI_VDEVICE(NI, 0x1290), BOARD_PCI6704 },
275         { PCI_VDEVICE(NI, 0x1920), BOARD_PXI6704 },
276         { PCI_VDEVICE(NI, 0x2c90), BOARD_PCI6703 },
277         { 0 }
278 };
279 MODULE_DEVICE_TABLE(pci, ni_670x_pci_table);
280 
281 static struct pci_driver ni_670x_pci_driver = {
282         .name           = "ni_670x",
283         .id_table       = ni_670x_pci_table,
284         .probe          = ni_670x_pci_probe,
285         .remove         = comedi_pci_auto_unconfig,
286 };
287 module_comedi_pci_driver(ni_670x_driver, ni_670x_pci_driver);
288 
289 MODULE_AUTHOR("Comedi http://www.comedi.org");
290 MODULE_DESCRIPTION("Comedi low-level driver");
291 MODULE_LICENSE("GPL");
292 

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