Merge branch 'master' into next
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / comedi / drivers / comedi_bond.c
CommitLineData
3cf840f6
DS
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/*
25Driver: comedi_bond
e7f2aa34
GKH
26Description: A driver to 'bond' (merge) multiple subdevices from multiple
27 devices together as one.
3cf840f6
DS
28Devices:
29Author: ds
30Updated: Mon, 10 Oct 00:18:25 -0500
31Status: works
32
33This driver allows you to 'bond' (merge) multiple comedi subdevices
34(coming from possibly difference boards and/or drivers) together. For
35example, if you had a board with 2 different DIO subdevices, and
36another with 1 DIO subdevice, you could 'bond' them with this driver
37so that they look like one big fat DIO subdevice. This makes writing
38applications slightly easier as you don't have to worry about managing
39different subdevices in the application -- you just worry about
40indexing one linear array of channel id's.
41
42Right now only DIO subdevices are supported as that's the personal itch
43I am scratching with this driver. If you want to add support for AI and AO
44subdevs, go right on ahead and do so!
45
46Commands aren't supported -- although it would be cool if they were.
47
48Configuration 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.
139dfbdf 62 * See the comment near board_name: in the struct comedi_driver structure
3cf840f6
DS
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
99MODULE_LICENSE("GPL");
100#endif
101#ifndef STR
102# define STR1(x) #x
103# define STR(x) STR1(x)
104#endif
105
246c5418 106static int debug;
3cf840f6 107module_param(debug, int, 0644);
e7f2aa34
GKH
108MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful"
109 "only to developers.");
3cf840f6
DS
110
111#define LOG_MSG(x...) printk(KERN_INFO MODULE_NAME": "x)
e7f2aa34
GKH
112#define DEBUG(x...) \
113 do { \
114 if (debug) \
115 printk(KERN_DEBUG MODULE_NAME": DEBUG: "x); \
116 } while (0)
3cf840f6
DS
117#define WARNING(x...) printk(KERN_WARNING MODULE_NAME ": WARNING: "x)
118#define ERROR(x...) printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x)
119MODULE_AUTHOR("Calin A. Culianu");
e7f2aa34
GKH
120MODULE_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...'");
3cf840f6
DS
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 */
129struct BondingBoard {
130 const char *name;
131};
3cf840f6 132
ff534766 133static const struct BondingBoard bondingBoards[] = {
3cf840f6 134 {
e7f2aa34
GKH
135 .name = MODULE_NAME,
136 },
3cf840f6
DS
137};
138
139/*
140 * Useful for shorthand access to the particular board structure
141 */
ff534766 142#define thisboard ((const struct BondingBoard *)dev->board_ptr)
3cf840f6
DS
143
144struct BondedDevice {
0b3fb27f 145 void *dev;
3cf840f6
DS
146 unsigned minor;
147 unsigned subdev;
148 unsigned subdev_type;
149 unsigned nchans;
e7f2aa34
GKH
150 unsigned chanid_offset; /* The offset into our unified linear
151 channel-id's of chanid 0 on this
152 subdevice. */
3cf840f6 153};
3cf840f6
DS
154
155/* this structure is for data unique to this hardware driver. If
156 several hardware drivers keep similar information in this structure,
71b5f4f1 157 feel free to suggest moving the variable to the struct comedi_device struct. */
3cf840f6
DS
158struct 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};
3cf840f6
DS
166
167/*
168 * most drivers define the following macro to make it easy to
169 * access the private structure.
170 */
ff534766 171#define devpriv ((struct Private *)dev->private)
3cf840f6
DS
172
173/*
139dfbdf 174 * The struct comedi_driver structure tells the Comedi core module
3cf840f6
DS
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 */
0707bb04 179static int bonding_attach(struct comedi_device *dev, struct comedi_devconfig *it);
71b5f4f1 180static int bonding_detach(struct comedi_device *dev);
3cf840f6 181/** Build Private array of all devices.. */
0707bb04 182static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it);
71b5f4f1 183static void doDevUnconfig(struct comedi_device *dev);
e7f2aa34
GKH
184/* Ugly implementation of realloc that always copies memory around -- I'm lazy,
185 * what can I say? I like to do wasteful memcopies.. :) */
3cf840f6
DS
186static void *Realloc(const void *ptr, size_t len, size_t old_len);
187
139dfbdf 188static struct comedi_driver driver_bonding = {
e7f2aa34
GKH
189 .driver_name = MODULE_NAME,
190 .module = THIS_MODULE,
191 .attach = bonding_attach,
192 .detach = bonding_detach,
3cf840f6
DS
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 */
e7f2aa34 211 .board_name = &bondingBoards[0].name,
ff534766
GKH
212 .offset = sizeof(struct BondingBoard),
213 .num_names = sizeof(bondingBoards) / sizeof(struct BondingBoard),
3cf840f6
DS
214};
215
34c43922 216static int bonding_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
90035c08 217 struct comedi_insn *insn, unsigned int *data);
34c43922 218static int bonding_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
90035c08 219 struct comedi_insn *insn, unsigned int *data);
3cf840f6
DS
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 */
0707bb04 227static int bonding_attach(struct comedi_device *dev, struct comedi_devconfig *it)
3cf840f6 228{
34c43922 229 struct comedi_subdevice *s;
3cf840f6
DS
230
231 LOG_MSG("comedi%d\n", dev->minor);
232
e7f2aa34
GKH
233 /*
234 * Allocate the private structure area. alloc_private() is a
235 * convenient macro defined in comedidev.h.
236 */
ff534766 237 if (alloc_private(dev, sizeof(struct Private)) < 0)
3cf840f6
DS
238 return -ENOMEM;
239
e7f2aa34
GKH
240 /*
241 * Setup our bonding from config params.. sets up our Private struct..
242 */
3cf840f6
DS
243 if (!doDevConfig(dev, it))
244 return -EINVAL;
245
e7f2aa34
GKH
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 */
3cf840f6
DS
250 dev->board_name = devpriv->name;
251
e7f2aa34
GKH
252 /*
253 * Allocate the subdevice structures. alloc_subdevice() is a
254 * convenient macro defined in comedidev.h.
255 */
3cf840f6
DS
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
e7f2aa34
GKH
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);
3cf840f6
DS
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 */
71b5f4f1 284static int bonding_detach(struct comedi_device *dev)
3cf840f6
DS
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 */
34c43922 296static int bonding_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
90035c08 297 struct comedi_insn *insn, unsigned int *data)
3cf840f6 298{
790c5541 299#define LSAMPL_BITS (sizeof(unsigned int)*8)
3cf840f6
DS
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) {
ff534766 310 struct BondedDevice *bdev = devpriv->devs[i];
3cf840f6
DS
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. */
e7f2aa34 314 /* Bits corresponding to this subdev. */
790c5541
BP
315 unsigned int subdevMask = ((1 << bdev->nchans) - 1);
316 unsigned int writeMask, dataBits;
3cf840f6
DS
317
318 /* Argh, we have >= LSAMPL_BITS chans.. take all bits */
319 if (bdev->nchans >= LSAMPL_BITS)
790c5541 320 subdevMask = (unsigned int) (-1);
3cf840f6
DS
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
34c43922 343static int bonding_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
90035c08 344 struct comedi_insn *insn, unsigned int *data)
3cf840f6
DS
345{
346 int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits;
347 unsigned int io;
ff534766 348 struct BondedDevice *bdev;
3cf840f6
DS
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 }
e7f2aa34
GKH
376 /* 'real' channel id for this subdev.. */
377 chan -= bdev->chanid_offset;
3cf840f6
DS
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
387static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen)
388{
3cf840f6 389 void *newmem = kmalloc(newlen, GFP_KERNEL);
e7f2aa34 390
3cf840f6 391 if (newmem && oldmem)
e7f2aa34
GKH
392 memcpy(newmem, oldmem, min(oldlen, newlen));
393 kfree(oldmem);
3cf840f6
DS
394 return newmem;
395}
396
0707bb04 397static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
3cf840f6
DS
398{
399 int i;
0b3fb27f 400 void *devs_opened[COMEDI_NUM_BOARD_MINORS];
3cf840f6
DS
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];
0b3fb27f 409 void *d;
3cf840f6 410 int sdev = -1, nchans, tmp;
246c5418 411 struct BondedDevice *bdev = NULL;
3cf840f6
DS
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) {
e7f2aa34
GKH
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);
3cf840f6
DS
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
e7f2aa34
GKH
462 /* Now put bdev pointer at end of devpriv->devs array
463 * list.. */
3cf840f6
DS
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) {
e7f2aa34
GKH
471 ERROR("Could not allocate memory. "
472 "Out of memory?");
3cf840f6
DS
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
71b5f4f1 500static void doDevUnconfig(struct comedi_device *dev)
3cf840f6
DS
501{
502 unsigned long devs_closed = 0;
503
504 if (devpriv) {
505 while (devpriv->ndevs-- && devpriv->devs) {
ff534766
GKH
506 struct BondedDevice *bdev;
507
508 bdev = devpriv->devs[devpriv->ndevs];
3cf840f6
DS
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 }
e7f2aa34 517 kfree(devpriv->devs);
246c5418 518 devpriv->devs = NULL;
3cf840f6 519 kfree(devpriv);
246c5418 520 dev->private = NULL;
3cf840f6
DS
521 }
522}
523
246c5418 524static int __init init(void)
3cf840f6
DS
525{
526 return comedi_driver_register(&driver_bonding);
527}
528
246c5418 529static void __exit cleanup(void)
3cf840f6
DS
530{
531 comedi_driver_unregister(&driver_bonding);
532}
533
534module_init(init);
535module_exit(cleanup);