Merge branch 'fix/asoc' into for-linus
[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 "../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
99 MODULE_LICENSE("GPL");
100 #endif
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         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 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, struct comedi_devconfig *it);
180 static int bonding_detach(struct comedi_device *dev);
181 /** Build Private array of all devices.. */
182 static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it);
183 static void doDevUnconfig(struct 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.. :) */
186 static void *Realloc(const void *ptr, size_t len, size_t old_len);
187
188 static struct 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
216 static int bonding_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
217                                  struct comedi_insn *insn, unsigned int *data);
218 static int bonding_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
219                                    struct 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  */
227 static int bonding_attach(struct comedi_device *dev, struct comedi_devconfig *it)
228 {
229         struct 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  */
284 static int bonding_detach(struct 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 */
296 static int bonding_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
297                                  struct 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
343 static int bonding_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
344                                    struct 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
387 static 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
397 static int doDevConfig(struct comedi_device *dev, struct 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
500 static void doDevUnconfig(struct 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
524 static int __init init(void)
525 {
526         return comedi_driver_register(&driver_bonding);
527 }
528
529 static void __exit cleanup(void)
530 {
531         comedi_driver_unregister(&driver_bonding);
532 }
533
534 module_init(init);
535 module_exit(cleanup);