forked from Minki/linux
staging: comedi: ni_65xx: (bug fix) confine insn_bits to one subdevice
The `insn_bits` handler `ni_65xx_dio_insn_bits()` has a `for` loop that currently writes (optionally) and reads back up to 5 "ports" consisting of 8 channels each. It reads up to 32 1-bit channels but can only read and write a whole port at once - it needs to handle up to 5 ports as the first channel it reads might not be aligned on a port boundary. It breaks out of the loop early if the next port it handles is beyond the final port on the card. It also breaks out early on the 5th port in the loop if the first channel was aligned. Unfortunately, it doesn't check that the current port it is dealing with belongs to the comedi subdevice the `insn_bits` handler is acting on. That's a bug. Redo the `for` loop to terminate after the final port belonging to the subdevice, changing the loop variable in the process to simplify things a bit. The `for` loop could now try and handle more than 5 ports if the subdevice has more than 40 channels, but the test `if (bitshift >= 32)` ensures it will break out early after 4 or 5 ports (depending on whether the first channel is aligned on a port boundary). (`bitshift` will be between -7 and 7 inclusive on the first iteration, increasing by 8 for each subsequent operation.) Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Cc: <stable@vger.kernel.org> # 3.10.y 3.11.y 3.12.y Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a7ebaf4646
commit
677a315656
@ -369,28 +369,23 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
|
||||
{
|
||||
const struct ni_65xx_board *board = comedi_board(dev);
|
||||
struct ni_65xx_private *devpriv = dev->private;
|
||||
unsigned base_bitfield_channel;
|
||||
const unsigned max_ports_per_bitfield = 5;
|
||||
int base_bitfield_channel;
|
||||
unsigned read_bits = 0;
|
||||
unsigned j;
|
||||
int last_port_offset = ni_65xx_port_by_channel(s->n_chan - 1);
|
||||
int port_offset;
|
||||
|
||||
base_bitfield_channel = CR_CHAN(insn->chanspec);
|
||||
for (j = 0; j < max_ports_per_bitfield; ++j) {
|
||||
const unsigned port_offset =
|
||||
ni_65xx_port_by_channel(base_bitfield_channel) + j;
|
||||
const unsigned port =
|
||||
sprivate(s)->base_port + port_offset;
|
||||
unsigned base_port_channel;
|
||||
for (port_offset = ni_65xx_port_by_channel(base_bitfield_channel);
|
||||
port_offset <= last_port_offset; port_offset++) {
|
||||
unsigned port = sprivate(s)->base_port + port_offset;
|
||||
int base_port_channel = port_offset * ni_65xx_channels_per_port;
|
||||
unsigned port_mask, port_data, port_read_bits;
|
||||
int bitshift;
|
||||
if (port >= ni_65xx_total_num_ports(board))
|
||||
int bitshift = base_port_channel - base_bitfield_channel;
|
||||
|
||||
if (bitshift >= 32)
|
||||
break;
|
||||
base_port_channel = port_offset * ni_65xx_channels_per_port;
|
||||
port_mask = data[0];
|
||||
port_data = data[1];
|
||||
bitshift = base_port_channel - base_bitfield_channel;
|
||||
if (bitshift >= 32 || bitshift <= -32)
|
||||
break;
|
||||
if (bitshift > 0) {
|
||||
port_mask >>= bitshift;
|
||||
port_data >>= bitshift;
|
||||
|
Loading…
Reference in New Issue
Block a user