Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh...
[pandora-kernel.git] / drivers / staging / comedi / drivers / comedi_bond.c
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 /*
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
32
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.
41
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!
45
46 Commands aren't supported -- although it would be cool if they were.
47
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.
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 struct 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 <linux/string.h>
91 #include <linux/slab.h>
92 #include "../comedi.h"
93 #include "../comedilib.h"
94 #include "../comedidev.h"
95
96 /* The maxiumum number of channels per subdevice. */
97 #define MAX_CHANS 256
98
99 #define MODULE_NAME "comedi_bond"
100 MODULE_LICENSE("GPL");
101 #ifndef STR
102 #  define STR1(x) #x
103 #  define STR(x) STR1(x)
104 #endif
105
106 static int debug;
107 module_param(debug, int, 0644);
108 MODULE_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)
119 MODULE_AUTHOR("Calin A. Culianu");
120 MODULE_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  */
129 struct BondingBoard {
130         const char *name;
131 };
132
133 static 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
144 struct BondedDevice {
145         struct comedi_device *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 struct comedi_device struct.  */
158 struct 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 struct 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  */
179 static int bonding_attach(struct comedi_device *dev,
180                           struct comedi_devconfig *it);
181 static int bonding_detach(struct comedi_device *dev);
182 /** Build Private array of all devices.. */
183 static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it);
184 static void doDevUnconfig(struct comedi_device *dev);
185 /* Ugly implementation of realloc that always copies memory around -- I'm lazy,
186  * what can I say?  I like to do wasteful memcopies.. :) */
187 static void *Realloc(const void *ptr, size_t len, size_t old_len);
188
189 static struct comedi_driver driver_bonding = {
190         .driver_name = MODULE_NAME,
191         .module = THIS_MODULE,
192         .attach = bonding_attach,
193         .detach = bonding_detach,
194         /* It is not necessary to implement the following members if you are
195          * writing a driver for a ISA PnP or PCI card */
196         /* Most drivers will support multiple types of boards by
197          * having an array of board structures.  These were defined
198          * in skel_boards[] above.  Note that the element 'name'
199          * was first in the structure -- Comedi uses this fact to
200          * extract the name of the board without knowing any details
201          * about the structure except for its length.
202          * When a device is attached (by comedi_config), the name
203          * of the device is given to Comedi, and Comedi tries to
204          * match it by going through the list of board names.  If
205          * there is a match, the address of the pointer is put
206          * into dev->board_ptr and driver->attach() is called.
207          *
208          * Note that these are not necessary if you can determine
209          * the type of board in software.  ISA PnP, PCI, and PCMCIA
210          * devices are such boards.
211          */
212         .board_name = &bondingBoards[0].name,
213         .offset = sizeof(struct BondingBoard),
214         .num_names = ARRAY_SIZE(bondingBoards),
215 };
216
217 static int bonding_dio_insn_bits(struct comedi_device *dev,
218                                  struct comedi_subdevice *s,
219                                  struct comedi_insn *insn, unsigned int *data);
220 static int bonding_dio_insn_config(struct comedi_device *dev,
221                                    struct comedi_subdevice *s,
222                                    struct comedi_insn *insn,
223                                    unsigned int *data);
224
225 /*
226  * Attach is called by the Comedi core to configure the driver
227  * for a particular board.  If you specified a board_name array
228  * in the driver structure, dev->board_ptr contains that
229  * address.
230  */
231 static int bonding_attach(struct comedi_device *dev,
232                           struct comedi_devconfig *it)
233 {
234         struct comedi_subdevice *s;
235
236         LOG_MSG("comedi%d\n", dev->minor);
237
238         /*
239          * Allocate the private structure area.  alloc_private() is a
240          * convenient macro defined in comedidev.h.
241          */
242         if (alloc_private(dev, sizeof(struct Private)) < 0)
243                 return -ENOMEM;
244
245         /*
246          * Setup our bonding from config params.. sets up our Private struct..
247          */
248         if (!doDevConfig(dev, it))
249                 return -EINVAL;
250
251         /*
252          * Initialize dev->board_name.  Note that we can use the "thisboard"
253          * macro now, since we just initialized it in the last line.
254          */
255         dev->board_name = devpriv->name;
256
257         /*
258          * Allocate the subdevice structures.  alloc_subdevice() is a
259          * convenient macro defined in comedidev.h.
260          */
261         if (alloc_subdevices(dev, 1) < 0)
262                 return -ENOMEM;
263
264         s = dev->subdevices + 0;
265         s->type = COMEDI_SUBD_DIO;
266         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
267         s->n_chan = devpriv->nchans;
268         s->maxdata = 1;
269         s->range_table = &range_digital;
270         s->insn_bits = bonding_dio_insn_bits;
271         s->insn_config = bonding_dio_insn_config;
272
273         LOG_MSG("attached with %u DIO channels coming from %u different "
274                 "subdevices all bonded together.  "
275                 "John Lennon would be proud!\n",
276                 devpriv->nchans, devpriv->ndevs);
277
278         return 1;
279 }
280
281 /*
282  * _detach is called to deconfigure a device.  It should deallocate
283  * resources.
284  * This function is also called when _attach() fails, so it should be
285  * careful not to release resources that were not necessarily
286  * allocated by _attach().  dev->private and dev->subdevices are
287  * deallocated automatically by the core.
288  */
289 static int bonding_detach(struct comedi_device *dev)
290 {
291         LOG_MSG("comedi%d: remove\n", dev->minor);
292         doDevUnconfig(dev);
293         return 0;
294 }
295
296 /* DIO devices are slightly special.  Although it is possible to
297  * implement the insn_read/insn_write interface, it is much more
298  * useful to applications if you implement the insn_bits interface.
299  * This allows packed reading/writing of the DIO channels.  The
300  * comedi core can convert between insn_bits and insn_read/write */
301 static int bonding_dio_insn_bits(struct comedi_device *dev,
302                                  struct comedi_subdevice *s,
303                                  struct comedi_insn *insn, unsigned int *data)
304 {
305 #define LSAMPL_BITS (sizeof(unsigned int)*8)
306         unsigned nchans = LSAMPL_BITS, num_done = 0, i;
307         if (insn->n != 2)
308                 return -EINVAL;
309
310         if (devpriv->nchans < nchans)
311                 nchans = devpriv->nchans;
312
313         /* The insn data is a mask in data[0] and the new data
314          * in data[1], each channel cooresponding to a bit. */
315         for (i = 0; num_done < nchans && i < devpriv->ndevs; ++i) {
316                 struct BondedDevice *bdev = devpriv->devs[i];
317                 /* Grab the channel mask and data of only the bits corresponding
318                    to this subdevice.. need to shift them to zero position of
319                    course. */
320                 /* Bits corresponding to this subdev. */
321                 unsigned int subdevMask = ((1 << bdev->nchans) - 1);
322                 unsigned int writeMask, dataBits;
323
324                 /* Argh, we have >= LSAMPL_BITS chans.. take all bits */
325                 if (bdev->nchans >= LSAMPL_BITS)
326                         subdevMask = (unsigned int)(-1);
327
328                 writeMask = (data[0] >> num_done) & subdevMask;
329                 dataBits = (data[1] >> num_done) & subdevMask;
330
331                 /* Read/Write the new digital lines */
332                 if (comedi_dio_bitfield(bdev->dev, bdev->subdev, writeMask,
333                                         &dataBits) != 2)
334                         return -EINVAL;
335
336                 /* Make room for the new bits in data[1], the return value */
337                 data[1] &= ~(subdevMask << num_done);
338                 /* Put the bits in the return value */
339                 data[1] |= (dataBits & subdevMask) << num_done;
340                 /* Save the new bits to the saved state.. */
341                 s->state = data[1];
342
343                 num_done += bdev->nchans;
344         }
345
346         return insn->n;
347 }
348
349 static int bonding_dio_insn_config(struct comedi_device *dev,
350                                    struct comedi_subdevice *s,
351                                    struct comedi_insn *insn, unsigned int *data)
352 {
353         int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits;
354         unsigned int io;
355         struct BondedDevice *bdev;
356
357         if (chan < 0 || chan >= devpriv->nchans)
358                 return -EINVAL;
359         bdev = devpriv->chanIdDevMap[chan];
360
361         /* The input or output configuration of each digital line is
362          * configured by a special insn_config instruction.  chanspec
363          * contains the channel to be changed, and data[0] contains the
364          * value COMEDI_INPUT or COMEDI_OUTPUT. */
365         switch (data[0]) {
366         case INSN_CONFIG_DIO_OUTPUT:
367                 io = COMEDI_OUTPUT;     /* is this really necessary? */
368                 io_bits |= 1 << chan;
369                 break;
370         case INSN_CONFIG_DIO_INPUT:
371                 io = COMEDI_INPUT;      /* is this really necessary? */
372                 io_bits &= ~(1 << chan);
373                 break;
374         case INSN_CONFIG_DIO_QUERY:
375                 data[1] =
376                     (io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
377                 return insn->n;
378                 break;
379         default:
380                 return -EINVAL;
381                 break;
382         }
383         /* 'real' channel id for this subdev.. */
384         chan -= bdev->chanid_offset;
385         ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, io);
386         if (ret != 1)
387                 return -EINVAL;
388         /* Finally, save the new io_bits values since we didn't get
389            an error above. */
390         s->io_bits = io_bits;
391         return insn->n;
392 }
393
394 static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen)
395 {
396         void *newmem = kmalloc(newlen, GFP_KERNEL);
397
398         if (newmem && oldmem)
399                 memcpy(newmem, oldmem, min(oldlen, newlen));
400         kfree(oldmem);
401         return newmem;
402 }
403
404 static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
405 {
406         int i;
407         struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS];
408
409         memset(devs_opened, 0, sizeof(devs_opened));
410         devpriv->name[0] = 0;;
411         /* Loop through all comedi devices specified on the command-line,
412            building our device list */
413         for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) {
414                 char file[] = "/dev/comediXXXXXX";
415                 int minor = it->options[i];
416                 struct comedi_device *d;
417                 int sdev = -1, nchans, tmp;
418                 struct BondedDevice *bdev = NULL;
419
420                 if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) {
421                         ERROR("Minor %d is invalid!\n", minor);
422                         return 0;
423                 }
424                 if (minor == dev->minor) {
425                         ERROR("Cannot bond this driver to itself!\n");
426                         return 0;
427                 }
428                 if (devs_opened[minor]) {
429                         ERROR("Minor %d specified more than once!\n", minor);
430                         return 0;
431                 }
432
433                 snprintf(file, sizeof(file), "/dev/comedi%u", minor);
434                 file[sizeof(file) - 1] = 0;
435
436                 d = devs_opened[minor] = comedi_open(file);
437
438                 if (!d) {
439                         ERROR("Minor %u could not be opened\n", minor);
440                         return 0;
441                 }
442
443                 /* Do DIO, as that's all we support now.. */
444                 while ((sdev = comedi_find_subdevice_by_type(d, COMEDI_SUBD_DIO,
445                                                              sdev + 1)) > -1) {
446                         nchans = comedi_get_n_channels(d, sdev);
447                         if (nchans <= 0) {
448                                 ERROR("comedi_get_n_channels() returned %d "
449                                       "on minor %u subdev %d!\n",
450                                       nchans, minor, sdev);
451                                 return 0;
452                         }
453                         bdev = kmalloc(sizeof(*bdev), GFP_KERNEL);
454                         if (!bdev) {
455                                 ERROR("Out of memory.\n");
456                                 return 0;
457                         }
458                         bdev->dev = d;
459                         bdev->minor = minor;
460                         bdev->subdev = sdev;
461                         bdev->subdev_type = COMEDI_SUBD_DIO;
462                         bdev->nchans = nchans;
463                         bdev->chanid_offset = devpriv->nchans;
464
465                         /* map channel id's to BondedDevice * pointer.. */
466                         while (nchans--)
467                                 devpriv->chanIdDevMap[devpriv->nchans++] = bdev;
468
469                         /* Now put bdev pointer at end of devpriv->devs array
470                          * list.. */
471
472                         /* ergh.. ugly.. we need to realloc :(  */
473                         tmp = devpriv->ndevs * sizeof(bdev);
474                         devpriv->devs =
475                             Realloc(devpriv->devs,
476                                     ++devpriv->ndevs * sizeof(bdev), tmp);
477                         if (!devpriv->devs) {
478                                 ERROR("Could not allocate memory. "
479                                       "Out of memory?");
480                                 return 0;
481                         }
482
483                         devpriv->devs[devpriv->ndevs - 1] = bdev;
484                         {
485         /** Append dev:subdev to devpriv->name */
486                                 char buf[20];
487                                 int left =
488                                     MAX_BOARD_NAME - strlen(devpriv->name) - 1;
489                                 snprintf(buf, sizeof(buf), "%d:%d ", dev->minor,
490                                          bdev->subdev);
491                                 buf[sizeof(buf) - 1] = 0;
492                                 strncat(devpriv->name, buf, left);
493                         }
494
495                 }
496         }
497
498         if (!devpriv->nchans) {
499                 ERROR("No channels found!\n");
500                 return 0;
501         }
502
503         return 1;
504 }
505
506 static void doDevUnconfig(struct comedi_device *dev)
507 {
508         unsigned long devs_closed = 0;
509
510         if (devpriv) {
511                 while (devpriv->ndevs-- && devpriv->devs) {
512                         struct BondedDevice *bdev;
513
514                         bdev = devpriv->devs[devpriv->ndevs];
515                         if (!bdev)
516                                 continue;
517                         if (!(devs_closed & (0x1 << bdev->minor))) {
518                                 comedi_close(bdev->dev);
519                                 devs_closed |= (0x1 << bdev->minor);
520                         }
521                         kfree(bdev);
522                 }
523                 kfree(devpriv->devs);
524                 devpriv->devs = NULL;
525                 kfree(devpriv);
526                 dev->private = NULL;
527         }
528 }
529
530 static int __init init(void)
531 {
532         return comedi_driver_register(&driver_bonding);
533 }
534
535 static void __exit cleanup(void)
536 {
537         comedi_driver_unregister(&driver_bonding);
538 }
539
540 module_init(init);
541 module_exit(cleanup);