Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cb_pcimdda.c
Go to the documentation of this file.
1 /*
2  comedi/drivers/cb_pcimdda.c
3  Computer Boards PCIM-DDA06-16 Comedi driver
4  Author: Calin Culianu <[email protected]>
5 
6  COMEDI - Linux Control and Measurement Device Interface
7  Copyright (C) 2000 David A. Schleef <[email protected]>
8 
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23 */
24 /*
25 Driver: cb_pcimdda
26 Description: Measurement Computing PCIM-DDA06-16
27 Devices: [Measurement Computing] PCIM-DDA06-16 (cb_pcimdda)
28 Author: Calin Culianu <[email protected]>
29 Updated: Mon, 14 Apr 2008 15:15:51 +0100
30 Status: works
31 
32 All features of the PCIM-DDA06-16 board are supported. This board
33 has 6 16-bit AO channels, and the usual 8255 DIO setup. (24 channels,
34 configurable in banks of 8 and 4, etc.). This board does not support commands.
35 
36 The board has a peculiar way of specifying AO gain/range settings -- You have
37 1 jumper bank on the card, which either makes all 6 AO channels either
38 5 Volt unipolar, 5V bipolar, 10 Volt unipolar or 10V bipolar.
39 
40 Since there is absolutely _no_ way to tell in software how this jumper is set
41 (well, at least according to the rather thin spec. from Measurement Computing
42  that comes with the board), the driver assumes the jumper is at its factory
43 default setting of +/-5V.
44 
45 Also of note is the fact that this board features another jumper, whose
46 state is also completely invisible to software. It toggles two possible AO
47 output modes on the board:
48 
49  - Update Mode: Writing to an AO channel instantaneously updates the actual
50  signal output by the DAC on the board (this is the factory default).
51  - Simultaneous XFER Mode: Writing to an AO channel has no effect until
52  you read from any one of the AO channels. This is useful for loading
53  all 6 AO values, and then reading from any one of the AO channels on the
54  device to instantly update all 6 AO values in unison. Useful for some
55  control apps, I would assume? If your jumper is in this setting, then you
56  need to issue your comedi_data_write()s to load all the values you want,
57  then issue one comedi_data_read() on any channel on the AO subdevice
58  to initiate the simultaneous XFER.
59 
60 Configuration Options: not applicable, uses PCI auto config
61 */
62 
63 /*
64  This is a driver for the Computer Boards PCIM-DDA06-16 Analog Output
65  card. This board has a unique register layout and as such probably
66  deserves its own driver file.
67 
68  It is theoretically possible to integrate this board into the cb_pcidda
69  file, but since that isn't my code, I didn't want to significantly
70  modify that file to support this board (I thought it impolite to do so).
71 
72  At any rate, if you feel ambitious, please feel free to take
73  the code out of this file and combine it with a more unified driver
74  file.
75 
76  I would like to thank Timothy Curry <[email protected]>
77  for lending me a board so that I could write this driver.
78 
79  -Calin Culianu <[email protected]>
80  */
81 
82 #include "../comedidev.h"
83 
84 #include "8255.h"
85 
86 /* device ids of the cards we support -- currently only 1 card supported */
87 #define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307
88 #define PCI_ID_PCIM_DDA06_16 0x0053
89 
90 /*
91  * Register map, 8-bit access only
92  */
93 #define PCIMDDA_DA_CHAN(x) (0x00 + (x) * 2)
94 #define PCIMDDA_8255_BASE_REG 0x0c
95 
96 #define MAX_AO_READBACK_CHANNELS 6
97 
100 };
101 
102 static int cb_pcimdda_ao_winsn(struct comedi_device *dev,
103  struct comedi_subdevice *s,
104  struct comedi_insn *insn,
105  unsigned int *data)
106 {
107  struct cb_pcimdda_private *devpriv = dev->private;
108  unsigned int chan = CR_CHAN(insn->chanspec);
109  unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan);
110  unsigned int val = 0;
111  int i;
112 
113  for (i = 0; i < insn->n; i++) {
114  val = data[i];
115 
116  /*
117  * Write the LSB then MSB.
118  *
119  * If the simultaneous xfer mode is selected by the
120  * jumper on the card, a read instruction is needed
121  * in order to initiate the simultaneous transfer.
122  * Otherwise, the DAC will be updated when the MSB
123  * is written.
124  */
125  outb(val & 0x00ff, offset);
126  outb((val >> 8) & 0x00ff, offset + 1);
127  }
128 
129  /* Cache the last value for readback */
130  devpriv->ao_readback[chan] = val;
131 
132  return insn->n;
133 }
134 
135 static int cb_pcimdda_ao_rinsn(struct comedi_device *dev,
136  struct comedi_subdevice *s,
137  struct comedi_insn *insn,
138  unsigned int *data)
139 {
140  struct cb_pcimdda_private *devpriv = dev->private;
141  int chan = CR_CHAN(insn->chanspec);
142  unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan);
143  int i;
144 
145  for (i = 0; i < insn->n; i++) {
146  /* Initiate the simultaneous transfer */
147  inw(offset);
148 
149  data[i] = devpriv->ao_readback[chan];
150  }
151 
152  return insn->n;
153 }
154 
155 static int cb_pcimdda_attach_pci(struct comedi_device *dev,
156  struct pci_dev *pcidev)
157 {
158  struct cb_pcimdda_private *devpriv;
159  struct comedi_subdevice *s;
160  int ret;
161 
162  comedi_set_hw_dev(dev, &pcidev->dev);
163  dev->board_name = dev->driver->driver_name;
164 
165  ret = alloc_private(dev, sizeof(*devpriv));
166  if (ret)
167  return ret;
168  devpriv = dev->private;
169 
170  ret = comedi_pci_enable(pcidev, dev->board_name);
171  if (ret)
172  return ret;
173  dev->iobase = pci_resource_start(pcidev, 3);
174 
175  ret = comedi_alloc_subdevices(dev, 2);
176  if (ret)
177  return ret;
178 
179  s = &dev->subdevices[0];
180  /* analog output subdevice */
181  s->type = COMEDI_SUBD_AO;
183  s->n_chan = 6;
184  s->maxdata = 0xffff;
186  s->insn_write = cb_pcimdda_ao_winsn;
187  s->insn_read = cb_pcimdda_ao_rinsn;
188 
189  s = &dev->subdevices[1];
190  /* digital i/o subdevice */
191  ret = subdev_8255_init(dev, s, NULL,
193  if (ret)
194  return ret;
195 
196  dev_info(dev->class_dev, "%s attached\n", dev->board_name);
197 
198  return 1;
199 }
200 
201 static void cb_pcimdda_detach(struct comedi_device *dev)
202 {
203  struct pci_dev *pcidev = comedi_to_pci_dev(dev);
204 
205  if (dev->subdevices)
206  subdev_8255_cleanup(dev, &dev->subdevices[1]);
207  if (pcidev) {
208  if (dev->iobase)
209  comedi_pci_disable(pcidev);
210  }
211 }
212 
213 static struct comedi_driver cb_pcimdda_driver = {
214  .driver_name = "cb_pcimdda",
215  .module = THIS_MODULE,
216  .attach_pci = cb_pcimdda_attach_pci,
217  .detach = cb_pcimdda_detach,
218 };
219 
220 static int __devinit cb_pcimdda_pci_probe(struct pci_dev *dev,
221  const struct pci_device_id *ent)
222 {
223  return comedi_pci_auto_config(dev, &cb_pcimdda_driver);
224 }
225 
226 static void __devexit cb_pcimdda_pci_remove(struct pci_dev *dev)
227 {
229 }
230 
231 static DEFINE_PCI_DEVICE_TABLE(cb_pcimdda_pci_table) = {
233  { 0 }
234 };
235 MODULE_DEVICE_TABLE(pci, cb_pcimdda_pci_table);
236 
237 static struct pci_driver cb_pcimdda_driver_pci_driver = {
238  .name = "cb_pcimdda",
239  .id_table = cb_pcimdda_pci_table,
240  .probe = cb_pcimdda_pci_probe,
241  .remove = __devexit_p(cb_pcimdda_pci_remove),
242 };
243 module_comedi_pci_driver(cb_pcimdda_driver, cb_pcimdda_driver_pci_driver);
244 
245 MODULE_AUTHOR("Calin A. Culianu <[email protected]>");
246 MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
247  "series. Currently only supports PCIM-DDA06-16 (which "
248  "also happens to be the only board in this series. :) ) ");
249 MODULE_LICENSE("GPL");