[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251210124455.69131-1-abbotti@mev.co.uk>
Date: Wed, 10 Dec 2025 12:44:55 +0000
From: Ian Abbott <abbotti@....co.uk>
To: linux-kernel@...r.kernel.org
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Ian Abbott <abbotti@....co.uk>,
H Hartley Sweeten <hsweeten@...ionengravers.com>
Subject: [PATCH] comedi: comedi_test: add a DIO subdevice
The fake "comedi_test" device currently has two subdevices: an analog
input subdevice, and an analog output subdevice. To make it a bit more
useful for testing, add a third subdevice for digital I/O.
The new DIO subdevice has 32 channels with each channel individually
programmable as an input or an output. To add a bit of interaction,
channels 0 to 15 are wired to channels 16 to 31 (0 to 16, 1 to 17,
etc.), and the state of each wire can be read back on both of the
channels connected to it. The outputs are modelled as NPN open
collector outputs with a pull-up resistor on the wire, so the state of
each wire (and the value read back from each channel connected to it)
will be logic level 1 unless either channel is configured as an output
at logic level 0.
Signed-off-by: Ian Abbott <abbotti@....co.uk>
---
drivers/comedi/drivers/comedi_test.c | 50 +++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/comedi/drivers/comedi_test.c b/drivers/comedi/drivers/comedi_test.c
index 7984950f0f99..01aafce20ef8 100644
--- a/drivers/comedi/drivers/comedi_test.c
+++ b/drivers/comedi/drivers/comedi_test.c
@@ -692,6 +692,44 @@ static int waveform_ao_insn_config(struct comedi_device *dev,
return -EINVAL;
}
+static int waveform_dio_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ u32 driven_low;
+ u16 wires;
+
+ /* Update the channel outputs. */
+ comedi_dio_update_state(s, data);
+ /*
+ * We are modelling the outputs as NPN open collector (0 = driven low,
+ * 1 = high impedance), with the lower 16 channels wired to the upper
+ * 16 channels in pairs (0 to 16, 1 to 17, ..., 15 to 31), with a
+ * pull-up resistor on each wire. When reading back each channel, we
+ * read back the state of the wire to which it is connected.
+ *
+ * The state of each wire and the value read back from both channels
+ * connected to it will be logic 1 unless either channel connected to
+ * the wire is configured as an output in the logic 0 state.
+ */
+ driven_low = s->io_bits & ~s->state;
+ wires = 0xFFFF & ~driven_low & ~(driven_low >> 16);
+ /* Read back the state of the wires for each pair of channels. */
+ data[1] = wires | (wires << 16);
+
+ return insn->n;
+}
+
+static int waveform_dio_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ /* configure each channel as input or output individually */
+ return comedi_dio_insn_config(dev, s, insn, data, 0);
+}
+
static int waveform_common_attach(struct comedi_device *dev,
int amplitude, int period)
{
@@ -707,7 +745,7 @@ static int waveform_common_attach(struct comedi_device *dev,
devpriv->wf_amplitude = amplitude;
devpriv->wf_period = period;
- ret = comedi_alloc_subdevices(dev, 2);
+ ret = comedi_alloc_subdevices(dev, 3);
if (ret)
return ret;
@@ -746,6 +784,16 @@ static int waveform_common_attach(struct comedi_device *dev,
for (i = 0; i < s->n_chan; i++)
devpriv->ao_loopbacks[i] = s->maxdata / 2;
+ s = &dev->subdevices[2];
+ /* digital input/output subdevice */
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 32;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = waveform_dio_insn_bits;
+ s->insn_config = waveform_dio_insn_config;
+
devpriv->dev = dev;
timer_setup(&devpriv->ai_timer, waveform_ai_timer, 0);
timer_setup(&devpriv->ao_timer, waveform_ao_timer, 0);
--
2.51.0
Powered by blists - more mailing lists