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