summaryrefslogtreecommitdiff
path: root/drivers/staging/comedi/drivers/comedi_bond.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/drivers/comedi_bond.c')
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c347
1 files changed, 0 insertions, 347 deletions
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
deleted file mode 100644
index 4392b5927a99..000000000000
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ /dev/null
@@ -1,347 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * comedi_bond.c
- * A Comedi driver to 'bond' or merge multiple drivers and devices as one.
- *
- * COMEDI - Linux Control and Measurement Device Interface
- * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
- * Copyright (C) 2005 Calin A. Culianu <calin@ajvar.org>
- */
-
-/*
- * Driver: comedi_bond
- * Description: A driver to 'bond' (merge) multiple subdevices from multiple
- * devices together as one.
- * Devices:
- * Author: ds
- * Updated: Mon, 10 Oct 00:18:25 -0500
- * Status: works
- *
- * This driver allows you to 'bond' (merge) multiple comedi subdevices
- * (coming from possibly difference boards and/or drivers) together. For
- * example, if you had a board with 2 different DIO subdevices, and
- * another with 1 DIO subdevice, you could 'bond' them with this driver
- * so that they look like one big fat DIO subdevice. This makes writing
- * applications slightly easier as you don't have to worry about managing
- * different subdevices in the application -- you just worry about
- * indexing one linear array of channel id's.
- *
- * Right now only DIO subdevices are supported as that's the personal itch
- * I am scratching with this driver. If you want to add support for AI and AO
- * subdevs, go right on ahead and do so!
- *
- * Commands aren't supported -- although it would be cool if they were.
- *
- * Configuration Options:
- * List of comedi-minors to bond. All subdevices of the same type
- * within each minor will be concatenated together in the order given here.
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "../comedi.h"
-#include "../comedilib.h"
-#include "../comedidev.h"
-
-struct bonded_device {
- struct comedi_device *dev;
- unsigned int minor;
- unsigned int subdev;
- unsigned int nchans;
-};
-
-struct comedi_bond_private {
- char name[256];
- struct bonded_device **devs;
- unsigned int ndevs;
- unsigned int nchans;
-};
-
-static int bonding_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct comedi_bond_private *devpriv = dev->private;
- unsigned int n_left, n_done, base_chan;
- unsigned int write_mask, data_bits;
- struct bonded_device **devs;
-
- write_mask = data[0];
- data_bits = data[1];
- base_chan = CR_CHAN(insn->chanspec);
- /* do a maximum of 32 channels, starting from base_chan. */
- n_left = devpriv->nchans - base_chan;
- if (n_left > 32)
- n_left = 32;
-
- n_done = 0;
- devs = devpriv->devs;
- do {
- struct bonded_device *bdev = *devs++;
-
- if (base_chan < bdev->nchans) {
- /* base channel falls within bonded device */
- unsigned int b_chans, b_mask, b_write_mask, b_data_bits;
- int ret;
-
- /*
- * Get num channels to do for bonded device and set
- * up mask and data bits for bonded device.
- */
- b_chans = bdev->nchans - base_chan;
- if (b_chans > n_left)
- b_chans = n_left;
- b_mask = (b_chans < 32) ? ((1 << b_chans) - 1)
- : 0xffffffff;
- b_write_mask = (write_mask >> n_done) & b_mask;
- b_data_bits = (data_bits >> n_done) & b_mask;
- /* Read/Write the new digital lines. */
- ret = comedi_dio_bitfield2(bdev->dev, bdev->subdev,
- b_write_mask, &b_data_bits,
- base_chan);
- if (ret < 0)
- return ret;
- /* Place read bits into data[1]. */
- data[1] &= ~(b_mask << n_done);
- data[1] |= (b_data_bits & b_mask) << n_done;
- /*
- * Set up for following bonded device (if still have
- * channels to read/write).
- */
- base_chan = 0;
- n_done += b_chans;
- n_left -= b_chans;
- } else {
- /* Skip bonded devices before base channel. */
- base_chan -= bdev->nchans;
- }
- } while (n_left);
-
- return insn->n;
-}
-
-static int bonding_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct comedi_bond_private *devpriv = dev->private;
- unsigned int chan = CR_CHAN(insn->chanspec);
- int ret;
- struct bonded_device *bdev;
- struct bonded_device **devs;
-
- /*
- * Locate bonded subdevice and adjust channel.
- */
- devs = devpriv->devs;
- for (bdev = *devs++; chan >= bdev->nchans; bdev = *devs++)
- chan -= bdev->nchans;
-
- /*
- * The input or output configuration of each digital line is
- * configured by a special insn_config instruction. chanspec
- * contains the channel to be changed, and data[0] contains the
- * configuration instruction INSN_CONFIG_DIO_OUTPUT,
- * INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_QUERY.
- *
- * Note that INSN_CONFIG_DIO_OUTPUT == COMEDI_OUTPUT,
- * and INSN_CONFIG_DIO_INPUT == COMEDI_INPUT. This is deliberate ;)
- */
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- case INSN_CONFIG_DIO_INPUT:
- ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, data[0]);
- break;
- case INSN_CONFIG_DIO_QUERY:
- ret = comedi_dio_get_config(bdev->dev, bdev->subdev, chan,
- &data[1]);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret >= 0)
- ret = insn->n;
- return ret;
-}
-
-static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_bond_private *devpriv = dev->private;
- DECLARE_BITMAP(devs_opened, COMEDI_NUM_BOARD_MINORS);
- int i;
-
- memset(&devs_opened, 0, sizeof(devs_opened));
- devpriv->name[0] = 0;
- /*
- * Loop through all comedi devices specified on the command-line,
- * building our device list.
- */
- for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) {
- char file[sizeof("/dev/comediXXXXXX")];
- int minor = it->options[i];
- struct comedi_device *d;
- int sdev = -1, nchans;
- struct bonded_device *bdev;
- struct bonded_device **devs;
-
- if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) {
- dev_err(dev->class_dev,
- "Minor %d is invalid!\n", minor);
- return -EINVAL;
- }
- if (minor == dev->minor) {
- dev_err(dev->class_dev,
- "Cannot bond this driver to itself!\n");
- return -EINVAL;
- }
- if (test_and_set_bit(minor, devs_opened)) {
- dev_err(dev->class_dev,
- "Minor %d specified more than once!\n", minor);
- return -EINVAL;
- }
-
- snprintf(file, sizeof(file), "/dev/comedi%d", minor);
- file[sizeof(file) - 1] = 0;
-
- d = comedi_open(file);
-
- if (!d) {
- dev_err(dev->class_dev,
- "Minor %u could not be opened\n", minor);
- return -ENODEV;
- }
-
- /* Do DIO, as that's all we support now.. */
- while ((sdev = comedi_find_subdevice_by_type(d, COMEDI_SUBD_DIO,
- sdev + 1)) > -1) {
- nchans = comedi_get_n_channels(d, sdev);
- if (nchans <= 0) {
- dev_err(dev->class_dev,
- "comedi_get_n_channels() returned %d on minor %u subdev %d!\n",
- nchans, minor, sdev);
- return -EINVAL;
- }
- bdev = kmalloc(sizeof(*bdev), GFP_KERNEL);
- if (!bdev)
- return -ENOMEM;
-
- bdev->dev = d;
- bdev->minor = minor;
- bdev->subdev = sdev;
- bdev->nchans = nchans;
- devpriv->nchans += nchans;
-
- /*
- * Now put bdev pointer at end of devpriv->devs array
- * list..
- */
-
- /* ergh.. ugly.. we need to realloc :( */
- devs = krealloc(devpriv->devs,
- (devpriv->ndevs + 1) * sizeof(*devs),
- GFP_KERNEL);
- if (!devs) {
- dev_err(dev->class_dev,
- "Could not allocate memory. Out of memory?\n");
- kfree(bdev);
- return -ENOMEM;
- }
- devpriv->devs = devs;
- devpriv->devs[devpriv->ndevs++] = bdev;
- {
- /* Append dev:subdev to devpriv->name */
- char buf[20];
-
- snprintf(buf, sizeof(buf), "%u:%u ",
- bdev->minor, bdev->subdev);
- strlcat(devpriv->name, buf,
- sizeof(devpriv->name));
- }
- }
- }
-
- if (!devpriv->nchans) {
- dev_err(dev->class_dev, "No channels found!\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int bonding_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_bond_private *devpriv;
- struct comedi_subdevice *s;
- int ret;
-
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
- /*
- * Setup our bonding from config params.. sets up our private struct..
- */
- ret = do_dev_config(dev, it);
- if (ret)
- return ret;
-
- dev->board_name = devpriv->name;
-
- ret = comedi_alloc_subdevices(dev, 1);
- if (ret)
- return ret;
-
- s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = devpriv->nchans;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = bonding_dio_insn_bits;
- s->insn_config = bonding_dio_insn_config;
-
- dev_info(dev->class_dev,
- "%s: %s attached, %u channels from %u devices\n",
- dev->driver->driver_name, dev->board_name,
- devpriv->nchans, devpriv->ndevs);
-
- return 0;
-}
-
-static void bonding_detach(struct comedi_device *dev)
-{
- struct comedi_bond_private *devpriv = dev->private;
-
- if (devpriv && devpriv->devs) {
- DECLARE_BITMAP(devs_closed, COMEDI_NUM_BOARD_MINORS);
-
- memset(&devs_closed, 0, sizeof(devs_closed));
- while (devpriv->ndevs--) {
- struct bonded_device *bdev;
-
- bdev = devpriv->devs[devpriv->ndevs];
- if (!bdev)
- continue;
- if (!test_and_set_bit(bdev->minor, devs_closed))
- comedi_close(bdev->dev);
- kfree(bdev);
- }
- kfree(devpriv->devs);
- devpriv->devs = NULL;
- }
-}
-
-static struct comedi_driver bonding_driver = {
- .driver_name = "comedi_bond",
- .module = THIS_MODULE,
- .attach = bonding_attach,
- .detach = bonding_detach,
-};
-module_comedi_driver(bonding_driver);
-
-MODULE_AUTHOR("Calin A. Culianu");
-MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI devices together as one.");
-MODULE_LICENSE("GPL");