comedi_bond.c revision 790c55415aa31f4c732729f94d2c3a54f7d3bfc2
1/*
2    comedi/drivers/comedi_bond.c
3    A Comedi driver to 'bond' or merge multiple drivers and devices as one.
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7    Copyright (C) 2005 Calin A. Culianu <calin@ajvar.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: comedi_bond
26Description: A driver to 'bond' (merge) multiple subdevices from multiple
27	     devices together as one.
28Devices:
29Author: ds
30Updated: Mon, 10 Oct 00:18:25 -0500
31Status: works
32
33This driver allows you to 'bond' (merge) multiple comedi subdevices
34(coming from possibly difference boards and/or drivers) together.  For
35example, if you had a board with 2 different DIO subdevices, and
36another with 1 DIO subdevice, you could 'bond' them with this driver
37so that they look like one big fat DIO subdevice.  This makes writing
38applications slightly easier as you don't have to worry about managing
39different subdevices in the application -- you just worry about
40indexing one linear array of channel id's.
41
42Right now only DIO subdevices are supported as that's the personal itch
43I am scratching with this driver.  If you want to add support for AI and AO
44subdevs, go right on ahead and do so!
45
46Commands aren't supported -- although it would be cool if they were.
47
48Configuration Options:
49  List of comedi-minors to bond.  All subdevices of the same type
50  within each minor will be concatenated together in the order given here.
51*/
52
53/*
54 * The previous block comment is used to automatically generate
55 * documentation in Comedi and Comedilib.  The fields:
56 *
57 * Driver: the name of the driver
58 * Description: a short phrase describing the driver.  Don't list boards.
59 * Devices: a full list of the boards that attempt to be supported by
60 *   the driver.  Format is "(manufacturer) board name [comedi name]",
61 *   where comedi_name is the name that is used to configure the board.
62 *   See the comment near board_name: in the comedi_driver structure
63 *   below.  If (manufacturer) or [comedi name] is missing, the previous
64 *   value is used.
65 * Author: you
66 * Updated: date when the _documentation_ was last updated.  Use 'date -R'
67 *   to get a value for this.
68 * Status: a one-word description of the status.  Valid values are:
69 *   works - driver works correctly on most boards supported, and
70 *     passes comedi_test.
71 *   unknown - unknown.  Usually put there by ds.
72 *   experimental - may not work in any particular release.  Author
73 *     probably wants assistance testing it.
74 *   bitrotten - driver has not been update in a long time, probably
75 *     doesn't work, and probably is missing support for significant
76 *     Comedi interface features.
77 *   untested - author probably wrote it "blind", and is believed to
78 *     work, but no confirmation.
79 *
80 * These headers should be followed by a blank line, and any comments
81 * you wish to say about the driver.  The comment area is the place
82 * to put any known bugs, limitations, unsupported features, supported
83 * command triggers, whether or not commands are supported on particular
84 * subdevices, etc.
85 *
86 * Somewhere in the comment should be information about configuration
87 * options that are used with comedi_config.
88 */
89
90#include "../comedilib.h"
91#include "../comedidev.h"
92#include <linux/string.h>
93
94/* The maxiumum number of channels per subdevice. */
95#define MAX_CHANS 256
96
97#define MODULE_NAME "comedi_bond"
98#ifdef MODULE_LICENSE
99MODULE_LICENSE("GPL");
100#endif
101#ifndef STR
102#  define STR1(x) #x
103#  define STR(x) STR1(x)
104#endif
105
106static int debug;
107module_param(debug, int, 0644);
108MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful"
109		 "only to developers.");
110
111#define LOG_MSG(x...) printk(KERN_INFO MODULE_NAME": "x)
112#define DEBUG(x...)							\
113	do {								\
114		if (debug)						\
115			printk(KERN_DEBUG MODULE_NAME": DEBUG: "x);	\
116	} while (0)
117#define WARNING(x...)  printk(KERN_WARNING MODULE_NAME ": WARNING: "x)
118#define ERROR(x...)  printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x)
119MODULE_AUTHOR("Calin A. Culianu");
120MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI "
121		   "devices together as one.  In the words of John Lennon: "
122		   "'And the world will live as one...'");
123
124/*
125 * Board descriptions for two imaginary boards.  Describing the
126 * boards in this way is optional, and completely driver-dependent.
127 * Some drivers use arrays such as this, other do not.
128 */
129struct BondingBoard {
130	const char *name;
131};
132
133static const struct BondingBoard bondingBoards[] = {
134	{
135		.name =	MODULE_NAME,
136	},
137};
138
139/*
140 * Useful for shorthand access to the particular board structure
141 */
142#define thisboard ((const struct BondingBoard *)dev->board_ptr)
143
144struct BondedDevice {
145	void *dev;
146	unsigned minor;
147	unsigned subdev;
148	unsigned subdev_type;
149	unsigned nchans;
150	unsigned chanid_offset;	/* The offset into our unified linear
151				   channel-id's of chanid 0 on this
152				   subdevice. */
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 comedi_device struct.  */
158struct Private {
159# define MAX_BOARD_NAME 256
160	char name[MAX_BOARD_NAME];
161	struct BondedDevice **devs;
162	unsigned ndevs;
163	struct BondedDevice *chanIdDevMap[MAX_CHANS];
164	unsigned nchans;
165};
166
167/*
168 * most drivers define the following macro to make it easy to
169 * access the private structure.
170 */
171#define devpriv ((struct Private *)dev->private)
172
173/*
174 * The comedi_driver structure tells the Comedi core module
175 * which functions to call to configure/deconfigure (attach/detach)
176 * the board, and also about the kernel module that contains
177 * the device code.
178 */
179static int bonding_attach(comedi_device *dev, comedi_devconfig *it);
180static int bonding_detach(comedi_device *dev);
181/** Build Private array of all devices.. */
182static int doDevConfig(comedi_device *dev, comedi_devconfig *it);
183static void doDevUnconfig(comedi_device *dev);
184/* Ugly implementation of realloc that always copies memory around -- I'm lazy,
185 * what can I say?  I like to do wasteful memcopies.. :) */
186static void *Realloc(const void *ptr, size_t len, size_t old_len);
187
188static comedi_driver driver_bonding = {
189      .driver_name =	MODULE_NAME,
190      .module =		THIS_MODULE,
191      .attach =		bonding_attach,
192      .detach =		bonding_detach,
193	/* It is not necessary to implement the following members if you are
194	 * writing a driver for a ISA PnP or PCI card */
195	/* Most drivers will support multiple types of boards by
196	 * having an array of board structures.  These were defined
197	 * in skel_boards[] above.  Note that the element 'name'
198	 * was first in the structure -- Comedi uses this fact to
199	 * extract the name of the board without knowing any details
200	 * about the structure except for its length.
201	 * When a device is attached (by comedi_config), the name
202	 * of the device is given to Comedi, and Comedi tries to
203	 * match it by going through the list of board names.  If
204	 * there is a match, the address of the pointer is put
205	 * into dev->board_ptr and driver->attach() is called.
206	 *
207	 * Note that these are not necessary if you can determine
208	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
209	 * devices are such boards.
210	 */
211      .board_name =	&bondingBoards[0].name,
212      .offset =		sizeof(struct BondingBoard),
213      .num_names =	sizeof(bondingBoards) / sizeof(struct BondingBoard),
214};
215
216static int bonding_dio_insn_bits(comedi_device *dev, comedi_subdevice *s,
217				 comedi_insn *insn, unsigned int *data);
218static int bonding_dio_insn_config(comedi_device *dev, comedi_subdevice *s,
219				   comedi_insn *insn, unsigned int *data);
220
221/*
222 * Attach is called by the Comedi core to configure the driver
223 * for a particular board.  If you specified a board_name array
224 * in the driver structure, dev->board_ptr contains that
225 * address.
226 */
227static int bonding_attach(comedi_device *dev, comedi_devconfig *it)
228{
229	comedi_subdevice *s;
230
231	LOG_MSG("comedi%d\n", dev->minor);
232
233	/*
234	 * Allocate the private structure area.  alloc_private() is a
235	 * convenient macro defined in comedidev.h.
236	 */
237	if (alloc_private(dev, sizeof(struct Private)) < 0)
238		return -ENOMEM;
239
240	/*
241	 * Setup our bonding from config params.. sets up our Private struct..
242	 */
243	if (!doDevConfig(dev, it))
244		return -EINVAL;
245
246	/*
247	 * Initialize dev->board_name.  Note that we can use the "thisboard"
248	 * macro now, since we just initialized it in the last line.
249	 */
250	dev->board_name = devpriv->name;
251
252	/*
253	 * Allocate the subdevice structures.  alloc_subdevice() is a
254	 * convenient macro defined in comedidev.h.
255	 */
256	if (alloc_subdevices(dev, 1) < 0)
257		return -ENOMEM;
258
259	s = dev->subdevices + 0;
260	s->type = COMEDI_SUBD_DIO;
261	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
262	s->n_chan = devpriv->nchans;
263	s->maxdata = 1;
264	s->range_table = &range_digital;
265	s->insn_bits = bonding_dio_insn_bits;
266	s->insn_config = bonding_dio_insn_config;
267
268	LOG_MSG("attached with %u DIO channels coming from %u different "
269		"subdevices all bonded together.  "
270		"John Lennon would be proud!\n",
271		devpriv->nchans, devpriv->ndevs);
272
273	return 1;
274}
275
276/*
277 * _detach is called to deconfigure a device.  It should deallocate
278 * resources.
279 * This function is also called when _attach() fails, so it should be
280 * careful not to release resources that were not necessarily
281 * allocated by _attach().  dev->private and dev->subdevices are
282 * deallocated automatically by the core.
283 */
284static int bonding_detach(comedi_device *dev)
285{
286	LOG_MSG("comedi%d: remove\n", dev->minor);
287	doDevUnconfig(dev);
288	return 0;
289}
290
291/* DIO devices are slightly special.  Although it is possible to
292 * implement the insn_read/insn_write interface, it is much more
293 * useful to applications if you implement the insn_bits interface.
294 * This allows packed reading/writing of the DIO channels.  The
295 * comedi core can convert between insn_bits and insn_read/write */
296static int bonding_dio_insn_bits(comedi_device *dev, comedi_subdevice *s,
297				 comedi_insn *insn, unsigned int *data)
298{
299#define LSAMPL_BITS (sizeof(unsigned int)*8)
300	unsigned nchans = LSAMPL_BITS, num_done = 0, i;
301	if (insn->n != 2)
302		return -EINVAL;
303
304	if (devpriv->nchans < nchans)
305		nchans = devpriv->nchans;
306
307	/* The insn data is a mask in data[0] and the new data
308	 * in data[1], each channel cooresponding to a bit. */
309	for (i = 0; num_done < nchans && i < devpriv->ndevs; ++i) {
310		struct BondedDevice *bdev = devpriv->devs[i];
311		/* Grab the channel mask and data of only the bits corresponding
312		   to this subdevice.. need to shift them to zero position of
313		   course. */
314		/* Bits corresponding to this subdev. */
315		unsigned int subdevMask = ((1 << bdev->nchans) - 1);
316		unsigned int writeMask, dataBits;
317
318		/* Argh, we have >= LSAMPL_BITS chans.. take all bits */
319		if (bdev->nchans >= LSAMPL_BITS)
320			subdevMask = (unsigned int) (-1);
321
322		writeMask = (data[0] >> num_done) & subdevMask;
323		dataBits = (data[1] >> num_done) & subdevMask;
324
325		/* Read/Write the new digital lines */
326		if (comedi_dio_bitfield(bdev->dev, bdev->subdev, writeMask,
327				&dataBits) != 2)
328			return -EINVAL;
329
330		/* Make room for the new bits in data[1], the return value */
331		data[1] &= ~(subdevMask << num_done);
332		/* Put the bits in the return value */
333		data[1] |= (dataBits & subdevMask) << num_done;
334		/* Save the new bits to the saved state.. */
335		s->state = data[1];
336
337		num_done += bdev->nchans;
338	}
339
340	return insn->n;
341}
342
343static int bonding_dio_insn_config(comedi_device *dev, comedi_subdevice *s,
344				   comedi_insn *insn, unsigned int *data)
345{
346	int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits;
347	unsigned int io;
348	struct BondedDevice *bdev;
349
350	if (chan < 0 || chan >= devpriv->nchans)
351		return -EINVAL;
352	bdev = devpriv->chanIdDevMap[chan];
353
354	/* The input or output configuration of each digital line is
355	 * configured by a special insn_config instruction.  chanspec
356	 * contains the channel to be changed, and data[0] contains the
357	 * value COMEDI_INPUT or COMEDI_OUTPUT. */
358	switch (data[0]) {
359	case INSN_CONFIG_DIO_OUTPUT:
360		io = COMEDI_OUTPUT;	/* is this really necessary? */
361		io_bits |= 1 << chan;
362		break;
363	case INSN_CONFIG_DIO_INPUT:
364		io = COMEDI_INPUT;	/* is this really necessary? */
365		io_bits &= ~(1 << chan);
366		break;
367	case INSN_CONFIG_DIO_QUERY:
368		data[1] =
369			(io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
370		return insn->n;
371		break;
372	default:
373		return -EINVAL;
374		break;
375	}
376	/* 'real' channel id for this subdev.. */
377	chan -= bdev->chanid_offset;
378	ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, io);
379	if (ret != 1)
380		return -EINVAL;
381	/* Finally, save the new io_bits values since we didn't get
382	   an error above. */
383	s->io_bits = io_bits;
384	return insn->n;
385}
386
387static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen)
388{
389	void *newmem = kmalloc(newlen, GFP_KERNEL);
390
391	if (newmem && oldmem)
392		memcpy(newmem, oldmem, min(oldlen, newlen));
393	kfree(oldmem);
394	return newmem;
395}
396
397static int doDevConfig(comedi_device *dev, comedi_devconfig *it)
398{
399	int i;
400	void *devs_opened[COMEDI_NUM_BOARD_MINORS];
401
402	memset(devs_opened, 0, sizeof(devs_opened));
403	devpriv->name[0] = 0;;
404	/* Loop through all comedi devices specified on the command-line,
405	   building our device list */
406	for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) {
407		char file[] = "/dev/comediXXXXXX";
408		int minor = it->options[i];
409		void *d;
410		int sdev = -1, nchans, tmp;
411		struct BondedDevice *bdev = NULL;
412
413		if (minor < 0 || minor > COMEDI_NUM_BOARD_MINORS) {
414			ERROR("Minor %d is invalid!\n", minor);
415			return 0;
416		}
417		if (minor == dev->minor) {
418			ERROR("Cannot bond this driver to itself!\n");
419			return 0;
420		}
421		if (devs_opened[minor]) {
422			ERROR("Minor %d specified more than once!\n", minor);
423			return 0;
424		}
425
426		snprintf(file, sizeof(file), "/dev/comedi%u", minor);
427		file[sizeof(file) - 1] = 0;
428
429		d = devs_opened[minor] = comedi_open(file);
430
431		if (!d) {
432			ERROR("Minor %u could not be opened\n", minor);
433			return 0;
434		}
435
436		/* Do DIO, as that's all we support now.. */
437		while ((sdev = comedi_find_subdevice_by_type(d, COMEDI_SUBD_DIO,
438					sdev + 1)) > -1) {
439			nchans = comedi_get_n_channels(d, sdev);
440			if (nchans <= 0) {
441				ERROR("comedi_get_n_channels() returned %d "
442				      "on minor %u subdev %d!\n",
443				      nchans, minor, sdev);
444				return 0;
445			}
446			bdev = kmalloc(sizeof(*bdev), GFP_KERNEL);
447			if (!bdev) {
448				ERROR("Out of memory.\n");
449				return 0;
450			}
451			bdev->dev = d;
452			bdev->minor = minor;
453			bdev->subdev = sdev;
454			bdev->subdev_type = COMEDI_SUBD_DIO;
455			bdev->nchans = nchans;
456			bdev->chanid_offset = devpriv->nchans;
457
458			/* map channel id's to BondedDevice * pointer.. */
459			while (nchans--)
460				devpriv->chanIdDevMap[devpriv->nchans++] = bdev;
461
462			/* Now put bdev pointer at end of devpriv->devs array
463			 * list.. */
464
465			/* ergh.. ugly.. we need to realloc :(  */
466			tmp = devpriv->ndevs * sizeof(bdev);
467			devpriv->devs =
468				Realloc(devpriv->devs,
469				++devpriv->ndevs * sizeof(bdev), tmp);
470			if (!devpriv->devs) {
471				ERROR("Could not allocate memory. "
472				      "Out of memory?");
473				return 0;
474			}
475
476			devpriv->devs[devpriv->ndevs - 1] = bdev;
477			{
478	/** Append dev:subdev to devpriv->name */
479				char buf[20];
480				int left =
481					MAX_BOARD_NAME - strlen(devpriv->name) -
482					1;
483				snprintf(buf, sizeof(buf), "%d:%d ", dev->minor,
484					bdev->subdev);
485				buf[sizeof(buf) - 1] = 0;
486				strncat(devpriv->name, buf, left);
487			}
488
489		}
490	}
491
492	if (!devpriv->nchans) {
493		ERROR("No channels found!\n");
494		return 0;
495	}
496
497	return 1;
498}
499
500static void doDevUnconfig(comedi_device *dev)
501{
502	unsigned long devs_closed = 0;
503
504	if (devpriv) {
505		while (devpriv->ndevs-- && devpriv->devs) {
506			struct BondedDevice *bdev;
507
508			bdev = devpriv->devs[devpriv->ndevs];
509			if (!bdev)
510				continue;
511			if (!(devs_closed & (0x1 << bdev->minor))) {
512				comedi_close(bdev->dev);
513				devs_closed |= (0x1 << bdev->minor);
514			}
515			kfree(bdev);
516		}
517		kfree(devpriv->devs);
518		devpriv->devs = NULL;
519		kfree(devpriv);
520		dev->private = NULL;
521	}
522}
523
524static int __init init(void)
525{
526	return comedi_driver_register(&driver_bonding);
527}
528
529static void __exit cleanup(void)
530{
531	comedi_driver_unregister(&driver_bonding);
532}
533
534module_init(init);
535module_exit(cleanup);
536