Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ni_670x.c
Go to the documentation of this file.
1 /*
2  comedi/drivers/ni_670x.c
3  Hardware driver for NI 670x devices
4 
5  COMEDI - Linux Control and Measurement Device Interface
6  Copyright (C) 1997-2001 David A. Schleef <[email protected]>
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  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22 */
23 /*
24 Driver: ni_670x
25 Description: National Instruments 670x
26 Author: Bart Joris <[email protected]>
27 Updated: Wed, 11 Dec 2002 18:25:35 -0800
28 Devices: [National Instruments] PCI-6703 (ni_670x), PCI-6704
29 Status: unknown
30 
31 Commands are not supported.
32 */
33 
34 /*
35  Bart Joris <[email protected]> Last updated on 20/08/2001
36 
37  Manuals:
38 
39  322110a.pdf PCI/PXI-6704 User Manual
40  322110b.pdf PCI/PXI-6703/6704 User Manual
41 
42 */
43 
44 #include <linux/interrupt.h>
45 #include <linux/slab.h>
46 #include "../comedidev.h"
47 
48 #include "mite.h"
49 
50 #define AO_VALUE_OFFSET 0x00
51 #define AO_CHAN_OFFSET 0x0c
52 #define AO_STATUS_OFFSET 0x10
53 #define AO_CONTROL_OFFSET 0x10
54 #define DIO_PORT0_DIR_OFFSET 0x20
55 #define DIO_PORT0_DATA_OFFSET 0x24
56 #define DIO_PORT1_DIR_OFFSET 0x28
57 #define DIO_PORT1_DATA_OFFSET 0x2c
58 #define MISC_STATUS_OFFSET 0x14
59 #define MISC_CONTROL_OFFSET 0x14
60 
61 /* Board description*/
62 
63 struct ni_670x_board {
64  const char *name;
65  unsigned short dev_id;
66  unsigned short ao_chans;
67 };
68 
69 static const struct ni_670x_board ni_670x_boards[] = {
70  {
71  .name = "PCI-6703",
72  .dev_id = 0x2c90,
73  .ao_chans = 16,
74  }, {
75  .name = "PXI-6704",
76  .dev_id = 0x1920,
77  .ao_chans = 32,
78  }, {
79  .name = "PCI-6704",
80  .dev_id = 0x1290,
81  .ao_chans = 32,
82  },
83 };
84 
86 
87  struct mite_struct *mite;
88  int boardtype;
89  int dio;
90  unsigned int ao_readback[32];
91 };
92 
93 static struct comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} };
94 
95 static int ni_670x_ao_winsn(struct comedi_device *dev,
96  struct comedi_subdevice *s,
97  struct comedi_insn *insn, unsigned int *data)
98 {
99  struct ni_670x_private *devpriv = dev->private;
100  int i;
101  int chan = CR_CHAN(insn->chanspec);
102 
103  /* Channel number mapping :
104 
105  NI 6703/ NI 6704 | NI 6704 Only
106  ----------------------------------------------------
107  vch(0) : 0 | ich(16) : 1
108  vch(1) : 2 | ich(17) : 3
109  . : . | . .
110  . : . | . .
111  . : . | . .
112  vch(15) : 30 | ich(31) : 31 */
113 
114  for (i = 0; i < insn->n; i++) {
115  /* First write in channel register which channel to use */
116  writel(((chan & 15) << 1) | ((chan & 16) >> 4),
117  devpriv->mite->daq_io_addr + AO_CHAN_OFFSET);
118  /* write channel value */
119  writel(data[i], devpriv->mite->daq_io_addr + AO_VALUE_OFFSET);
120  devpriv->ao_readback[chan] = data[i];
121  }
122 
123  return i;
124 }
125 
126 static int ni_670x_ao_rinsn(struct comedi_device *dev,
127  struct comedi_subdevice *s,
128  struct comedi_insn *insn, unsigned int *data)
129 {
130  struct ni_670x_private *devpriv = dev->private;
131  int i;
132  int chan = CR_CHAN(insn->chanspec);
133 
134  for (i = 0; i < insn->n; i++)
135  data[i] = devpriv->ao_readback[chan];
136 
137  return i;
138 }
139 
140 static int ni_670x_dio_insn_bits(struct comedi_device *dev,
141  struct comedi_subdevice *s,
142  struct comedi_insn *insn, unsigned int *data)
143 {
144  struct ni_670x_private *devpriv = dev->private;
145  void __iomem *io_addr = devpriv->mite->daq_io_addr +
147  unsigned int mask = data[0];
148  unsigned int bits = data[1];
149 
150  if (mask) {
151  s->state &= ~mask;
152  s->state |= (bits & mask);
153 
154  writel(s->state, io_addr);
155  }
156 
157  data[1] = readl(io_addr);
158 
159  return insn->n;
160 }
161 
162 static int ni_670x_dio_insn_config(struct comedi_device *dev,
163  struct comedi_subdevice *s,
164  struct comedi_insn *insn, unsigned int *data)
165 {
166  struct ni_670x_private *devpriv = dev->private;
167  int chan = CR_CHAN(insn->chanspec);
168 
169  switch (data[0]) {
171  s->io_bits |= 1 << chan;
172  break;
174  s->io_bits &= ~(1 << chan);
175  break;
177  data[1] =
178  (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
179  return insn->n;
180  break;
181  default:
182  return -EINVAL;
183  break;
184  }
185  writel(s->io_bits, devpriv->mite->daq_io_addr + DIO_PORT0_DIR_OFFSET);
186 
187  return insn->n;
188 }
189 
190 static const struct ni_670x_board *
191 ni_670x_find_boardinfo(struct pci_dev *pcidev)
192 {
193  unsigned int dev_id = pcidev->device;
194  unsigned int n;
195 
196  for (n = 0; n < ARRAY_SIZE(ni_670x_boards); n++) {
197  const struct ni_670x_board *board = &ni_670x_boards[n];
198  if (board->dev_id == dev_id)
199  return board;
200  }
201  return NULL;
202 }
203 
204 static int __devinit ni_670x_attach_pci(struct comedi_device *dev,
205  struct pci_dev *pcidev)
206 {
207  const struct ni_670x_board *thisboard;
208  struct ni_670x_private *devpriv;
209  struct comedi_subdevice *s;
210  int ret;
211  int i;
212 
213  ret = alloc_private(dev, sizeof(*devpriv));
214  if (ret < 0)
215  return ret;
216  devpriv = dev->private;
217  dev->board_ptr = ni_670x_find_boardinfo(pcidev);
218  if (!dev->board_ptr)
219  return -ENODEV;
220  devpriv->mite = mite_alloc(pcidev);
221  if (!devpriv->mite)
222  return -ENOMEM;
223  thisboard = comedi_board(dev);
224 
225  ret = mite_setup(devpriv->mite);
226  if (ret < 0) {
227  dev_warn(dev->class_dev, "error setting up mite\n");
228  return ret;
229  }
230  dev->board_name = thisboard->name;
231 
232  ret = comedi_alloc_subdevices(dev, 2);
233  if (ret)
234  return ret;
235 
236  s = &dev->subdevices[0];
237  /* analog output subdevice */
238  s->type = COMEDI_SUBD_AO;
240  s->n_chan = thisboard->ao_chans;
241  s->maxdata = 0xffff;
242  if (s->n_chan == 32) {
243  const struct comedi_lrange **range_table_list;
244 
245  range_table_list = kmalloc(sizeof(struct comedi_lrange *) * 32,
246  GFP_KERNEL);
247  if (!range_table_list)
248  return -ENOMEM;
249  s->range_table_list = range_table_list;
250  for (i = 0; i < 16; i++) {
251  range_table_list[i] = &range_bipolar10;
252  range_table_list[16 + i] = &range_0_20mA;
253  }
254  } else {
256  }
257  s->insn_write = &ni_670x_ao_winsn;
258  s->insn_read = &ni_670x_ao_rinsn;
259 
260  s = &dev->subdevices[1];
261  /* digital i/o subdevice */
262  s->type = COMEDI_SUBD_DIO;
264  s->n_chan = 8;
265  s->maxdata = 1;
267  s->insn_bits = ni_670x_dio_insn_bits;
268  s->insn_config = ni_670x_dio_insn_config;
269 
270  /* Config of misc registers */
271  writel(0x10, devpriv->mite->daq_io_addr + MISC_CONTROL_OFFSET);
272  /* Config of ao registers */
273  writel(0x00, devpriv->mite->daq_io_addr + AO_CONTROL_OFFSET);
274 
275  dev_info(dev->class_dev, "%s: %s attached\n",
276  dev->driver->driver_name, dev->board_name);
277 
278  return 0;
279 }
280 
281 static void ni_670x_detach(struct comedi_device *dev)
282 {
283  struct ni_670x_private *devpriv = dev->private;
284  struct comedi_subdevice *s;
285 
286  if (dev->n_subdevices) {
287  s = &dev->subdevices[0];
288  if (s)
290  }
291  if (devpriv && devpriv->mite) {
292  mite_unsetup(devpriv->mite);
293  mite_free(devpriv->mite);
294  }
295 }
296 
297 static struct comedi_driver ni_670x_driver = {
298  .driver_name = "ni_670x",
299  .module = THIS_MODULE,
300  .attach_pci = ni_670x_attach_pci,
301  .detach = ni_670x_detach,
302 };
303 
304 static int __devinit ni_670x_pci_probe(struct pci_dev *dev,
305  const struct pci_device_id *ent)
306 {
307  return comedi_pci_auto_config(dev, &ni_670x_driver);
308 }
309 
310 static void __devexit ni_670x_pci_remove(struct pci_dev *dev)
311 {
313 }
314 
315 static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table) = {
316  { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c90) },
317  { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1920) },
318  { 0 }
319 };
320 MODULE_DEVICE_TABLE(pci, ni_670x_pci_table);
321 
322 static struct pci_driver ni_670x_pci_driver = {
323  .name ="ni_670x",
324  .id_table = ni_670x_pci_table,
325  .probe = ni_670x_pci_probe,
326  .remove = __devexit_p(ni_670x_pci_remove),
327 };
328 module_comedi_pci_driver(ni_670x_driver, ni_670x_pci_driver);
329 
330 MODULE_AUTHOR("Comedi http://www.comedi.org");
331 MODULE_DESCRIPTION("Comedi low-level driver");
332 MODULE_LICENSE("GPL");