Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ni_6527.c
Go to the documentation of this file.
1 /*
2  comedi/drivers/ni_6527.c
3  driver for National Instruments PCI-6527
4 
5  COMEDI - Linux Control and Measurement Device Interface
6  Copyright (C) 1999,2002,2003 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_6527
25 Description: National Instruments 6527
26 Author: ds
27 Status: works
28 Devices: [National Instruments] PCI-6527 (ni6527), PXI-6527
29 Updated: Sat, 25 Jan 2003 13:24:40 -0800
30 
31 
32 */
33 
34 /*
35  Manuals (available from ftp://ftp.natinst.com/support/manuals)
36 
37  370106b.pdf 6527 Register Level Programmer Manual
38 
39  */
40 
41 #define DEBUG 1
42 #define DEBUG_FLAGS
43 
44 #include <linux/interrupt.h>
45 #include "../comedidev.h"
46 
47 #include "comedi_fc.h"
48 #include "mite.h"
49 
50 #define DRIVER_NAME "ni_6527"
51 
52 #define NI6527_DIO_SIZE 4096
53 #define NI6527_MITE_SIZE 4096
54 
55 #define Port_Register(x) (0x00+(x))
56 #define ID_Register 0x06
57 
58 #define Clear_Register 0x07
59 #define ClrEdge 0x08
60 #define ClrOverflow 0x04
61 #define ClrFilter 0x02
62 #define ClrInterval 0x01
63 
64 #define Filter_Interval(x) (0x08+(x))
65 #define Filter_Enable(x) (0x0c+(x))
66 
67 #define Change_Status 0x14
68 #define MasterInterruptStatus 0x04
69 #define Overflow 0x02
70 #define EdgeStatus 0x01
71 
72 #define Master_Interrupt_Control 0x15
73 #define FallingEdgeIntEnable 0x10
74 #define RisingEdgeIntEnable 0x08
75 #define MasterInterruptEnable 0x04
76 #define OverflowIntEnable 0x02
77 #define EdgeIntEnable 0x01
78 
79 #define Rising_Edge_Detection_Enable(x) (0x018+(x))
80 #define Falling_Edge_Detection_Enable(x) (0x020+(x))
81 
82 struct ni6527_board {
83 
84  int dev_id;
85  const char *name;
86 };
87 
88 static const struct ni6527_board ni6527_boards[] = {
89  {
90  .dev_id = 0x2b20,
91  .name = "pci-6527",
92  },
93  {
94  .dev_id = 0x2b10,
95  .name = "pxi-6527",
96  },
97 };
98 
99 #define this_board ((const struct ni6527_board *)dev->board_ptr)
100 
101 static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = {
102  {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b10)},
103  {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b20)},
104  {0}
105 };
106 
107 MODULE_DEVICE_TABLE(pci, ni6527_pci_table);
108 
110  struct mite_struct *mite;
111  unsigned int filter_interval;
112  unsigned int filter_enable;
113 };
114 
115 #define devpriv ((struct ni6527_private *)dev->private)
116 
117 static int ni6527_di_insn_config(struct comedi_device *dev,
118  struct comedi_subdevice *s,
119  struct comedi_insn *insn, unsigned int *data)
120 {
121  int chan = CR_CHAN(insn->chanspec);
122  unsigned int interval;
123 
124  if (insn->n != 2)
125  return -EINVAL;
126 
127  if (data[0] != INSN_CONFIG_FILTER)
128  return -EINVAL;
129 
130  if (data[1]) {
131  interval = (data[1] + 100) / 200;
132  data[1] = interval * 200;
133 
134  if (interval != devpriv->filter_interval) {
135  writeb(interval & 0xff,
136  devpriv->mite->daq_io_addr + Filter_Interval(0));
137  writeb((interval >> 8) & 0xff,
138  devpriv->mite->daq_io_addr + Filter_Interval(1));
139  writeb((interval >> 16) & 0x0f,
140  devpriv->mite->daq_io_addr + Filter_Interval(2));
141 
143  devpriv->mite->daq_io_addr + Clear_Register);
144 
145  devpriv->filter_interval = interval;
146  }
147 
148  devpriv->filter_enable |= 1 << chan;
149  } else {
150  devpriv->filter_enable &= ~(1 << chan);
151  }
152 
153  writeb(devpriv->filter_enable,
154  devpriv->mite->daq_io_addr + Filter_Enable(0));
155  writeb(devpriv->filter_enable >> 8,
156  devpriv->mite->daq_io_addr + Filter_Enable(1));
157  writeb(devpriv->filter_enable >> 16,
158  devpriv->mite->daq_io_addr + Filter_Enable(2));
159 
160  return 2;
161 }
162 
163 static int ni6527_di_insn_bits(struct comedi_device *dev,
164  struct comedi_subdevice *s,
165  struct comedi_insn *insn, unsigned int *data)
166 {
167  data[1] = readb(devpriv->mite->daq_io_addr + Port_Register(0));
168  data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(1)) << 8;
169  data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(2)) << 16;
170 
171  return insn->n;
172 }
173 
174 static int ni6527_do_insn_bits(struct comedi_device *dev,
175  struct comedi_subdevice *s,
176  struct comedi_insn *insn, unsigned int *data)
177 {
178  if (data[0]) {
179  s->state &= ~data[0];
180  s->state |= (data[0] & data[1]);
181 
182  /* The open relay state on the board cooresponds to 1,
183  * but in Comedi, it is represented by 0. */
184  if (data[0] & 0x0000ff) {
185  writeb((s->state ^ 0xff),
186  devpriv->mite->daq_io_addr + Port_Register(3));
187  }
188  if (data[0] & 0x00ff00) {
189  writeb((s->state >> 8) ^ 0xff,
190  devpriv->mite->daq_io_addr + Port_Register(4));
191  }
192  if (data[0] & 0xff0000) {
193  writeb((s->state >> 16) ^ 0xff,
194  devpriv->mite->daq_io_addr + Port_Register(5));
195  }
196  }
197  data[1] = s->state;
198 
199  return insn->n;
200 }
201 
202 static irqreturn_t ni6527_interrupt(int irq, void *d)
203 {
204  struct comedi_device *dev = d;
205  struct comedi_subdevice *s = &dev->subdevices[2];
206  unsigned int status;
207 
208  status = readb(devpriv->mite->daq_io_addr + Change_Status);
209  if ((status & MasterInterruptStatus) == 0)
210  return IRQ_NONE;
211  if ((status & EdgeStatus) == 0)
212  return IRQ_NONE;
213 
215  devpriv->mite->daq_io_addr + Clear_Register);
216 
217  comedi_buf_put(s->async, 0);
218  s->async->events |= COMEDI_CB_EOS;
219  comedi_event(dev, s);
220  return IRQ_HANDLED;
221 }
222 
223 static int ni6527_intr_cmdtest(struct comedi_device *dev,
224  struct comedi_subdevice *s,
225  struct comedi_cmd *cmd)
226 {
227  int err = 0;
228 
229  /* Step 1 : check if triggers are trivially valid */
230 
231  err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
232  err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_OTHER);
233  err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
234  err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
235  err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
236 
237  if (err)
238  return 1;
239 
240  /* Step 2a : make sure trigger sources are unique */
241  /* Step 2b : and mutually compatible */
242 
243  if (err)
244  return 2;
245 
246  /* step 3: make sure arguments are trivially compatible */
247 
248  if (cmd->start_arg != 0) {
249  cmd->start_arg = 0;
250  err++;
251  }
252  if (cmd->scan_begin_arg != 0) {
253  cmd->scan_begin_arg = 0;
254  err++;
255  }
256  if (cmd->convert_arg != 0) {
257  cmd->convert_arg = 0;
258  err++;
259  }
260 
261  if (cmd->scan_end_arg != 1) {
262  cmd->scan_end_arg = 1;
263  err++;
264  }
265  if (cmd->stop_arg != 0) {
266  cmd->stop_arg = 0;
267  err++;
268  }
269 
270  if (err)
271  return 3;
272 
273  /* step 4: fix up any arguments */
274 
275  if (err)
276  return 4;
277 
278  return 0;
279 }
280 
281 static int ni6527_intr_cmd(struct comedi_device *dev,
282  struct comedi_subdevice *s)
283 {
284  /* struct comedi_cmd *cmd = &s->async->cmd; */
285 
287  devpriv->mite->daq_io_addr + Clear_Register);
290  devpriv->mite->daq_io_addr + Master_Interrupt_Control);
291 
292  return 0;
293 }
294 
295 static int ni6527_intr_cancel(struct comedi_device *dev,
296  struct comedi_subdevice *s)
297 {
298  writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control);
299 
300  return 0;
301 }
302 
303 static int ni6527_intr_insn_bits(struct comedi_device *dev,
304  struct comedi_subdevice *s,
305  struct comedi_insn *insn, unsigned int *data)
306 {
307  data[1] = 0;
308  return insn->n;
309 }
310 
311 static int ni6527_intr_insn_config(struct comedi_device *dev,
312  struct comedi_subdevice *s,
313  struct comedi_insn *insn, unsigned int *data)
314 {
315  if (insn->n < 1)
316  return -EINVAL;
317  if (data[0] != INSN_CONFIG_CHANGE_NOTIFY)
318  return -EINVAL;
319 
320  writeb(data[1],
321  devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0));
322  writeb(data[1] >> 8,
323  devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(1));
324  writeb(data[1] >> 16,
325  devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(2));
326 
327  writeb(data[2],
328  devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0));
329  writeb(data[2] >> 8,
330  devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(1));
331  writeb(data[2] >> 16,
332  devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(2));
333 
334  return 2;
335 }
336 
337 static const struct ni6527_board *
338 ni6527_find_boardinfo(struct pci_dev *pcidev)
339 {
340  unsigned int dev_id = pcidev->device;
341  unsigned int n;
342 
343  for (n = 0; n < ARRAY_SIZE(ni6527_boards); n++) {
344  const struct ni6527_board *board = &ni6527_boards[n];
345  if (board->dev_id == dev_id)
346  return board;
347  }
348  return NULL;
349 }
350 
351 static int __devinit ni6527_attach_pci(struct comedi_device *dev,
352  struct pci_dev *pcidev)
353 {
354  struct comedi_subdevice *s;
355  int ret;
356 
357  ret = alloc_private(dev, sizeof(struct ni6527_private));
358  if (ret < 0)
359  return ret;
360 
361  dev->board_ptr = ni6527_find_boardinfo(pcidev);
362  if (!dev->board_ptr)
363  return -ENODEV;
364 
365  devpriv->mite = mite_alloc(pcidev);
366  if (!devpriv->mite)
367  return -ENOMEM;
368 
369  ret = mite_setup(devpriv->mite);
370  if (ret < 0) {
371  dev_err(dev->class_dev, "error setting up mite\n");
372  return ret;
373  }
374 
375  dev->board_name = this_board->name;
376  dev_info(dev->class_dev, "board: %s, ID=0x%02x\n", dev->board_name,
377  readb(devpriv->mite->daq_io_addr + ID_Register));
378 
379  ret = comedi_alloc_subdevices(dev, 3);
380  if (ret)
381  return ret;
382 
383  s = &dev->subdevices[0];
384  s->type = COMEDI_SUBD_DI;
386  s->n_chan = 24;
388  s->maxdata = 1;
389  s->insn_config = ni6527_di_insn_config;
390  s->insn_bits = ni6527_di_insn_bits;
391 
392  s = &dev->subdevices[1];
393  s->type = COMEDI_SUBD_DO;
395  s->n_chan = 24;
396  s->range_table = &range_unknown; /* FIXME: actually conductance */
397  s->maxdata = 1;
398  s->insn_bits = ni6527_do_insn_bits;
399 
400  s = &dev->subdevices[2];
401  dev->read_subdev = s;
402  s->type = COMEDI_SUBD_DI;
404  s->n_chan = 1;
406  s->maxdata = 1;
407  s->do_cmdtest = ni6527_intr_cmdtest;
408  s->do_cmd = ni6527_intr_cmd;
409  s->cancel = ni6527_intr_cancel;
410  s->insn_bits = ni6527_intr_insn_bits;
411  s->insn_config = ni6527_intr_insn_config;
412 
413  writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(0));
414  writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(1));
415  writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(2));
416 
418  devpriv->mite->daq_io_addr + Clear_Register);
419  writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control);
420 
421  ret = request_irq(mite_irq(devpriv->mite), ni6527_interrupt,
422  IRQF_SHARED, DRIVER_NAME, dev);
423  if (ret < 0)
424  dev_warn(dev->class_dev, "irq not available\n");
425  else
426  dev->irq = mite_irq(devpriv->mite);
427 
428  return 0;
429 }
430 
431 static void ni6527_detach(struct comedi_device *dev)
432 {
433  if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr)
434  writeb(0x00,
435  devpriv->mite->daq_io_addr + Master_Interrupt_Control);
436  if (dev->irq)
437  free_irq(dev->irq, dev);
438  if (devpriv && devpriv->mite) {
439  mite_unsetup(devpriv->mite);
440  mite_free(devpriv->mite);
441  }
442 }
443 
444 static struct comedi_driver ni6527_driver = {
445  .driver_name = DRIVER_NAME,
446  .module = THIS_MODULE,
447  .attach_pci = ni6527_attach_pci,
448  .detach = ni6527_detach,
449 };
450 
451 static int __devinit ni6527_pci_probe(struct pci_dev *dev,
452  const struct pci_device_id *ent)
453 {
454  return comedi_pci_auto_config(dev, &ni6527_driver);
455 }
456 
457 static void __devexit ni6527_pci_remove(struct pci_dev *dev)
458 {
460 }
461 
462 static struct pci_driver ni6527_pci_driver = {
463  .name = DRIVER_NAME,
464  .id_table = ni6527_pci_table,
465  .probe = ni6527_pci_probe,
466  .remove = __devexit_p(ni6527_pci_remove)
467 };
468 module_comedi_pci_driver(ni6527_driver, ni6527_pci_driver);
469 
470 MODULE_AUTHOR("Comedi http://www.comedi.org");
471 MODULE_DESCRIPTION("Comedi low-level driver");
472 MODULE_LICENSE("GPL");