Commit 16d2d3cb authored by Ian Abbott's avatar Ian Abbott Committed by Greg Kroah-Hartman

staging: comedi: comedi_bond: get INSN_CONFIG_DIO_QUERY info from horse's mouth

The DIO subdevice of the "comedi_bond" device attempts to remember the
directions of DIO channels itself in the `io_bits` member of the
subdevice, but that is only large enough for the first 32 channels and
it might not be accurate anyway as changing the direction of one channel
may have affected a whole group of channels and we have no idea of the
initial directions before the "bonded" device was linked to the the
"comedi_bond" device.  It would be better to ask the bonded device for
this information when handling a `INSN_CONFIG_DIO_QUERY` configuration
instruction.  Add new function `comedi_dio_get_config()` to the
"kcomedilib" module to allow us to get the DIO direction of a channel
and use it.
Signed-off-by: default avatarIan Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7b8cbe92
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
struct comedi_device *comedi_open(const char *path); struct comedi_device *comedi_open(const char *path);
int comedi_close(struct comedi_device *dev); int comedi_close(struct comedi_device *dev);
int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev,
unsigned int chan, unsigned int *io);
int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
unsigned int chan, unsigned int io); unsigned int chan, unsigned int io);
int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev, int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev,
......
...@@ -124,59 +124,44 @@ static int bonding_dio_insn_config(struct comedi_device *dev, ...@@ -124,59 +124,44 @@ static int bonding_dio_insn_config(struct comedi_device *dev,
struct comedi_insn *insn, unsigned int *data) struct comedi_insn *insn, unsigned int *data)
{ {
struct comedi_bond_private *devpriv = dev->private; struct comedi_bond_private *devpriv = dev->private;
int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits; unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int chanid_offset; int ret;
unsigned int io;
struct bonded_device *bdev; struct bonded_device *bdev;
struct bonded_device **devs; struct bonded_device **devs;
if (chan < 0 || chan >= devpriv->nchans)
return -EINVAL;
/* /*
* Locate bonded subdevice. * Locate bonded subdevice and adjust channel.
*/ */
chanid_offset = 0;
devs = devpriv->devs; devs = devpriv->devs;
for (bdev = *devs++; chan >= chanid_offset + bdev->nchans; for (bdev = *devs++; chan >= bdev->nchans; bdev = *devs++)
bdev = *devs++) chan -= bdev->nchans;
chanid_offset += bdev->nchans;
/* /*
* The input or output configuration of each digital line is * The input or output configuration of each digital line is
* configured by a special insn_config instruction. chanspec * configured by a special insn_config instruction. chanspec
* contains the channel to be changed, and data[0] contains the * contains the channel to be changed, and data[0] contains the
* value COMEDI_INPUT or COMEDI_OUTPUT. * 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]) { switch (data[0]) {
case INSN_CONFIG_DIO_OUTPUT: case INSN_CONFIG_DIO_OUTPUT:
io = COMEDI_OUTPUT; /* is this really necessary? */
io_bits |= 1 << chan;
break;
case INSN_CONFIG_DIO_INPUT: case INSN_CONFIG_DIO_INPUT:
io = COMEDI_INPUT; /* is this really necessary? */ ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, data[0]);
io_bits &= ~(1 << chan);
break; break;
case INSN_CONFIG_DIO_QUERY: case INSN_CONFIG_DIO_QUERY:
data[1] = ret = comedi_dio_get_config(bdev->dev, bdev->subdev, chan,
(io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; &data[1]);
return insn->n;
break; break;
default: default:
return -EINVAL; ret = -EINVAL;
break; break;
} }
/* 'real' channel id for this subdev.. */ if (ret >= 0)
chan -= chanid_offset; ret = insn->n;
ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, io); return ret;
if (ret != 1)
return -EINVAL;
/*
* Finally, save the new io_bits values since we didn't get an error
* above.
*/
s->io_bits = io_bits;
return insn->n;
} }
static void *realloc(const void *oldmem, size_t newlen, size_t oldlen) static void *realloc(const void *oldmem, size_t newlen, size_t oldlen)
......
...@@ -123,6 +123,27 @@ static int comedi_do_insn(struct comedi_device *dev, ...@@ -123,6 +123,27 @@ static int comedi_do_insn(struct comedi_device *dev,
return ret; return ret;
} }
int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev,
unsigned int chan, unsigned int *io)
{
struct comedi_insn insn;
unsigned int data[2];
int ret;
memset(&insn, 0, sizeof(insn));
insn.insn = INSN_CONFIG;
insn.n = 2;
insn.subdev = subdev;
insn.chanspec = CR_PACK(chan, 0, 0);
data[0] = INSN_CONFIG_DIO_QUERY;
data[1] = 0;
ret = comedi_do_insn(dev, &insn, data);
if (ret >= 0)
*io = data[1];
return ret;
}
EXPORT_SYMBOL_GPL(comedi_dio_get_config);
int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
unsigned int chan, unsigned int io) unsigned int chan, unsigned int io)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment