Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
[GitHub/mt8127/android_kernel_alcatel_ttab.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,
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 void *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 void *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);