GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / comedi / drivers / comedi_bond.c
blobcfcbd9b8f39376bc9de300a86104c198db2a4d2c
1 /*
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.
25 Driver: comedi_bond
26 Description: A driver to 'bond' (merge) multiple subdevices from multiple
27 devices together as one.
28 Devices:
29 Author: ds
30 Updated: Mon, 10 Oct 00:18:25 -0500
31 Status: works
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.
53 #include <linux/string.h>
54 #include <linux/slab.h>
55 #include "../comedi.h"
56 #include "../comedilib.h"
57 #include "../comedidev.h"
59 /* The maxiumum number of channels per subdevice. */
60 #define MAX_CHANS 256
62 #define MODULE_NAME "comedi_bond"
63 MODULE_LICENSE("GPL");
64 #ifndef STR
65 # define STR1(x) #x
66 # define STR(x) STR1(x)
67 #endif
69 static int debug;
70 module_param(debug, int, 0644);
71 MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful"
72 "only to developers.");
74 #define LOG_MSG(x...) printk(KERN_INFO MODULE_NAME": "x)
75 #define DEBUG(x...) \
76 do { \
77 if (debug) \
78 printk(KERN_DEBUG MODULE_NAME": DEBUG: "x); \
79 } while (0)
80 #define WARNING(x...) printk(KERN_WARNING MODULE_NAME ": WARNING: "x)
81 #define ERROR(x...) printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x)
82 MODULE_AUTHOR("Calin A. Culianu");
83 MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI "
84 "devices together as one. In the words of John Lennon: "
85 "'And the world will live as one...'");
88 * Board descriptions for two imaginary boards. Describing the
89 * boards in this way is optional, and completely driver-dependent.
90 * Some drivers use arrays such as this, other do not.
92 struct BondingBoard {
93 const char *name;
96 static const struct BondingBoard bondingBoards[] = {
98 .name = MODULE_NAME,
103 * Useful for shorthand access to the particular board structure
105 #define thisboard ((const struct BondingBoard *)dev->board_ptr)
107 struct BondedDevice {
108 struct comedi_device *dev;
109 unsigned minor;
110 unsigned subdev;
111 unsigned subdev_type;
112 unsigned nchans;
113 unsigned chanid_offset; /* The offset into our unified linear
114 channel-id's of chanid 0 on this
115 subdevice. */
118 /* this structure is for data unique to this hardware driver. If
119 several hardware drivers keep similar information in this structure,
120 feel free to suggest moving the variable to the struct comedi_device struct. */
121 struct Private {
122 # define MAX_BOARD_NAME 256
123 char name[MAX_BOARD_NAME];
124 struct BondedDevice **devs;
125 unsigned ndevs;
126 struct BondedDevice *chanIdDevMap[MAX_CHANS];
127 unsigned nchans;
131 * most drivers define the following macro to make it easy to
132 * access the private structure.
134 #define devpriv ((struct Private *)dev->private)
137 * The struct comedi_driver structure tells the Comedi core module
138 * which functions to call to configure/deconfigure (attach/detach)
139 * the board, and also about the kernel module that contains
140 * the device code.
142 static int bonding_attach(struct comedi_device *dev,
143 struct comedi_devconfig *it);
144 static int bonding_detach(struct comedi_device *dev);
145 /** Build Private array of all devices.. */
146 static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it);
147 static void doDevUnconfig(struct comedi_device *dev);
148 /* Ugly implementation of realloc that always copies memory around -- I'm lazy,
149 * what can I say? I like to do wasteful memcopies.. :) */
150 static void *Realloc(const void *ptr, size_t len, size_t old_len);
152 static struct comedi_driver driver_bonding = {
153 .driver_name = MODULE_NAME,
154 .module = THIS_MODULE,
155 .attach = bonding_attach,
156 .detach = bonding_detach,
157 /* It is not necessary to implement the following members if you are
158 * writing a driver for a ISA PnP or PCI card */
159 /* Most drivers will support multiple types of boards by
160 * having an array of board structures. These were defined
161 * in skel_boards[] above. Note that the element 'name'
162 * was first in the structure -- Comedi uses this fact to
163 * extract the name of the board without knowing any details
164 * about the structure except for its length.
165 * When a device is attached (by comedi_config), the name
166 * of the device is given to Comedi, and Comedi tries to
167 * match it by going through the list of board names. If
168 * there is a match, the address of the pointer is put
169 * into dev->board_ptr and driver->attach() is called.
171 * Note that these are not necessary if you can determine
172 * the type of board in software. ISA PnP, PCI, and PCMCIA
173 * devices are such boards.
175 .board_name = &bondingBoards[0].name,
176 .offset = sizeof(struct BondingBoard),
177 .num_names = ARRAY_SIZE(bondingBoards),
180 static int bonding_dio_insn_bits(struct comedi_device *dev,
181 struct comedi_subdevice *s,
182 struct comedi_insn *insn, unsigned int *data);
183 static int bonding_dio_insn_config(struct comedi_device *dev,
184 struct comedi_subdevice *s,
185 struct comedi_insn *insn,
186 unsigned int *data);
189 * Attach is called by the Comedi core to configure the driver
190 * for a particular board. If you specified a board_name array
191 * in the driver structure, dev->board_ptr contains that
192 * address.
194 static int bonding_attach(struct comedi_device *dev,
195 struct comedi_devconfig *it)
197 struct comedi_subdevice *s;
199 LOG_MSG("comedi%d\n", dev->minor);
202 * Allocate the private structure area. alloc_private() is a
203 * convenient macro defined in comedidev.h.
205 if (alloc_private(dev, sizeof(struct Private)) < 0)
206 return -ENOMEM;
209 * Setup our bonding from config params.. sets up our Private struct..
211 if (!doDevConfig(dev, it))
212 return -EINVAL;
215 * Initialize dev->board_name. Note that we can use the "thisboard"
216 * macro now, since we just initialized it in the last line.
218 dev->board_name = devpriv->name;
221 * Allocate the subdevice structures. alloc_subdevice() is a
222 * convenient macro defined in comedidev.h.
224 if (alloc_subdevices(dev, 1) < 0)
225 return -ENOMEM;
227 s = dev->subdevices + 0;
228 s->type = COMEDI_SUBD_DIO;
229 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
230 s->n_chan = devpriv->nchans;
231 s->maxdata = 1;
232 s->range_table = &range_digital;
233 s->insn_bits = bonding_dio_insn_bits;
234 s->insn_config = bonding_dio_insn_config;
236 LOG_MSG("attached with %u DIO channels coming from %u different "
237 "subdevices all bonded together. "
238 "John Lennon would be proud!\n",
239 devpriv->nchans, devpriv->ndevs);
241 return 1;
245 * _detach is called to deconfigure a device. It should deallocate
246 * resources.
247 * This function is also called when _attach() fails, so it should be
248 * careful not to release resources that were not necessarily
249 * allocated by _attach(). dev->private and dev->subdevices are
250 * deallocated automatically by the core.
252 static int bonding_detach(struct comedi_device *dev)
254 LOG_MSG("comedi%d: remove\n", dev->minor);
255 doDevUnconfig(dev);
256 return 0;
259 /* DIO devices are slightly special. Although it is possible to
260 * implement the insn_read/insn_write interface, it is much more
261 * useful to applications if you implement the insn_bits interface.
262 * This allows packed reading/writing of the DIO channels. The
263 * comedi core can convert between insn_bits and insn_read/write */
264 static int bonding_dio_insn_bits(struct comedi_device *dev,
265 struct comedi_subdevice *s,
266 struct comedi_insn *insn, unsigned int *data)
268 #define LSAMPL_BITS (sizeof(unsigned int)*8)
269 unsigned nchans = LSAMPL_BITS, num_done = 0, i;
270 if (insn->n != 2)
271 return -EINVAL;
273 if (devpriv->nchans < nchans)
274 nchans = devpriv->nchans;
276 /* The insn data is a mask in data[0] and the new data
277 * in data[1], each channel cooresponding to a bit. */
278 for (i = 0; num_done < nchans && i < devpriv->ndevs; ++i) {
279 struct BondedDevice *bdev = devpriv->devs[i];
280 /* Grab the channel mask and data of only the bits corresponding
281 to this subdevice.. need to shift them to zero position of
282 course. */
283 /* Bits corresponding to this subdev. */
284 unsigned int subdevMask = ((1 << bdev->nchans) - 1);
285 unsigned int writeMask, dataBits;
287 /* Argh, we have >= LSAMPL_BITS chans.. take all bits */
288 if (bdev->nchans >= LSAMPL_BITS)
289 subdevMask = (unsigned int)(-1);
291 writeMask = (data[0] >> num_done) & subdevMask;
292 dataBits = (data[1] >> num_done) & subdevMask;
294 /* Read/Write the new digital lines */
295 if (comedi_dio_bitfield(bdev->dev, bdev->subdev, writeMask,
296 &dataBits) != 2)
297 return -EINVAL;
299 /* Make room for the new bits in data[1], the return value */
300 data[1] &= ~(subdevMask << num_done);
301 /* Put the bits in the return value */
302 data[1] |= (dataBits & subdevMask) << num_done;
303 /* Save the new bits to the saved state.. */
304 s->state = data[1];
306 num_done += bdev->nchans;
309 return insn->n;
312 static int bonding_dio_insn_config(struct comedi_device *dev,
313 struct comedi_subdevice *s,
314 struct comedi_insn *insn, unsigned int *data)
316 int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits;
317 unsigned int io;
318 struct BondedDevice *bdev;
320 if (chan < 0 || chan >= devpriv->nchans)
321 return -EINVAL;
322 bdev = devpriv->chanIdDevMap[chan];
324 /* The input or output configuration of each digital line is
325 * configured by a special insn_config instruction. chanspec
326 * contains the channel to be changed, and data[0] contains the
327 * value COMEDI_INPUT or COMEDI_OUTPUT. */
328 switch (data[0]) {
329 case INSN_CONFIG_DIO_OUTPUT:
330 io = COMEDI_OUTPUT; /* is this really necessary? */
331 io_bits |= 1 << chan;
332 break;
333 case INSN_CONFIG_DIO_INPUT:
334 io = COMEDI_INPUT; /* is this really necessary? */
335 io_bits &= ~(1 << chan);
336 break;
337 case INSN_CONFIG_DIO_QUERY:
338 data[1] =
339 (io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
340 return insn->n;
341 break;
342 default:
343 return -EINVAL;
344 break;
346 /* 'real' channel id for this subdev.. */
347 chan -= bdev->chanid_offset;
348 ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, io);
349 if (ret != 1)
350 return -EINVAL;
351 /* Finally, save the new io_bits values since we didn't get
352 an error above. */
353 s->io_bits = io_bits;
354 return insn->n;
357 static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen)
359 void *newmem = kmalloc(newlen, GFP_KERNEL);
361 if (newmem && oldmem)
362 memcpy(newmem, oldmem, min(oldlen, newlen));
363 kfree(oldmem);
364 return newmem;
367 static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
369 int i;
370 struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS];
372 memset(devs_opened, 0, sizeof(devs_opened));
373 devpriv->name[0] = 0;;
374 /* Loop through all comedi devices specified on the command-line,
375 building our device list */
376 for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) {
377 char file[] = "/dev/comediXXXXXX";
378 int minor = it->options[i];
379 struct comedi_device *d;
380 int sdev = -1, nchans, tmp;
381 struct BondedDevice *bdev = NULL;
383 if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) {
384 ERROR("Minor %d is invalid!\n", minor);
385 return 0;
387 if (minor == dev->minor) {
388 ERROR("Cannot bond this driver to itself!\n");
389 return 0;
391 if (devs_opened[minor]) {
392 ERROR("Minor %d specified more than once!\n", minor);
393 return 0;
396 snprintf(file, sizeof(file), "/dev/comedi%u", minor);
397 file[sizeof(file) - 1] = 0;
399 d = devs_opened[minor] = comedi_open(file);
401 if (!d) {
402 ERROR("Minor %u could not be opened\n", minor);
403 return 0;
406 /* Do DIO, as that's all we support now.. */
407 while ((sdev = comedi_find_subdevice_by_type(d, COMEDI_SUBD_DIO,
408 sdev + 1)) > -1) {
409 nchans = comedi_get_n_channels(d, sdev);
410 if (nchans <= 0) {
411 ERROR("comedi_get_n_channels() returned %d "
412 "on minor %u subdev %d!\n",
413 nchans, minor, sdev);
414 return 0;
416 bdev = kmalloc(sizeof(*bdev), GFP_KERNEL);
417 if (!bdev) {
418 ERROR("Out of memory.\n");
419 return 0;
421 bdev->dev = d;
422 bdev->minor = minor;
423 bdev->subdev = sdev;
424 bdev->subdev_type = COMEDI_SUBD_DIO;
425 bdev->nchans = nchans;
426 bdev->chanid_offset = devpriv->nchans;
428 /* map channel id's to BondedDevice * pointer.. */
429 while (nchans--)
430 devpriv->chanIdDevMap[devpriv->nchans++] = bdev;
432 /* Now put bdev pointer at end of devpriv->devs array
433 * list.. */
435 /* ergh.. ugly.. we need to realloc :( */
436 tmp = devpriv->ndevs * sizeof(bdev);
437 devpriv->devs =
438 Realloc(devpriv->devs,
439 ++devpriv->ndevs * sizeof(bdev), tmp);
440 if (!devpriv->devs) {
441 ERROR("Could not allocate memory. "
442 "Out of memory?");
443 return 0;
446 devpriv->devs[devpriv->ndevs - 1] = bdev;
448 /** Append dev:subdev to devpriv->name */
449 char buf[20];
450 int left =
451 MAX_BOARD_NAME - strlen(devpriv->name) - 1;
452 snprintf(buf, sizeof(buf), "%d:%d ", dev->minor,
453 bdev->subdev);
454 buf[sizeof(buf) - 1] = 0;
455 strncat(devpriv->name, buf, left);
461 if (!devpriv->nchans) {
462 ERROR("No channels found!\n");
463 return 0;
466 return 1;
469 static void doDevUnconfig(struct comedi_device *dev)
471 unsigned long devs_closed = 0;
473 if (devpriv) {
474 while (devpriv->ndevs-- && devpriv->devs) {
475 struct BondedDevice *bdev;
477 bdev = devpriv->devs[devpriv->ndevs];
478 if (!bdev)
479 continue;
480 if (!(devs_closed & (0x1 << bdev->minor))) {
481 comedi_close(bdev->dev);
482 devs_closed |= (0x1 << bdev->minor);
484 kfree(bdev);
486 kfree(devpriv->devs);
487 devpriv->devs = NULL;
488 kfree(devpriv);
489 dev->private = NULL;
493 static int __init init(void)
495 return comedi_driver_register(&driver_bonding);
498 static void __exit cleanup(void)
500 comedi_driver_unregister(&driver_bonding);
503 module_init(init);
504 module_exit(cleanup);