2 comedi/drivers/comedi_bond.c
3 A Comedi driver to 'bond' or merge multiple drivers and devices as one.
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>
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.
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.
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.
26 Description: A driver to 'bond' (merge) multiple subdevices from multiple
27 devices together as one.
30 Updated: Mon, 10 Oct 00:18:25 -0500
33 This driver allows you to 'bond' (merge) multiple comedi subdevices
34 (coming from possibly difference boards and/or drivers) together. For
35 example, if you had a board with 2 different DIO subdevices, and
36 another with 1 DIO subdevice, you could 'bond' them with this driver
37 so that they look like one big fat DIO subdevice. This makes writing
38 applications slightly easier as you don't have to worry about managing
39 different subdevices in the application -- you just worry about
40 indexing one linear array of channel id's.
42 Right now only DIO subdevices are supported as that's the personal itch
43 I am scratching with this driver. If you want to add support for AI and AO
44 subdevs, go right on ahead and do so!
46 Commands aren't supported -- although it would be cool if they were.
48 Configuration 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.
54 * The previous block comment is used to automatically generate
55 * documentation in Comedi and Comedilib. The fields:
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 struct comedi_driver structure
63 * below. If (manufacturer) or [comedi name] is missing, the previous
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
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.
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
86 * Somewhere in the comment should be information about configuration
87 * options that are used with comedi_config.
90 #include "../comedilib.h"
91 #include "../comedidev.h"
92 #include <linux/string.h>
93 #include <linux/slab.h>
95 /* The maxiumum number of channels per subdevice. */
98 #define MODULE_NAME "comedi_bond"
100 MODULE_LICENSE("GPL");
104 # define STR(x) STR1(x)
108 module_param(debug, int, 0644);
109 MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful"
110 "only to developers.");
112 #define LOG_MSG(x...) printk(KERN_INFO MODULE_NAME": "x)
113 #define DEBUG(x...) \
116 printk(KERN_DEBUG MODULE_NAME": DEBUG: "x); \
118 #define WARNING(x...) printk(KERN_WARNING MODULE_NAME ": WARNING: "x)
119 #define ERROR(x...) printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x)
120 MODULE_AUTHOR("Calin A. Culianu");
121 MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI "
122 "devices together as one. In the words of John Lennon: "
123 "'And the world will live as one...'");
126 * Board descriptions for two imaginary boards. Describing the
127 * boards in this way is optional, and completely driver-dependent.
128 * Some drivers use arrays such as this, other do not.
130 struct BondingBoard {
134 static const struct BondingBoard bondingBoards[] = {
141 * Useful for shorthand access to the particular board structure
143 #define thisboard ((const struct BondingBoard *)dev->board_ptr)
145 struct BondedDevice {
149 unsigned subdev_type;
151 unsigned chanid_offset; /* The offset into our unified linear
152 channel-id's of chanid 0 on this
156 /* this structure is for data unique to this hardware driver. If
157 several hardware drivers keep similar information in this structure,
158 feel free to suggest moving the variable to the struct comedi_device struct. */
160 # define MAX_BOARD_NAME 256
161 char name[MAX_BOARD_NAME];
162 struct BondedDevice **devs;
164 struct BondedDevice *chanIdDevMap[MAX_CHANS];
169 * most drivers define the following macro to make it easy to
170 * access the private structure.
172 #define devpriv ((struct Private *)dev->private)
175 * The struct comedi_driver structure tells the Comedi core module
176 * which functions to call to configure/deconfigure (attach/detach)
177 * the board, and also about the kernel module that contains
180 static int bonding_attach(struct comedi_device *dev,
181 struct comedi_devconfig *it);
182 static int bonding_detach(struct comedi_device *dev);
183 /** Build Private array of all devices.. */
184 static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it);
185 static void doDevUnconfig(struct comedi_device *dev);
186 /* Ugly implementation of realloc that always copies memory around -- I'm lazy,
187 * what can I say? I like to do wasteful memcopies.. :) */
188 static void *Realloc(const void *ptr, size_t len, size_t old_len);
190 static struct comedi_driver driver_bonding = {
191 .driver_name = MODULE_NAME,
192 .module = THIS_MODULE,
193 .attach = bonding_attach,
194 .detach = bonding_detach,
195 /* It is not necessary to implement the following members if you are
196 * writing a driver for a ISA PnP or PCI card */
197 /* Most drivers will support multiple types of boards by
198 * having an array of board structures. These were defined
199 * in skel_boards[] above. Note that the element 'name'
200 * was first in the structure -- Comedi uses this fact to
201 * extract the name of the board without knowing any details
202 * about the structure except for its length.
203 * When a device is attached (by comedi_config), the name
204 * of the device is given to Comedi, and Comedi tries to
205 * match it by going through the list of board names. If
206 * there is a match, the address of the pointer is put
207 * into dev->board_ptr and driver->attach() is called.
209 * Note that these are not necessary if you can determine
210 * the type of board in software. ISA PnP, PCI, and PCMCIA
211 * devices are such boards.
213 .board_name = &bondingBoards[0].name,
214 .offset = sizeof(struct BondingBoard),
215 .num_names = ARRAY_SIZE(bondingBoards),
218 static int bonding_dio_insn_bits(struct comedi_device *dev,
219 struct comedi_subdevice *s,
220 struct comedi_insn *insn, unsigned int *data);
221 static int bonding_dio_insn_config(struct comedi_device *dev,
222 struct comedi_subdevice *s,
223 struct comedi_insn *insn,
227 * Attach is called by the Comedi core to configure the driver
228 * for a particular board. If you specified a board_name array
229 * in the driver structure, dev->board_ptr contains that
232 static int bonding_attach(struct comedi_device *dev,
233 struct comedi_devconfig *it)
235 struct comedi_subdevice *s;
237 LOG_MSG("comedi%d\n", dev->minor);
240 * Allocate the private structure area. alloc_private() is a
241 * convenient macro defined in comedidev.h.
243 if (alloc_private(dev, sizeof(struct Private)) < 0)
247 * Setup our bonding from config params.. sets up our Private struct..
249 if (!doDevConfig(dev, it))
253 * Initialize dev->board_name. Note that we can use the "thisboard"
254 * macro now, since we just initialized it in the last line.
256 dev->board_name = devpriv->name;
259 * Allocate the subdevice structures. alloc_subdevice() is a
260 * convenient macro defined in comedidev.h.
262 if (alloc_subdevices(dev, 1) < 0)
265 s = dev->subdevices + 0;
266 s->type = COMEDI_SUBD_DIO;
267 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
268 s->n_chan = devpriv->nchans;
270 s->range_table = &range_digital;
271 s->insn_bits = bonding_dio_insn_bits;
272 s->insn_config = bonding_dio_insn_config;
274 LOG_MSG("attached with %u DIO channels coming from %u different "
275 "subdevices all bonded together. "
276 "John Lennon would be proud!\n",
277 devpriv->nchans, devpriv->ndevs);
283 * _detach is called to deconfigure a device. It should deallocate
285 * This function is also called when _attach() fails, so it should be
286 * careful not to release resources that were not necessarily
287 * allocated by _attach(). dev->private and dev->subdevices are
288 * deallocated automatically by the core.
290 static int bonding_detach(struct comedi_device *dev)
292 LOG_MSG("comedi%d: remove\n", dev->minor);
297 /* DIO devices are slightly special. Although it is possible to
298 * implement the insn_read/insn_write interface, it is much more
299 * useful to applications if you implement the insn_bits interface.
300 * This allows packed reading/writing of the DIO channels. The
301 * comedi core can convert between insn_bits and insn_read/write */
302 static int bonding_dio_insn_bits(struct comedi_device *dev,
303 struct comedi_subdevice *s,
304 struct comedi_insn *insn, unsigned int *data)
306 #define LSAMPL_BITS (sizeof(unsigned int)*8)
307 unsigned nchans = LSAMPL_BITS, num_done = 0, i;
311 if (devpriv->nchans < nchans)
312 nchans = devpriv->nchans;
314 /* The insn data is a mask in data[0] and the new data
315 * in data[1], each channel cooresponding to a bit. */
316 for (i = 0; num_done < nchans && i < devpriv->ndevs; ++i) {
317 struct BondedDevice *bdev = devpriv->devs[i];
318 /* Grab the channel mask and data of only the bits corresponding
319 to this subdevice.. need to shift them to zero position of
321 /* Bits corresponding to this subdev. */
322 unsigned int subdevMask = ((1 << bdev->nchans) - 1);
323 unsigned int writeMask, dataBits;
325 /* Argh, we have >= LSAMPL_BITS chans.. take all bits */
326 if (bdev->nchans >= LSAMPL_BITS)
327 subdevMask = (unsigned int)(-1);
329 writeMask = (data[0] >> num_done) & subdevMask;
330 dataBits = (data[1] >> num_done) & subdevMask;
332 /* Read/Write the new digital lines */
333 if (comedi_dio_bitfield(bdev->dev, bdev->subdev, writeMask,
337 /* Make room for the new bits in data[1], the return value */
338 data[1] &= ~(subdevMask << num_done);
339 /* Put the bits in the return value */
340 data[1] |= (dataBits & subdevMask) << num_done;
341 /* Save the new bits to the saved state.. */
344 num_done += bdev->nchans;
350 static int bonding_dio_insn_config(struct comedi_device *dev,
351 struct comedi_subdevice *s,
352 struct comedi_insn *insn, unsigned int *data)
354 int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits;
356 struct BondedDevice *bdev;
358 if (chan < 0 || chan >= devpriv->nchans)
360 bdev = devpriv->chanIdDevMap[chan];
362 /* The input or output configuration of each digital line is
363 * configured by a special insn_config instruction. chanspec
364 * contains the channel to be changed, and data[0] contains the
365 * value COMEDI_INPUT or COMEDI_OUTPUT. */
367 case INSN_CONFIG_DIO_OUTPUT:
368 io = COMEDI_OUTPUT; /* is this really necessary? */
369 io_bits |= 1 << chan;
371 case INSN_CONFIG_DIO_INPUT:
372 io = COMEDI_INPUT; /* is this really necessary? */
373 io_bits &= ~(1 << chan);
375 case INSN_CONFIG_DIO_QUERY:
377 (io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
384 /* 'real' channel id for this subdev.. */
385 chan -= bdev->chanid_offset;
386 ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, io);
389 /* Finally, save the new io_bits values since we didn't get
391 s->io_bits = io_bits;
395 static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen)
397 void *newmem = kmalloc(newlen, GFP_KERNEL);
399 if (newmem && oldmem)
400 memcpy(newmem, oldmem, min(oldlen, newlen));
405 static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
408 void *devs_opened[COMEDI_NUM_BOARD_MINORS];
410 memset(devs_opened, 0, sizeof(devs_opened));
411 devpriv->name[0] = 0;;
412 /* Loop through all comedi devices specified on the command-line,
413 building our device list */
414 for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) {
415 char file[] = "/dev/comediXXXXXX";
416 int minor = it->options[i];
418 int sdev = -1, nchans, tmp;
419 struct BondedDevice *bdev = NULL;
421 if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) {
422 ERROR("Minor %d is invalid!\n", minor);
425 if (minor == dev->minor) {
426 ERROR("Cannot bond this driver to itself!\n");
429 if (devs_opened[minor]) {
430 ERROR("Minor %d specified more than once!\n", minor);
434 snprintf(file, sizeof(file), "/dev/comedi%u", minor);
435 file[sizeof(file) - 1] = 0;
437 d = devs_opened[minor] = comedi_open(file);
440 ERROR("Minor %u could not be opened\n", minor);
444 /* Do DIO, as that's all we support now.. */
445 while ((sdev = comedi_find_subdevice_by_type(d, COMEDI_SUBD_DIO,
447 nchans = comedi_get_n_channels(d, sdev);
449 ERROR("comedi_get_n_channels() returned %d "
450 "on minor %u subdev %d!\n",
451 nchans, minor, sdev);
454 bdev = kmalloc(sizeof(*bdev), GFP_KERNEL);
456 ERROR("Out of memory.\n");
462 bdev->subdev_type = COMEDI_SUBD_DIO;
463 bdev->nchans = nchans;
464 bdev->chanid_offset = devpriv->nchans;
466 /* map channel id's to BondedDevice * pointer.. */
468 devpriv->chanIdDevMap[devpriv->nchans++] = bdev;
470 /* Now put bdev pointer at end of devpriv->devs array
473 /* ergh.. ugly.. we need to realloc :( */
474 tmp = devpriv->ndevs * sizeof(bdev);
476 Realloc(devpriv->devs,
477 ++devpriv->ndevs * sizeof(bdev), tmp);
478 if (!devpriv->devs) {
479 ERROR("Could not allocate memory. "
484 devpriv->devs[devpriv->ndevs - 1] = bdev;
486 /** Append dev:subdev to devpriv->name */
489 MAX_BOARD_NAME - strlen(devpriv->name) - 1;
490 snprintf(buf, sizeof(buf), "%d:%d ", dev->minor,
492 buf[sizeof(buf) - 1] = 0;
493 strncat(devpriv->name, buf, left);
499 if (!devpriv->nchans) {
500 ERROR("No channels found!\n");
507 static void doDevUnconfig(struct comedi_device *dev)
509 unsigned long devs_closed = 0;
512 while (devpriv->ndevs-- && devpriv->devs) {
513 struct BondedDevice *bdev;
515 bdev = devpriv->devs[devpriv->ndevs];
518 if (!(devs_closed & (0x1 << bdev->minor))) {
519 comedi_close(bdev->dev);
520 devs_closed |= (0x1 << bdev->minor);
524 kfree(devpriv->devs);
525 devpriv->devs = NULL;
531 static int __init init(void)
533 return comedi_driver_register(&driver_bonding);
536 static void __exit cleanup(void)
538 comedi_driver_unregister(&driver_bonding);
542 module_exit(cleanup);