staging: comedi das08_cs.c: Fix io_req_t conversion
[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
3b6b25b5
GKH
53#include <linux/string.h>
54#include <linux/slab.h>
e2a0eab0 55#include "../comedi.h"
3cf840f6
DS
56#include "../comedilib.h"
57#include "../comedidev.h"
3cf840f6
DS
58
59/* The maxiumum number of channels per subdevice. */
60#define MAX_CHANS 256
61
62#define MODULE_NAME "comedi_bond"
3cf840f6 63MODULE_LICENSE("GPL");
3cf840f6
DS
64#ifndef STR
65# define STR1(x) #x
66# define STR(x) STR1(x)
67#endif
68
246c5418 69static int debug;
3cf840f6 70module_param(debug, int, 0644);
e7f2aa34
GKH
71MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful"
72 "only to developers.");
3cf840f6
DS
73
74#define LOG_MSG(x...) printk(KERN_INFO MODULE_NAME": "x)
e7f2aa34
GKH
75#define DEBUG(x...) \
76 do { \
77 if (debug) \
78 printk(KERN_DEBUG MODULE_NAME": DEBUG: "x); \
79 } while (0)
3cf840f6
DS
80#define WARNING(x...) printk(KERN_WARNING MODULE_NAME ": WARNING: "x)
81#define ERROR(x...) printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x)
82MODULE_AUTHOR("Calin A. Culianu");
e7f2aa34
GKH
83MODULE_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...'");
3cf840f6
DS
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 */
92struct BondingBoard {
93 const char *name;
94};
3cf840f6 95
ff534766 96static const struct BondingBoard bondingBoards[] = {
3cf840f6 97 {
0a85b6f0
MT
98 .name = MODULE_NAME,
99 },
3cf840f6
DS
100};
101
102/*
103 * Useful for shorthand access to the particular board structure
104 */
ff534766 105#define thisboard ((const struct BondingBoard *)dev->board_ptr)
3cf840f6
DS
106
107struct BondedDevice {
472dfe77 108 struct comedi_device *dev;
3cf840f6
DS
109 unsigned minor;
110 unsigned subdev;
111 unsigned subdev_type;
112 unsigned nchans;
e7f2aa34
GKH
113 unsigned chanid_offset; /* The offset into our unified linear
114 channel-id's of chanid 0 on this
115 subdevice. */
3cf840f6 116};
3cf840f6
DS
117
118/* this structure is for data unique to this hardware driver. If
119 several hardware drivers keep similar information in this structure,
71b5f4f1 120 feel free to suggest moving the variable to the struct comedi_device struct. */
3cf840f6
DS
121struct 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};
3cf840f6
DS
129
130/*
131 * most drivers define the following macro to make it easy to
132 * access the private structure.
133 */
ff534766 134#define devpriv ((struct Private *)dev->private)
3cf840f6
DS
135
136/*
139dfbdf 137 * The struct comedi_driver structure tells the Comedi core module
3cf840f6
DS
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 */
0a85b6f0
MT
142static int bonding_attach(struct comedi_device *dev,
143 struct comedi_devconfig *it);
71b5f4f1 144static int bonding_detach(struct comedi_device *dev);
3cf840f6 145/** Build Private array of all devices.. */
0707bb04 146static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it);
71b5f4f1 147static void doDevUnconfig(struct comedi_device *dev);
e7f2aa34
GKH
148/* Ugly implementation of realloc that always copies memory around -- I'm lazy,
149 * what can I say? I like to do wasteful memcopies.. :) */
3cf840f6
DS
150static void *Realloc(const void *ptr, size_t len, size_t old_len);
151
139dfbdf 152static struct comedi_driver driver_bonding = {
0a85b6f0
MT
153 .driver_name = MODULE_NAME,
154 .module = THIS_MODULE,
155 .attach = bonding_attach,
156 .detach = bonding_detach,
3cf840f6
DS
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 */
0a85b6f0
MT
175 .board_name = &bondingBoards[0].name,
176 .offset = sizeof(struct BondingBoard),
177 .num_names = ARRAY_SIZE(bondingBoards),
3cf840f6
DS
178};
179
0a85b6f0
MT
180static int bonding_dio_insn_bits(struct comedi_device *dev,
181 struct comedi_subdevice *s,
90035c08 182 struct comedi_insn *insn, unsigned int *data);
0a85b6f0
MT
183static int bonding_dio_insn_config(struct comedi_device *dev,
184 struct comedi_subdevice *s,
185 struct comedi_insn *insn,
186 unsigned int *data);
3cf840f6
DS
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 */
0a85b6f0
MT
194static int bonding_attach(struct comedi_device *dev,
195 struct comedi_devconfig *it)
3cf840f6 196{
34c43922 197 struct comedi_subdevice *s;
3cf840f6
DS
198
199 LOG_MSG("comedi%d\n", dev->minor);
200
e7f2aa34
GKH
201 /*
202 * Allocate the private structure area. alloc_private() is a
203 * convenient macro defined in comedidev.h.
204 */
ff534766 205 if (alloc_private(dev, sizeof(struct Private)) < 0)
3cf840f6
DS
206 return -ENOMEM;
207
e7f2aa34
GKH
208 /*
209 * Setup our bonding from config params.. sets up our Private struct..
210 */
3cf840f6
DS
211 if (!doDevConfig(dev, it))
212 return -EINVAL;
213
e7f2aa34
GKH
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 */
3cf840f6
DS
218 dev->board_name = devpriv->name;
219
e7f2aa34
GKH
220 /*
221 * Allocate the subdevice structures. alloc_subdevice() is a
222 * convenient macro defined in comedidev.h.
223 */
3cf840f6
DS
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
e7f2aa34
GKH
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);
3cf840f6
DS
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 */
71b5f4f1 252static int bonding_detach(struct comedi_device *dev)
3cf840f6
DS
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 */
0a85b6f0
MT
264static int bonding_dio_insn_bits(struct comedi_device *dev,
265 struct comedi_subdevice *s,
90035c08 266 struct comedi_insn *insn, unsigned int *data)
3cf840f6 267{
790c5541 268#define LSAMPL_BITS (sizeof(unsigned int)*8)
3cf840f6
DS
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) {
ff534766 279 struct BondedDevice *bdev = devpriv->devs[i];
3cf840f6
DS
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. */
e7f2aa34 283 /* Bits corresponding to this subdev. */
790c5541
BP
284 unsigned int subdevMask = ((1 << bdev->nchans) - 1);
285 unsigned int writeMask, dataBits;
3cf840f6
DS
286
287 /* Argh, we have >= LSAMPL_BITS chans.. take all bits */
288 if (bdev->nchans >= LSAMPL_BITS)
0a85b6f0 289 subdevMask = (unsigned int)(-1);
3cf840f6
DS
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,
0a85b6f0 296 &dataBits) != 2)
3cf840f6
DS
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
0a85b6f0
MT
312static int bonding_dio_insn_config(struct comedi_device *dev,
313 struct comedi_subdevice *s,
90035c08 314 struct comedi_insn *insn, unsigned int *data)
3cf840f6
DS
315{
316 int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits;
317 unsigned int io;
ff534766 318 struct BondedDevice *bdev;
3cf840f6
DS
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] =
0a85b6f0 339 (io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
3cf840f6
DS
340 return insn->n;
341 break;
342 default:
343 return -EINVAL;
344 break;
345 }
e7f2aa34
GKH
346 /* 'real' channel id for this subdev.. */
347 chan -= bdev->chanid_offset;
3cf840f6
DS
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
357static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen)
358{
3cf840f6 359 void *newmem = kmalloc(newlen, GFP_KERNEL);
e7f2aa34 360
3cf840f6 361 if (newmem && oldmem)
e7f2aa34
GKH
362 memcpy(newmem, oldmem, min(oldlen, newlen));
363 kfree(oldmem);
3cf840f6
DS
364 return newmem;
365}
366
0707bb04 367static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
3cf840f6
DS
368{
369 int i;
472dfe77 370 struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS];
3cf840f6
DS
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];
472dfe77 379 struct comedi_device *d;
3cf840f6 380 int sdev = -1, nchans, tmp;
246c5418 381 struct BondedDevice *bdev = NULL;
3cf840f6 382
5d3aed74 383 if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) {
3cf840f6
DS
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,
0a85b6f0 408 sdev + 1)) > -1) {
e7f2aa34
GKH
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);
3cf840f6
DS
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
e7f2aa34
GKH
432 /* Now put bdev pointer at end of devpriv->devs array
433 * list.. */
3cf840f6
DS
434
435 /* ergh.. ugly.. we need to realloc :( */
436 tmp = devpriv->ndevs * sizeof(bdev);
437 devpriv->devs =
0a85b6f0
MT
438 Realloc(devpriv->devs,
439 ++devpriv->ndevs * sizeof(bdev), tmp);
3cf840f6 440 if (!devpriv->devs) {
e7f2aa34
GKH
441 ERROR("Could not allocate memory. "
442 "Out of memory?");
3cf840f6
DS
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 =
0a85b6f0 451 MAX_BOARD_NAME - strlen(devpriv->name) - 1;
3cf840f6 452 snprintf(buf, sizeof(buf), "%d:%d ", dev->minor,
0a85b6f0 453 bdev->subdev);
3cf840f6
DS
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
71b5f4f1 469static void doDevUnconfig(struct comedi_device *dev)
3cf840f6
DS
470{
471 unsigned long devs_closed = 0;
472
473 if (devpriv) {
474 while (devpriv->ndevs-- && devpriv->devs) {
ff534766
GKH
475 struct BondedDevice *bdev;
476
477 bdev = devpriv->devs[devpriv->ndevs];
3cf840f6
DS
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 }
e7f2aa34 486 kfree(devpriv->devs);
246c5418 487 devpriv->devs = NULL;
3cf840f6 488 kfree(devpriv);
246c5418 489 dev->private = NULL;
3cf840f6
DS
490 }
491}
492
246c5418 493static int __init init(void)
3cf840f6
DS
494{
495 return comedi_driver_register(&driver_bonding);
496}
497
246c5418 498static void __exit cleanup(void)
3cf840f6
DS
499{
500 comedi_driver_unregister(&driver_bonding);
501}
502
503module_init(init);
504module_exit(cleanup);