1/*
2    comedi/drivers/cb_pcimdda.c
3    Computer Boards PCIM-DDA06-16 Comedi driver
4    Author: Calin Culianu <calin@ajvar.org>
5
6    COMEDI - Linux Control and Measurement Device Interface
7    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
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/*
25Driver: cb_pcimdda
26Description: Measurement Computing PCIM-DDA06-16
27Devices: [Measurement Computing] PCIM-DDA06-16 (cb_pcimdda)
28Author: Calin Culianu <calin@ajvar.org>
29Updated: Mon, 14 Apr 2008 15:15:51 +0100
30Status: works
31
32All features of the PCIM-DDA06-16 board are supported.  This board
33has 6 16-bit AO channels, and the usual 8255 DIO setup.  (24 channels,
34configurable in banks of 8 and 4, etc.).  This board does not support commands.
35
36The board has a peculiar way of specifying AO gain/range settings -- You have
371 jumper bank on the card, which either makes all 6 AO channels either
385 Volt unipolar, 5V bipolar, 10 Volt unipolar or 10V bipolar.
39
40Since 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
43default setting of +/-5V.
44
45Also of note is the fact that this board features another jumper, whose
46state is also completely invisible to software.  It toggles two possible AO
47output 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
60Configuration Options:
61  [0] PCI bus (optional)
62  [1] PCI slot (optional)
63  [2] analog output range jumper setting
64      0 == +/- 5 V
65      1 == +/- 10 V
66*/
67
68/*
69    This is a driver for the Computer Boards PCIM-DDA06-16 Analog Output
70    card.  This board has a unique register layout and as such probably
71    deserves its own driver file.
72
73    It is theoretically possible to integrate this board into the cb_pcidda
74    file, but since that isn't my code, I didn't want to significantly
75    modify that file to support this board (I thought it impolite to do so).
76
77    At any rate, if you feel ambitious, please feel free to take
78    the code out of this file and combine it with a more unified driver
79    file.
80
81    I would like to thank Timothy Curry <Timothy.Curry@rdec.redstone.army.mil>
82    for lending me a board so that I could write this driver.
83
84    -Calin Culianu <calin@ajvar.org>
85 */
86
87#include "../comedidev.h"
88
89#include "comedi_pci.h"
90
91#include "8255.h"
92
93/* device ids of the cards we support -- currently only 1 card supported */
94#define PCI_VENDOR_ID_COMPUTERBOARDS	0x1307
95#define PCI_ID_PCIM_DDA06_16		0x0053
96
97/*
98 * This is straight from skel.c -- I did this in case this source file
99 * will someday support more than 1 board...
100 */
101struct board_struct {
102	const char *name;
103	unsigned short device_id;
104	int ao_chans;
105	int ao_bits;
106	int dio_chans;
107	int dio_method;
108	/* how many bytes into the BADR are the DIO ports */
109	int dio_offset;
110	int regs_badrindex;	/* IO Region for the control, analog output,
111				   and DIO registers */
112	int reg_sz;		/* number of bytes of registers in io region */
113};
114
115enum DIO_METHODS {
116	DIO_NONE = 0,
117	DIO_8255,
118	DIO_INTERNAL		/* unimplemented */
119};
120
121static const struct board_struct boards[] = {
122	{
123	 .name = "cb_pcimdda06-16",
124	 .device_id = PCI_ID_PCIM_DDA06_16,
125	 .ao_chans = 6,
126	 .ao_bits = 16,
127	 .dio_chans = 24,
128	 .dio_method = DIO_8255,
129	 .dio_offset = 12,
130	 .regs_badrindex = 3,
131	 .reg_sz = 16,
132	 }
133};
134
135/*
136 * Useful for shorthand access to the particular board structure
137 */
138#define thisboard    ((const struct board_struct *)dev->board_ptr)
139
140#define REG_SZ (thisboard->reg_sz)
141#define REGS_BADRINDEX (thisboard->regs_badrindex)
142
143/* This is used by modprobe to translate PCI IDs to drivers.  Should
144 * only be used for PCI and ISA-PnP devices */
145/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
146 * upstream. */
147static DEFINE_PCI_DEVICE_TABLE(pci_table) = {
148	{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) },
149	{0}
150};
151
152MODULE_DEVICE_TABLE(pci, pci_table);
153
154/*
155 * this structure is for data unique to this hardware driver.  If
156 * several hardware drivers keep similar information in this structure,
157 * feel free to suggest moving the variable to the struct comedi_device
158 * struct.
159 */
160struct board_private_struct {
161	unsigned long registers;	/* set by probe */
162	unsigned long dio_registers;
163	char attached_to_8255;	/* boolean */
164	char attached_successfully;	/* boolean */
165	/* would be useful for a PCI device */
166	struct pci_dev *pci_dev;
167
168#define MAX_AO_READBACK_CHANNELS 6
169	/* Used for AO readback */
170	unsigned int ao_readback[MAX_AO_READBACK_CHANNELS];
171
172};
173
174/*
175 * most drivers define the following macro to make it easy to
176 * access the private structure.
177 */
178#define devpriv ((struct board_private_struct *)dev->private)
179
180/*
181 * The struct comedi_driver structure tells the Comedi core module
182 * which functions to call to configure/deconfigure (attach/detach)
183 * the board, and also about the kernel module that contains
184 * the device code.
185 */
186static int attach(struct comedi_device *dev, struct comedi_devconfig *it);
187static int detach(struct comedi_device *dev);
188static struct comedi_driver cb_pcimdda_driver = {
189	.driver_name = "cb_pcimdda",
190	.module = THIS_MODULE,
191	.attach = attach,
192	.detach = detach,
193};
194
195MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>");
196MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
197		   "series.  Currently only supports PCIM-DDA06-16 (which "
198		   "also happens to be the only board in this series. :) ) ");
199MODULE_LICENSE("GPL");
200static int __devinit cb_pcimdda_driver_pci_probe(struct pci_dev *dev,
201						 const struct pci_device_id
202						 *ent)
203{
204	return comedi_pci_auto_config(dev, cb_pcimdda_driver.driver_name);
205}
206
207static void __devexit cb_pcimdda_driver_pci_remove(struct pci_dev *dev)
208{
209	comedi_pci_auto_unconfig(dev);
210}
211
212static struct pci_driver cb_pcimdda_driver_pci_driver = {
213	.id_table = pci_table,
214	.probe = &cb_pcimdda_driver_pci_probe,
215	.remove = __devexit_p(&cb_pcimdda_driver_pci_remove)
216};
217
218static int __init cb_pcimdda_driver_init_module(void)
219{
220	int retval;
221
222	retval = comedi_driver_register(&cb_pcimdda_driver);
223	if (retval < 0)
224		return retval;
225
226	cb_pcimdda_driver_pci_driver.name =
227	    (char *)cb_pcimdda_driver.driver_name;
228	return pci_register_driver(&cb_pcimdda_driver_pci_driver);
229}
230
231static void __exit cb_pcimdda_driver_cleanup_module(void)
232{
233	pci_unregister_driver(&cb_pcimdda_driver_pci_driver);
234	comedi_driver_unregister(&cb_pcimdda_driver);
235}
236
237module_init(cb_pcimdda_driver_init_module);
238module_exit(cb_pcimdda_driver_cleanup_module);
239
240static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
241		    struct comedi_insn *insn, unsigned int *data);
242static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
243		    struct comedi_insn *insn, unsigned int *data);
244
245/*---------------------------------------------------------------------------
246  HELPER FUNCTION DECLARATIONS
247-----------------------------------------------------------------------------*/
248
249/* returns a maxdata value for a given n_bits */
250static inline unsigned int figure_out_maxdata(int bits)
251{
252	return ((unsigned int)1 << bits) - 1;
253}
254
255/*
256 *  Probes for a supported device.
257 *
258 *  Prerequisite: private be allocated already inside dev
259 *
260 *  If the device is found, it returns 0 and has the following side effects:
261 *
262 *  o  assigns a struct pci_dev * to dev->private->pci_dev
263 *  o  assigns a struct board * to dev->board_ptr
264 *  o  sets dev->private->registers
265 *  o  sets dev->private->dio_registers
266 *
267 *  Otherwise, returns a -errno on error
268 */
269static int probe(struct comedi_device *dev, const struct comedi_devconfig *it);
270
271/*---------------------------------------------------------------------------
272  FUNCTION DEFINITIONS
273-----------------------------------------------------------------------------*/
274
275/*
276 * Attach is called by the Comedi core to configure the driver
277 * for a particular board.  If you specified a board_name array
278 * in the driver structure, dev->board_ptr contains that
279 * address.
280 */
281static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
282{
283	struct comedi_subdevice *s;
284	int err;
285
286/*
287 * Allocate the private structure area.  alloc_private() is a
288 * convenient macro defined in comedidev.h.
289 * if this function fails (returns negative) then the private area is
290 * kfree'd by comedi
291 */
292	if (alloc_private(dev, sizeof(struct board_private_struct)) < 0)
293		return -ENOMEM;
294
295/*
296 * If you can probe the device to determine what device in a series
297 * it is, this is the place to do it.  Otherwise, dev->board_ptr
298 * should already be initialized.
299 */
300	err = probe(dev, it);
301	if (err)
302		return err;
303
304/* Output some info */
305	printk("comedi%d: %s: ", dev->minor, thisboard->name);
306
307/*
308 * Initialize dev->board_name.  Note that we can use the "thisboard"
309 * macro now, since we just initialized it in the last line.
310 */
311	dev->board_name = thisboard->name;
312
313/*
314 * Allocate the subdevice structures.  alloc_subdevice() is a
315 * convenient macro defined in comedidev.h.
316 */
317	if (alloc_subdevices(dev, 2) < 0)
318		return -ENOMEM;
319
320	s = dev->subdevices + 0;
321
322	/* analog output subdevice */
323	s->type = COMEDI_SUBD_AO;
324	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
325	s->n_chan = thisboard->ao_chans;
326	s->maxdata = figure_out_maxdata(thisboard->ao_bits);
327	/* this is hard-coded here */
328	if (it->options[2])
329		s->range_table = &range_bipolar10;
330	else
331		s->range_table = &range_bipolar5;
332	s->insn_write = &ao_winsn;
333	s->insn_read = &ao_rinsn;
334
335	s = dev->subdevices + 1;
336	/* digital i/o subdevice */
337	if (thisboard->dio_chans) {
338		switch (thisboard->dio_method) {
339		case DIO_8255:
340			/*
341			 * this is a straight 8255, so register us with
342			 * the 8255 driver
343			 */
344			subdev_8255_init(dev, s, NULL, devpriv->dio_registers);
345			devpriv->attached_to_8255 = 1;
346			break;
347		case DIO_INTERNAL:
348		default:
349			printk("DIO_INTERNAL not implemented yet!\n");
350			return -ENXIO;
351			break;
352		}
353	} else {
354		s->type = COMEDI_SUBD_UNUSED;
355	}
356
357	devpriv->attached_successfully = 1;
358
359	printk("attached\n");
360
361	return 1;
362}
363
364/*
365 * _detach is called to deconfigure a device.  It should deallocate
366 * resources.
367 * This function is also called when _attach() fails, so it should be
368 * careful not to release resources that were not necessarily
369 * allocated by _attach().  dev->private and dev->subdevices are
370 * deallocated automatically by the core.
371 */
372static int detach(struct comedi_device *dev)
373{
374	if (devpriv) {
375
376		if (dev->subdevices && devpriv->attached_to_8255) {
377			/* de-register us from the 8255 driver */
378			subdev_8255_cleanup(dev, dev->subdevices + 2);
379			devpriv->attached_to_8255 = 0;
380		}
381
382		if (devpriv->pci_dev) {
383			if (devpriv->registers)
384				comedi_pci_disable(devpriv->pci_dev);
385			pci_dev_put(devpriv->pci_dev);
386		}
387
388		if (devpriv->attached_successfully && thisboard)
389			printk("comedi%d: %s: detached\n", dev->minor,
390			       thisboard->name);
391
392	}
393
394	return 0;
395}
396
397static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
398		    struct comedi_insn *insn, unsigned int *data)
399{
400	int i;
401	int chan = CR_CHAN(insn->chanspec);
402	unsigned long offset = devpriv->registers + chan * 2;
403
404	/* Writing a list of values to an AO channel is probably not
405	 * very useful, but that's how the interface is defined. */
406	for (i = 0; i < insn->n; i++) {
407		/*  first, load the low byte */
408		outb((char)(data[i] & 0x00ff), offset);
409		/*  next, write the high byte -- only after this is written is
410		   the channel voltage updated in the DAC, unless
411		   we're in simultaneous xfer mode (jumper on card)
412		   then a rinsn is necessary to actually update the DAC --
413		   see ao_rinsn() below... */
414		outb((char)(data[i] >> 8 & 0x00ff), offset + 1);
415
416		/* for testing only.. the actual rinsn SHOULD do an inw!
417		   (see the stuff about simultaneous XFER mode on this board) */
418		devpriv->ao_readback[chan] = data[i];
419	}
420
421	/* return the number of samples read/written */
422	return i;
423}
424
425/* AO subdevices should have a read insn as well as a write insn.
426
427   Usually this means copying a value stored in devpriv->ao_readback.
428   However, since this board has this jumper setting called "Simultaneous
429   Xfer mode" (off by default), we will support it.  Simultaneaous xfer
430   mode is accomplished by loading ALL the values you want for AO in all the
431   channels, then READing off one of the AO registers to initiate the
432   instantaneous simultaneous update of all DAC outputs, which makes
433   all AO channels update simultaneously.  This is useful for some control
434   applications, I would imagine.
435*/
436static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
437		    struct comedi_insn *insn, unsigned int *data)
438{
439	int i;
440	int chan = CR_CHAN(insn->chanspec);
441
442	for (i = 0; i < insn->n; i++) {
443		inw(devpriv->registers + chan * 2);
444		/*
445		 * should I set data[i] to the result of the actual read
446		 * on the register or the cached unsigned int in
447		 * devpriv->ao_readback[]?
448		 */
449		data[i] = devpriv->ao_readback[chan];
450	}
451
452	return i;
453}
454
455/*---------------------------------------------------------------------------
456  HELPER FUNCTION DEFINITIONS
457-----------------------------------------------------------------------------*/
458
459/*
460 *  Probes for a supported device.
461 *
462 *  Prerequisite: private be allocated already inside dev
463 *
464 *  If the device is found, it returns 0 and has the following side effects:
465 *
466 *  o  assigns a struct pci_dev * to dev->private->pci_dev
467 *  o  assigns a struct board * to dev->board_ptr
468 *  o  sets dev->private->registers
469 *  o  sets dev->private->dio_registers
470 *
471 *  Otherwise, returns a -errno on error
472 */
473static int probe(struct comedi_device *dev, const struct comedi_devconfig *it)
474{
475	struct pci_dev *pcidev = NULL;
476	int index;
477	unsigned long registers;
478
479	for_each_pci_dev(pcidev) {
480		/*  is it not a computer boards card? */
481		if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS)
482			continue;
483		/*  loop through cards supported by this driver */
484		for (index = 0; index < ARRAY_SIZE(boards); index++) {
485			if (boards[index].device_id != pcidev->device)
486				continue;
487			/*  was a particular bus/slot requested? */
488			if (it->options[0] || it->options[1]) {
489				/*  are we on the wrong bus/slot? */
490				if (pcidev->bus->number != it->options[0] ||
491				    PCI_SLOT(pcidev->devfn) != it->options[1]) {
492					continue;
493				}
494			}
495			/* found ! */
496
497			devpriv->pci_dev = pcidev;
498			dev->board_ptr = boards + index;
499			if (comedi_pci_enable(pcidev, thisboard->name)) {
500				printk
501				    ("cb_pcimdda: Failed to enable PCI device and request regions\n");
502				return -EIO;
503			}
504			registers =
505			    pci_resource_start(devpriv->pci_dev,
506					       REGS_BADRINDEX);
507			devpriv->registers = registers;
508			devpriv->dio_registers
509			    = devpriv->registers + thisboard->dio_offset;
510			return 0;
511		}
512	}
513
514	printk("cb_pcimdda: No supported ComputerBoards/MeasurementComputing "
515	       "card found at the requested position\n");
516	return -ENODEV;
517}
518