Merge branch 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[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 #include <linux/string.h>
54 #include <linux/slab.h>
55 #include "../comedi.h"
56 #include "../comedilib.h"
57 #include "../comedidev.h"
58
59 /* The maxiumum number of channels per subdevice. */
60 #define MAX_CHANS 256
61
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
68
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.");
73
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...'");
86
87 /*
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.
91  */
92 struct BondingBoard {
93         const char *name;
94 };
95
96 static const struct BondingBoard bondingBoards[] = {
97         {
98          .name = MODULE_NAME,
99          },
100 };
101
102 /*
103  * Useful for shorthand access to the particular board structure
104  */
105 #define thisboard ((const struct BondingBoard *)dev->board_ptr)
106
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. */
116 };
117
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;
128 };
129
130 /*
131  * most drivers define the following macro to make it easy to
132  * access the private structure.
133  */
134 #define devpriv ((struct Private *)dev->private)
135
136 /*
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.
141  */
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);
151
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.
170          *
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.
174          */
175         .board_name = &bondingBoards[0].name,
176         .offset = sizeof(struct BondingBoard),
177         .num_names = ARRAY_SIZE(bondingBoards),
178 };
179
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);
187
188 /*
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.
193  */
194 static int bonding_attach(struct comedi_device *dev,
195                           struct comedi_devconfig *it)
196 {
197         struct comedi_subdevice *s;
198
199         LOG_MSG("comedi%d\n", dev->minor);
200
201         /*
202          * Allocate the private structure area.  alloc_private() is a
203          * convenient macro defined in comedidev.h.
204          */
205         if (alloc_private(dev, sizeof(struct Private)) < 0)
206                 return -ENOMEM;
207
208         /*
209          * Setup our bonding from config params.. sets up our Private struct..
210          */
211         if (!doDevConfig(dev, it))
212                 return -EINVAL;
213
214         /*
215          * Initialize dev->board_name.  Note that we can use the "thisboard"
216          * macro now, since we just initialized it in the last line.
217          */
218         dev->board_name = devpriv->name;
219
220         /*
221          * Allocate the subdevice structures.  alloc_subdevice() is a
222          * convenient macro defined in comedidev.h.
223          */
224         if (alloc_subdevices(dev, 1) < 0)
225                 return -ENOMEM;
226
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;
235
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);
240
241         return 1;
242 }
243
244 /*
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.
251  */
252 static int bonding_detach(struct comedi_device *dev)
253 {
254         LOG_MSG("comedi%d: remove\n", dev->minor);
255         doDevUnconfig(dev);
256         return 0;
257 }
258
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)
267 {
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;
272
273         if (devpriv->nchans < nchans)
274                 nchans = devpriv->nchans;
275
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;
286
287                 /* Argh, we have >= LSAMPL_BITS chans.. take all bits */
288                 if (bdev->nchans >= LSAMPL_BITS)
289                         subdevMask = (unsigned int)(-1);
290
291                 writeMask = (data[0] >> num_done) & subdevMask;
292                 dataBits = (data[1] >> num_done) & subdevMask;
293
294                 /* Read/Write the new digital lines */
295                 if (comedi_dio_bitfield(bdev->dev, bdev->subdev, writeMask,
296                                         &dataBits) != 2)
297                         return -EINVAL;
298
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];
305
306                 num_done += bdev->nchans;
307         }
308
309         return insn->n;
310 }
311
312 static int bonding_dio_insn_config(struct comedi_device *dev,
313                                    struct comedi_subdevice *s,
314                                    struct comedi_insn *insn, unsigned int *data)
315 {
316         int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits;
317         unsigned int io;
318         struct BondedDevice *bdev;
319
320         if (chan < 0 || chan >= devpriv->nchans)
321                 return -EINVAL;
322         bdev = devpriv->chanIdDevMap[chan];
323
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;
345         }
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;
355 }
356
357 static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen)
358 {
359         void *newmem = kmalloc(newlen, GFP_KERNEL);
360
361         if (newmem && oldmem)
362                 memcpy(newmem, oldmem, min(oldlen, newlen));
363         kfree(oldmem);
364         return newmem;
365 }
366
367 static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
368 {
369         int i;
370         struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS];
371
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;
382
383                 if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) {
384                         ERROR("Minor %d is invalid!\n", minor);
385                         return 0;
386                 }
387                 if (minor == dev->minor) {
388                         ERROR("Cannot bond this driver to itself!\n");
389                         return 0;
390                 }
391                 if (devs_opened[minor]) {
392                         ERROR("Minor %d specified more than once!\n", minor);
393                         return 0;
394                 }
395
396                 snprintf(file, sizeof(file), "/dev/comedi%u", minor);
397                 file[sizeof(file) - 1] = 0;
398
399                 d = devs_opened[minor] = comedi_open(file);
400
401                 if (!d) {
402                         ERROR("Minor %u could not be opened\n", minor);
403                         return 0;
404                 }
405
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;
415                         }
416                         bdev = kmalloc(sizeof(*bdev), GFP_KERNEL);
417                         if (!bdev) {
418                                 ERROR("Out of memory.\n");
419                                 return 0;
420                         }
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;
427
428                         /* map channel id's to BondedDevice * pointer.. */
429                         while (nchans--)
430                                 devpriv->chanIdDevMap[devpriv->nchans++] = bdev;
431
432                         /* Now put bdev pointer at end of devpriv->devs array
433                          * list.. */
434
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;
444                         }
445
446                         devpriv->devs[devpriv->ndevs - 1] = bdev;
447                         {
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);
456                         }
457
458                 }
459         }
460
461         if (!devpriv->nchans) {
462                 ERROR("No channels found!\n");
463                 return 0;
464         }
465
466         return 1;
467 }
468
469 static void doDevUnconfig(struct comedi_device *dev)
470 {
471         unsigned long devs_closed = 0;
472
473         if (devpriv) {
474                 while (devpriv->ndevs-- && devpriv->devs) {
475                         struct BondedDevice *bdev;
476
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);
483                         }
484                         kfree(bdev);
485                 }
486                 kfree(devpriv->devs);
487                 devpriv->devs = NULL;
488                 kfree(devpriv);
489                 dev->private = NULL;
490         }
491 }
492
493 static int __init init(void)
494 {
495         return comedi_driver_register(&driver_bonding);
496 }
497
498 static void __exit cleanup(void)
499 {
500         comedi_driver_unregister(&driver_bonding);
501 }
502
503 module_init(init);
504 module_exit(cleanup);