mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
comedi: Make insn_rw_emulate_bits() do insn->n samples
The `insn_rw_emulate_bits()` function is used as a default handler for
`INSN_READ` instructions for subdevices that have a handler for
`INSN_BITS` but not for `INSN_READ`. Similarly, it is used as a default
handler for `INSN_WRITE` instructions for subdevices that have a handler
for `INSN_BITS` but not for `INSN_WRITE`. It works by emulating the
`INSN_READ` or `INSN_WRITE` instruction handling with a constructed
`INSN_BITS` instruction. However, `INSN_READ` and `INSN_WRITE`
instructions are supposed to be able read or write multiple samples,
indicated by the `insn->n` value, but `insn_rw_emulate_bits()` currently
only handles a single sample. For `INSN_READ`, the comedi core will
copy `insn->n` samples back to user-space. (That triggered KASAN
kernel-infoleak errors when `insn->n` was greater than 1, but that is
being fixed more generally elsewhere in the comedi core.)
Make `insn_rw_emulate_bits()` either handle `insn->n` samples, or return
an error, to conform to the general expectation for `INSN_READ` and
`INSN_WRITE` handlers.
Fixes: ed9eccbe89
("Staging: add comedi core")
Cc: stable <stable@kernel.org> # 5.13+
Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Link: https://lore.kernel.org/r/20250725141034.87297-1-abbotti@mev.co.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
3cd212e895
commit
7afba9221f
1 changed files with 14 additions and 13 deletions
|
@ -620,11 +620,9 @@ static int insn_rw_emulate_bits(struct comedi_device *dev,
|
|||
unsigned int chan = CR_CHAN(insn->chanspec);
|
||||
unsigned int base_chan = (chan < 32) ? 0 : chan;
|
||||
unsigned int _data[2];
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (insn->n == 0)
|
||||
return 0;
|
||||
|
||||
memset(_data, 0, sizeof(_data));
|
||||
memset(&_insn, 0, sizeof(_insn));
|
||||
_insn.insn = INSN_BITS;
|
||||
|
@ -635,18 +633,21 @@ static int insn_rw_emulate_bits(struct comedi_device *dev,
|
|||
if (insn->insn == INSN_WRITE) {
|
||||
if (!(s->subdev_flags & SDF_WRITABLE))
|
||||
return -EINVAL;
|
||||
_data[0] = 1U << (chan - base_chan); /* mask */
|
||||
_data[1] = data[0] ? (1U << (chan - base_chan)) : 0; /* bits */
|
||||
_data[0] = 1U << (chan - base_chan); /* mask */
|
||||
}
|
||||
for (i = 0; i < insn->n; i++) {
|
||||
if (insn->insn == INSN_WRITE)
|
||||
_data[1] = data[i] ? _data[0] : 0; /* bits */
|
||||
|
||||
ret = s->insn_bits(dev, s, &_insn, _data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (insn->insn == INSN_READ)
|
||||
data[i] = (_data[1] >> (chan - base_chan)) & 1;
|
||||
}
|
||||
|
||||
ret = s->insn_bits(dev, s, &_insn, _data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (insn->insn == INSN_READ)
|
||||
data[0] = (_data[1] >> (chan - base_chan)) & 1;
|
||||
|
||||
return 1;
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int __comedi_device_postconfig_async(struct comedi_device *dev,
|
||||
|
|
Loading…
Add table
Reference in a new issue