// 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.
*/
if (base_chan < bdev->nchans) { /* base channel falls within bonded device */ unsignedint 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);
/* * 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;
}
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;
}
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;
MODULE_AUTHOR("Calin A. Culianu");
MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI devices together as one.");
MODULE_LICENSE("GPL");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.