--- /dev/null
+From be8e89087ec2d2c8a1ad1e3db64bf4efdfc3c298 Mon Sep 17 00:00:00 2001
+From: Ian Abbott <abbotti@mev.co.uk>
+Date: Mon, 19 Jan 2015 14:47:27 +0000
+Subject: staging: comedi: cb_pcidas64: fix incorrect AI range code handling
+
+From: Ian Abbott <abbotti@mev.co.uk>
+
+commit be8e89087ec2d2c8a1ad1e3db64bf4efdfc3c298 upstream.
+
+The hardware range code values and list of valid ranges for the AI
+subdevice is incorrect for several supported boards. The hardware range
+code values for all boards except PCI-DAS4020/12 is determined by
+calling `ai_range_bits_6xxx()` based on the maximum voltage of the range
+and whether it is bipolar or unipolar, however it only returns the
+correct hardware range code for the PCI-DAS60xx boards. For
+PCI-DAS6402/16 (and /12) it returns the wrong code for the unipolar
+ranges. For PCI-DAS64/Mx/16 it returns the wrong code for all the
+ranges and the comedi range table is incorrect.
+
+Change `ai_range_bits_6xxx()` to use a look-up table pointed to by new
+member `ai_range_codes` of `struct pcidas64_board` to map the comedi
+range table indices to the hardware range codes. Use a new comedi range
+table for the PCI-DAS64/Mx/16 boards (and the commented out variants).
+
+Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/staging/comedi/drivers/cb_pcidas64.c | 124 ++++++++++++++++-----------
+ 1 file changed, 76 insertions(+), 48 deletions(-)
+
+--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
++++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
+@@ -441,6 +441,29 @@ static const struct comedi_lrange ai_ran
+ }
+ };
+
++static const uint8_t ai_range_code_64xx[8] = {
++ 0x0, 0x1, 0x2, 0x3, /* bipolar 10, 5, 2,5, 1.25 */
++ 0x8, 0x9, 0xa, 0xb /* unipolar 10, 5, 2.5, 1.25 */
++};
++
++/* analog input ranges for 64-Mx boards */
++static const struct comedi_lrange ai_ranges_64_mx = {
++ 7, {
++ BIP_RANGE(5),
++ BIP_RANGE(2.5),
++ BIP_RANGE(1.25),
++ BIP_RANGE(0.625),
++ UNI_RANGE(5),
++ UNI_RANGE(2.5),
++ UNI_RANGE(1.25)
++ }
++};
++
++static const uint8_t ai_range_code_64_mx[7] = {
++ 0x0, 0x1, 0x2, 0x3, /* bipolar 5, 2.5, 1.25, 0.625 */
++ 0x9, 0xa, 0xb /* unipolar 5, 2.5, 1.25 */
++};
++
+ /* analog input ranges for 60xx boards */
+ static const struct comedi_lrange ai_ranges_60xx = {
+ 4, {
+@@ -451,6 +474,10 @@ static const struct comedi_lrange ai_ran
+ }
+ };
+
++static const uint8_t ai_range_code_60xx[4] = {
++ 0x0, 0x1, 0x4, 0x7 /* bipolar 10, 5, 0.5, 0.05 */
++};
++
+ /* analog input ranges for 6030, etc boards */
+ static const struct comedi_lrange ai_ranges_6030 = {
+ 14, {
+@@ -471,6 +498,11 @@ static const struct comedi_lrange ai_ran
+ }
+ };
+
++static const uint8_t ai_range_code_6030[14] = {
++ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, /* bip 10, 5, 2, 1, 0.5, 0.2, 0.1 */
++ 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* uni 10, 5, 2, 1, 0.5, 0.2, 0.1 */
++};
++
+ /* analog input ranges for 6052, etc boards */
+ static const struct comedi_lrange ai_ranges_6052 = {
+ 15, {
+@@ -492,6 +524,11 @@ static const struct comedi_lrange ai_ran
+ }
+ };
+
++static const uint8_t ai_range_code_6052[15] = {
++ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, /* bipolar 10 ... 0.05 */
++ 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* unipolar 10 ... 0.1 */
++};
++
+ /* analog input ranges for 4020 board */
+ static const struct comedi_lrange ai_ranges_4020 = {
+ 2, {
+@@ -595,6 +632,7 @@ struct pcidas64_board {
+ int ai_bits; /* analog input resolution */
+ int ai_speed; /* fastest conversion period in ns */
+ const struct comedi_lrange *ai_range_table;
++ const uint8_t *ai_range_code;
+ int ao_nchan; /* number of analog out channels */
+ int ao_bits; /* analog output resolution */
+ int ao_scan_speed; /* analog output scan speed */
+@@ -653,6 +691,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
++ .ai_range_code = ai_range_code_64xx,
+ .ao_range_table = &ao_ranges_64xx,
+ .ao_range_code = ao_range_code_64xx,
+ .ai_fifo = &ai_fifo_64xx,
+@@ -668,6 +707,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
++ .ai_range_code = ai_range_code_64xx,
+ .ao_range_table = &ao_ranges_64xx,
+ .ao_range_code = ao_range_code_64xx,
+ .ai_fifo = &ai_fifo_64xx,
+@@ -682,7 +722,8 @@ static const struct pcidas64_board pcida
+ .ao_bits = 16,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+- .ai_range_table = &ai_ranges_64xx,
++ .ai_range_table = &ai_ranges_64_mx,
++ .ai_range_code = ai_range_code_64_mx,
+ .ao_range_table = &ao_ranges_64xx,
+ .ao_range_code = ao_range_code_64xx,
+ .ai_fifo = &ai_fifo_64xx,
+@@ -697,7 +738,8 @@ static const struct pcidas64_board pcida
+ .ao_bits = 16,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+- .ai_range_table = &ai_ranges_64xx,
++ .ai_range_table = &ai_ranges_64_mx,
++ .ai_range_code = ai_range_code_64_mx,
+ .ao_range_table = &ao_ranges_64xx,
+ .ao_range_code = ao_range_code_64xx,
+ .ai_fifo = &ai_fifo_64xx,
+@@ -712,7 +754,8 @@ static const struct pcidas64_board pcida
+ .ao_bits = 16,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+- .ai_range_table = &ai_ranges_64xx,
++ .ai_range_table = &ai_ranges_64_mx,
++ .ai_range_code = ai_range_code_64_mx,
+ .ao_range_table = &ao_ranges_64xx,
+ .ao_range_code = ao_range_code_64xx,
+ .ai_fifo = &ai_fifo_64xx,
+@@ -727,6 +770,7 @@ static const struct pcidas64_board pcida
+ .ao_bits = 16,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
++ .ai_range_code = ai_range_code_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -742,6 +786,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 100000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
++ .ai_range_code = ai_range_code_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -756,6 +801,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 100000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
++ .ai_range_code = ai_range_code_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -771,6 +817,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 100000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
++ .ai_range_code = ai_range_code_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -786,6 +833,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6030,
++ .ai_range_code = ai_range_code_6030,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -801,6 +849,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6030,
++ .ai_range_code = ai_range_code_6030,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -814,6 +863,7 @@ static const struct pcidas64_board pcida
+ .ao_nchan = 0,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6030,
++ .ai_range_code = ai_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+@@ -825,6 +875,7 @@ static const struct pcidas64_board pcida
+ .ao_nchan = 0,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6030,
++ .ai_range_code = ai_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+@@ -837,6 +888,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 0,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
++ .ai_range_code = ai_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+@@ -850,6 +902,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 100000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
++ .ai_range_code = ai_range_code_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -865,6 +918,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 100000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
++ .ai_range_code = ai_range_code_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -880,6 +934,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 1000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6052,
++ .ai_range_code = ai_range_code_6052,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -895,6 +950,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 3333,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6052,
++ .ai_range_code = ai_range_code_6052,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -910,6 +966,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 1000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6052,
++ .ai_range_code = ai_range_code_6052,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -925,6 +982,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 1000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6052,
++ .ai_range_code = ai_range_code_6052,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+@@ -959,6 +1017,7 @@ static const struct pcidas64_board pcida
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
++ .ai_range_code = ai_range_code_64xx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+@@ -970,7 +1029,8 @@ static const struct pcidas64_board pcida
+ .ao_nchan = 0,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+- .ai_range_table = &ai_ranges_64xx,
++ .ai_range_table = &ai_ranges_64_mx,
++ .ai_range_code = ai_range_code_64_mx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+@@ -982,7 +1042,8 @@ static const struct pcidas64_board pcida
+ .ao_nchan = 0,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+- .ai_range_table = &ai_ranges_64xx,
++ .ai_range_table = &ai_ranges_64_mx,
++ .ai_range_code = ai_range_code_64_mx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+@@ -994,7 +1055,8 @@ static const struct pcidas64_board pcida
+ .ao_nchan = 0,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+- .ai_range_table = &ai_ranges_64xx,
++ .ai_range_table = &ai_ranges_64_mx,
++ .ai_range_code = ai_range_code_64_mx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+@@ -1006,7 +1068,8 @@ static const struct pcidas64_board pcida
+ .ao_nchan = 2,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+- .ai_range_table = &ai_ranges_64xx,
++ .ai_range_table = &ai_ranges_64_mx,
++ .ai_range_code = ai_range_code_64_mx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+@@ -1018,7 +1081,8 @@ static const struct pcidas64_board pcida
+ .ao_nchan = 2,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+- .ai_range_table = &ai_ranges_64xx,
++ .ai_range_table = &ai_ranges_64_mx,
++ .ai_range_code = ai_range_code_64_mx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+@@ -1030,7 +1094,8 @@ static const struct pcidas64_board pcida
+ .ao_nchan = 2,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+- .ai_range_table = &ai_ranges_64xx,
++ .ai_range_table = &ai_ranges_64_mx,
++ .ai_range_code = ai_range_code_64_mx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+@@ -1127,45 +1192,8 @@ static unsigned int ai_range_bits_6xxx(c
+ unsigned int range_index)
+ {
+ const struct pcidas64_board *thisboard = comedi_board(dev);
+- const struct comedi_krange *range =
+- &thisboard->ai_range_table->range[range_index];
+- unsigned int bits = 0;
+-
+- switch (range->max) {
+- case 10000000:
+- bits = 0x000;
+- break;
+- case 5000000:
+- bits = 0x100;
+- break;
+- case 2000000:
+- case 2500000:
+- bits = 0x200;
+- break;
+- case 1000000:
+- case 1250000:
+- bits = 0x300;
+- break;
+- case 500000:
+- bits = 0x400;
+- break;
+- case 200000:
+- case 250000:
+- bits = 0x500;
+- break;
+- case 100000:
+- bits = 0x600;
+- break;
+- case 50000:
+- bits = 0x700;
+- break;
+- default:
+- comedi_error(dev, "bug! in ai_range_bits_6xxx");
+- break;
+- }
+- if (range->min == 0)
+- bits += 0x900;
+- return bits;
++
++ return thisboard->ai_range_code[range_index] << 8;
+ }
+
+ static unsigned int hw_revision(const struct comedi_device *dev,