Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: comedi: adv_pci1710: fix analog output readback value

The last value written to a analog output channel is cached in the
private data of this driver for readback.

Currently, the wrong value is cached in the (*insn_write) functions.
The current code stores the data[n] value for readback afer the loop
has written all the values. At this time 'n' points past the end of
the data array.

Fix the functions by using a local variable to hold the data being
written to the analog output channel. This variable is then used
after the loop is complete to store the readback value. The current
value is retrieved before the loop in case no values are actually
written..

Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Reviewed-by: Ian Abbott <abbotti@mev.co.uk>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

H Hartley Sweeten and committed by
Greg Kroah-Hartman
1e85c1ea 7a081ea2

+12 -5
+12 -5
drivers/staging/comedi/drivers/adv_pci1710.c
··· 494 494 struct comedi_insn *insn, unsigned int *data) 495 495 { 496 496 struct pci1710_private *devpriv = dev->private; 497 + unsigned int val; 497 498 int n, chan, range, ofs; 498 499 499 500 chan = CR_CHAN(insn->chanspec); ··· 510 509 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); 511 510 ofs = PCI171x_DA1; 512 511 } 512 + val = devpriv->ao_data[chan]; 513 513 514 - for (n = 0; n < insn->n; n++) 515 - outw(data[n], dev->iobase + ofs); 514 + for (n = 0; n < insn->n; n++) { 515 + val = data[n]; 516 + outw(val, dev->iobase + ofs); 517 + } 516 518 517 - devpriv->ao_data[chan] = data[n]; 519 + devpriv->ao_data[chan] = val; 518 520 519 521 return n; 520 522 ··· 683 679 struct comedi_insn *insn, unsigned int *data) 684 680 { 685 681 struct pci1710_private *devpriv = dev->private; 682 + unsigned int val; 686 683 int n, rangereg, chan; 687 684 688 685 chan = CR_CHAN(insn->chanspec); ··· 693 688 outb(rangereg, dev->iobase + PCI1720_RANGE); 694 689 devpriv->da_ranges = rangereg; 695 690 } 691 + val = devpriv->ao_data[chan]; 696 692 697 693 for (n = 0; n < insn->n; n++) { 698 - outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1)); 694 + val = data[n]; 695 + outw(val, dev->iobase + PCI1720_DA0 + (chan << 1)); 699 696 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ 700 697 } 701 698 702 - devpriv->ao_data[chan] = data[n]; 699 + devpriv->ao_data[chan] = val; 703 700 704 701 return n; 705 702 }