From: Greg Kroah-Hartman Date: Mon, 16 Mar 2015 12:52:37 +0000 (+0100) Subject: 3.10-stable patches X-Git-Tag: v3.10.72~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d459171977397a401bf33072e5b261dc9b1a5f3c;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches added patches: dm-fix-a-race-condition-in-dm_get_md.patch dm-io-reject-unsupported-discard-requests-with-eopnotsupp.patch dm-mirror-do-not-degrade-the-mirror-on-discard-error.patch dm-snapshot-fix-a-possible-invalid-memory-access-on-unload.patch drivers-hv-vmbus-incorrect-device-name-is-printed-when-child-device-is-unregistered.patch hid-fixup-the-conflicting-keyboard-mappings-quirk.patch hid-input-fix-confusion-on-conflicting-mappings.patch staging-comedi-cb_pcidas64-fix-incorrect-ai-range-code-handling.patch --- diff --git a/queue-3.10/dm-fix-a-race-condition-in-dm_get_md.patch b/queue-3.10/dm-fix-a-race-condition-in-dm_get_md.patch new file mode 100644 index 00000000000..4bf4085f24a --- /dev/null +++ b/queue-3.10/dm-fix-a-race-condition-in-dm_get_md.patch @@ -0,0 +1,84 @@ +From 2bec1f4a8832e74ebbe859f176d8a9cb20dd97f4 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Tue, 17 Feb 2015 14:30:53 -0500 +Subject: dm: fix a race condition in dm_get_md + +From: Mikulas Patocka + +commit 2bec1f4a8832e74ebbe859f176d8a9cb20dd97f4 upstream. + +The function dm_get_md finds a device mapper device with a given dev_t, +increases the reference count and returns the pointer. + +dm_get_md calls dm_find_md, dm_find_md takes _minor_lock, finds the +device, tests that the device doesn't have DMF_DELETING or DMF_FREEING +flag, drops _minor_lock and returns pointer to the device. dm_get_md then +calls dm_get. dm_get calls BUG if the device has the DMF_FREEING flag, +otherwise it increments the reference count. + +There is a possible race condition - after dm_find_md exits and before +dm_get is called, there are no locks held, so the device may disappear or +DMF_FREEING flag may be set, which results in BUG. + +To fix this bug, we need to call dm_get while we hold _minor_lock. This +patch renames dm_find_md to dm_get_md and changes it so that it calls +dm_get while holding the lock. + +Signed-off-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm.c | 27 ++++++++++----------------- + 1 file changed, 10 insertions(+), 17 deletions(-) + +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -2270,7 +2270,7 @@ int dm_setup_md_queue(struct mapped_devi + return 0; + } + +-static struct mapped_device *dm_find_md(dev_t dev) ++struct mapped_device *dm_get_md(dev_t dev) + { + struct mapped_device *md; + unsigned minor = MINOR(dev); +@@ -2281,12 +2281,15 @@ static struct mapped_device *dm_find_md( + spin_lock(&_minor_lock); + + md = idr_find(&_minor_idr, minor); +- if (md && (md == MINOR_ALLOCED || +- (MINOR(disk_devt(dm_disk(md))) != minor) || +- dm_deleting_md(md) || +- test_bit(DMF_FREEING, &md->flags))) { +- md = NULL; +- goto out; ++ if (md) { ++ if ((md == MINOR_ALLOCED || ++ (MINOR(disk_devt(dm_disk(md))) != minor) || ++ dm_deleting_md(md) || ++ test_bit(DMF_FREEING, &md->flags))) { ++ md = NULL; ++ goto out; ++ } ++ dm_get(md); + } + + out: +@@ -2294,16 +2297,6 @@ out: + + return md; + } +- +-struct mapped_device *dm_get_md(dev_t dev) +-{ +- struct mapped_device *md = dm_find_md(dev); +- +- if (md) +- dm_get(md); +- +- return md; +-} + EXPORT_SYMBOL_GPL(dm_get_md); + + void *dm_get_mdptr(struct mapped_device *md) diff --git a/queue-3.10/dm-io-reject-unsupported-discard-requests-with-eopnotsupp.patch b/queue-3.10/dm-io-reject-unsupported-discard-requests-with-eopnotsupp.patch new file mode 100644 index 00000000000..c70ebf7233b --- /dev/null +++ b/queue-3.10/dm-io-reject-unsupported-discard-requests-with-eopnotsupp.patch @@ -0,0 +1,62 @@ +From 37527b869207ad4c208b1e13967d69b8bba1fbf9 Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Fri, 13 Feb 2015 11:05:37 -0800 +Subject: dm io: reject unsupported DISCARD requests with EOPNOTSUPP + +From: "Darrick J. Wong" + +commit 37527b869207ad4c208b1e13967d69b8bba1fbf9 upstream. + +I created a dm-raid1 device backed by a device that supports DISCARD +and another device that does NOT support DISCARD with the following +dm configuration: + + # echo '0 2048 mirror core 1 512 2 /dev/sda 0 /dev/sdb 0' | dmsetup create moo + # lsblk -D + NAME DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO + sda 0 4K 1G 0 + `-moo (dm-0) 0 4K 1G 0 + sdb 0 0B 0B 0 + `-moo (dm-0) 0 4K 1G 0 + +Notice that the mirror device /dev/mapper/moo advertises DISCARD +support even though one of the mirror halves doesn't. + +If I issue a DISCARD request (via fstrim, mount -o discard, or ioctl +BLKDISCARD) through the mirror, kmirrord gets stuck in an infinite +loop in do_region() when it tries to issue a DISCARD request to sdb. +The problem is that when we call do_region() against sdb, num_sectors +is set to zero because q->limits.max_discard_sectors is zero. +Therefore, "remaining" never decreases and the loop never terminates. + +To fix this: before entering the loop, check for the combination of +REQ_DISCARD and no discard and return -EOPNOTSUPP to avoid hanging up +the mirror device. + +This bug was found by the unfortunate coincidence of pvmove and a +discard operation in the RHEL 6.5 kernel; upstream is also affected. + +Signed-off-by: Darrick J. Wong +Acked-by: "Martin K. Petersen" +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-io.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/md/dm-io.c ++++ b/drivers/md/dm-io.c +@@ -291,6 +291,12 @@ static void do_region(int rw, unsigned r + unsigned short logical_block_size = queue_logical_block_size(q); + sector_t num_sectors; + ++ /* Reject unsupported discard requests */ ++ if ((rw & REQ_DISCARD) && !blk_queue_discard(q)) { ++ dec_count(io, region, -EOPNOTSUPP); ++ return; ++ } ++ + /* + * where->count may be zero if rw holds a flush and we need to + * send a zero-sized flush. diff --git a/queue-3.10/dm-mirror-do-not-degrade-the-mirror-on-discard-error.patch b/queue-3.10/dm-mirror-do-not-degrade-the-mirror-on-discard-error.patch new file mode 100644 index 00000000000..36766eb46e5 --- /dev/null +++ b/queue-3.10/dm-mirror-do-not-degrade-the-mirror-on-discard-error.patch @@ -0,0 +1,47 @@ +From f2ed51ac64611d717d1917820a01930174c2f236 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Thu, 12 Feb 2015 10:09:20 -0500 +Subject: dm mirror: do not degrade the mirror on discard error + +From: Mikulas Patocka + +commit f2ed51ac64611d717d1917820a01930174c2f236 upstream. + +It may be possible that a device claims discard support but it rejects +discards with -EOPNOTSUPP. It happens when using loopback on ext2/ext3 +filesystem driven by the ext4 driver. It may also happen if the +underlying devices are moved from one disk on another. + +If discard error happens, we reject the bio with -EOPNOTSUPP, but we do +not degrade the array. + +This patch fixes failed test shell/lvconvert-repair-transient.sh in the +lvm2 testsuite if the testsuite is extracted on an ext2 or ext3 +filesystem and it is being driven by the ext4 driver. + +Signed-off-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-raid1.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/md/dm-raid1.c ++++ b/drivers/md/dm-raid1.c +@@ -604,6 +604,15 @@ static void write_callback(unsigned long + return; + } + ++ /* ++ * If the bio is discard, return an error, but do not ++ * degrade the array. ++ */ ++ if (bio->bi_rw & REQ_DISCARD) { ++ bio_endio(bio, -EOPNOTSUPP); ++ return; ++ } ++ + for (i = 0; i < ms->nr_mirrors; i++) + if (test_bit(i, &error)) + fail_mirror(ms->mirror + i, DM_RAID1_WRITE_ERROR); diff --git a/queue-3.10/dm-snapshot-fix-a-possible-invalid-memory-access-on-unload.patch b/queue-3.10/dm-snapshot-fix-a-possible-invalid-memory-access-on-unload.patch new file mode 100644 index 00000000000..f913f3fa2ed --- /dev/null +++ b/queue-3.10/dm-snapshot-fix-a-possible-invalid-memory-access-on-unload.patch @@ -0,0 +1,52 @@ +From 22aa66a3ee5b61e0f4a0bfeabcaa567861109ec3 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Tue, 17 Feb 2015 14:34:00 -0500 +Subject: dm snapshot: fix a possible invalid memory access on unload + +From: Mikulas Patocka + +commit 22aa66a3ee5b61e0f4a0bfeabcaa567861109ec3 upstream. + +When the snapshot target is unloaded, snapshot_dtr() waits until +pending_exceptions_count drops to zero. Then, it destroys the snapshot. +Therefore, the function that decrements pending_exceptions_count +should not touch the snapshot structure after the decrement. + +pending_complete() calls free_pending_exception(), which decrements +pending_exceptions_count, and then it performs up_write(&s->lock) and it +calls retry_origin_bios() which dereferences s->origin. These two +memory accesses to the fields of the snapshot may touch the dm_snapshot +struture after it is freed. + +This patch moves the call to free_pending_exception() to the end of +pending_complete(), so that the snapshot will not be destroyed while +pending_complete() is in progress. + +Signed-off-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-snap.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/md/dm-snap.c ++++ b/drivers/md/dm-snap.c +@@ -1439,8 +1439,6 @@ out: + full_bio->bi_end_io = pe->full_bio_end_io; + full_bio->bi_private = pe->full_bio_private; + } +- free_pending_exception(pe); +- + increment_pending_exceptions_done_count(); + + up_write(&s->lock); +@@ -1457,6 +1455,8 @@ out: + } + + retry_origin_bios(s, origin_bios); ++ ++ free_pending_exception(pe); + } + + static void commit_callback(void *context, int success) diff --git a/queue-3.10/drivers-hv-vmbus-incorrect-device-name-is-printed-when-child-device-is-unregistered.patch b/queue-3.10/drivers-hv-vmbus-incorrect-device-name-is-printed-when-child-device-is-unregistered.patch new file mode 100644 index 00000000000..e358f072347 --- /dev/null +++ b/queue-3.10/drivers-hv-vmbus-incorrect-device-name-is-printed-when-child-device-is-unregistered.patch @@ -0,0 +1,58 @@ +From 84672369ffb98a51d4ddf74c20a23636da3ad615 Mon Sep 17 00:00:00 2001 +From: Fernando Soto +Date: Fri, 14 Jun 2013 23:13:35 +0000 +Subject: Drivers: hv: vmbus: incorrect device name is printed when child device is unregistered +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Fernando Soto + +commit 84672369ffb98a51d4ddf74c20a23636da3ad615 upstream. + +Whenever a device is unregistered in vmbus_device_unregister (drivers/hv/vmbus_drv.c), the device name in the log message may contain garbage as the memory has already been freed by the time pr_info is called. Log example: + [ 3149.170475] hv_vmbus: child device àõsèè0_5 unregistered + +By logging the message just before calling device_unregister, the correct device name is printed: +[ 3145.034652] hv_vmbus: child device vmbus_0_5 unregistered + +Also changing register & unregister messages to debug to avoid unnecessarily cluttering the kernel log. + +Signed-off-by: Fernando M Soto +Signed-off-by: K. Y. Srinivasan +Cc: Joseph Salisbury +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hv/vmbus_drv.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/hv/vmbus_drv.c ++++ b/drivers/hv/vmbus_drv.c +@@ -686,7 +686,7 @@ int vmbus_device_register(struct hv_devi + if (ret) + pr_err("Unable to register child device\n"); + else +- pr_info("child device %s registered\n", ++ pr_debug("child device %s registered\n", + dev_name(&child_device_obj->device)); + + return ret; +@@ -698,14 +698,14 @@ int vmbus_device_register(struct hv_devi + */ + void vmbus_device_unregister(struct hv_device *device_obj) + { ++ pr_debug("child device %s unregistered\n", ++ dev_name(&device_obj->device)); ++ + /* + * Kick off the process of unregistering the device. + * This will call vmbus_remove() and eventually vmbus_device_release() + */ + device_unregister(&device_obj->device); +- +- pr_info("child device %s unregistered\n", +- dev_name(&device_obj->device)); + } + + diff --git a/queue-3.10/hid-fixup-the-conflicting-keyboard-mappings-quirk.patch b/queue-3.10/hid-fixup-the-conflicting-keyboard-mappings-quirk.patch new file mode 100644 index 00000000000..de69a5b09d6 --- /dev/null +++ b/queue-3.10/hid-fixup-the-conflicting-keyboard-mappings-quirk.patch @@ -0,0 +1,34 @@ +From 8e7b341037db1835ee6eea64663013cbfcf33575 Mon Sep 17 00:00:00 2001 +From: Jiri Kosina +Date: Tue, 6 Jan 2015 22:34:19 +0100 +Subject: HID: fixup the conflicting keyboard mappings quirk + +From: Jiri Kosina + +commit 8e7b341037db1835ee6eea64663013cbfcf33575 upstream. + +The ignore check that got added in 6ce901eb61 ("HID: input: fix confusion +on conflicting mappings") needs to properly check for VARIABLE reports +as well (ARRAY reports should be ignored), otherwise legitimate keyboards +might break. + +Fixes: 6ce901eb61 ("HID: input: fix confusion on conflicting mappings") +Reported-by: Fredrik Hallenberg +Reported-by: David Herrmann +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hid/hid-input.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/hid/hid-input.c ++++ b/drivers/hid/hid-input.c +@@ -1078,6 +1078,7 @@ void hidinput_hid_event(struct hid_devic + */ + if (!(field->flags & (HID_MAIN_ITEM_RELATIVE | + HID_MAIN_ITEM_BUFFERED_BYTE)) && ++ (field->flags & HID_MAIN_ITEM_VARIABLE) && + usage->usage_index < field->maxusage && + value == field->value[usage->usage_index]) + return; diff --git a/queue-3.10/hid-input-fix-confusion-on-conflicting-mappings.patch b/queue-3.10/hid-input-fix-confusion-on-conflicting-mappings.patch new file mode 100644 index 00000000000..6c1bd32e744 --- /dev/null +++ b/queue-3.10/hid-input-fix-confusion-on-conflicting-mappings.patch @@ -0,0 +1,143 @@ +From 6ce901eb61aa30ba8565c62049ee80c90728ef14 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Mon, 29 Dec 2014 15:21:26 +0100 +Subject: HID: input: fix confusion on conflicting mappings + +From: David Herrmann + +commit 6ce901eb61aa30ba8565c62049ee80c90728ef14 upstream. + +On an PC-101/103/104 keyboard (American layout) the 'Enter' key and its +neighbours look like this: + + +---+ +---+ +-------+ + | 1 | | 2 | | 5 | + +---+ +---+ +-------+ + +---+ +-----------+ + | 3 | | 4 | + +---+ +-----------+ + +On a PC-102/105 keyboard (European layout) it looks like this: + + +---+ +---+ +-------+ + | 1 | | 2 | | | + +---+ +---+ +-+ 4 | + +---+ +---+ | | + | 3 | | 5 | | | + +---+ +---+ +-----+ + +(Note that the number of keys is the same, but key '5' is moved down and + the shape of key '4' is changed. Keys '1' to '3' are exactly the same.) + +The keys 1-4 report the same scan-code in HID in both layouts, even though +the keysym they produce is usually different depending on the XKB-keymap +used by user-space. +However, key '5' (US 'backslash'/'pipe') reports 0x31 for the upper layout +and 0x32 for the lower layout, as defined by the HID spec. This is highly +confusing as the linux-input API uses a single keycode for both. + +So far, this was never a problem as there never has been a keyboard with +both of those keys present at the same time. It would have to look +something like this: + + +---+ +---+ +-------+ + | 1 | | 2 | | x31 | + +---+ +---+ +-------+ + +---+ +---+ +-----+ + | 3 | |x32| | 4 | + +---+ +---+ +-----+ + +HID can represent such a keyboard, but the linux-input API cannot. +Furthermore, any user-space mapping would be confused by this and, +luckily, no-one ever produced such hardware. + +Now, the HID input layer fixed this mess by mapping both 0x31 and 0x32 to +the same keycode (KEY_BACKSLASH==0x2b). As only one of both physical keys +is present on a hardware, this works just fine. + +Lets introduce hardware-vendors into this: +------------------------------------------ + +Unfortunately, it seems way to expensive to produce a different device for +American and European layouts. Therefore, hardware-vendors put both keys, +(0x31 and 0x32) on the same keyboard, but only one of them is hooked up +to the physical button, the other one is 'dead'. +This means, they can use the same hardware, with a different button-layout +and automatically produce the correct HID events for American *and* +European layouts. This is unproblematic for normal keyboards, as the +'dead' key will never report any KEY-DOWN events. But RollOver keyboards +send the whole matrix on each key-event, allowing n-key roll-over mode. +This means, we get a 0x31 and 0x32 event on each key-press. One of them +will always be 0, the other reports the real state. As we map both to the +same keycode, we will get spurious key-events, even though the real +key-state never changed. + +The easiest way would be to blacklist 'dead' keys and never handle those. +We could simply read the 'country' tag of USB devices and blacklist either +key according to the layout. But... hardware vendors... want the same +device for all countries and thus many of them set 'country' to 0 for all +devices. Meh.. + +So we have to deal with this properly. As we cannot know which of the keys +is 'dead', we either need a heuristic and track those keys, or we simply +make use of our value-tracking for HID fields. We simply ignore HID events +for absolute data if the data didn't change. As HID tracks events on the +HID level, we haven't done the keycode translation, yet. Therefore, the +'dead' key is tracked independently of the real key, therefore, any events +on it will be ignored. + +This patch simply discards any HID events for absolute data if it didn't +change compared to the last report. We need to ignore relative and +buffered-byte reports for obvious reasons. But those cannot be affected by +this bug, so we're fine. + +Preferably, we'd do this filtering on the HID-core level. But this might +break a lot of custom drivers, if they do not follow the HID specs. +Therefore, we do this late in hid-input just before we inject it into the +input layer (which does the exact same filtering, but on the keycode +level). + +If this turns out to break some devices, we might have to limit filtering +to EV_KEY events. But lets try to do the Right Thing first, and properly +filter any absolute data that didn't change. + +This patch is tagged for 'stable' as it fixes a lot of n-key RollOver +hardware. We might wanna wait with backporting for a while, before we know +it doesn't break anything else, though. + +Reported-by: Adam Goode +Reported-by: Fredrik Hallenberg +Tested-by: Fredrik Hallenberg +Signed-off-by: David Herrmann +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hid/hid-input.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/drivers/hid/hid-input.c ++++ b/drivers/hid/hid-input.c +@@ -1066,6 +1066,22 @@ void hidinput_hid_event(struct hid_devic + return; + } + ++ /* ++ * Ignore reports for absolute data if the data didn't change. This is ++ * not only an optimization but also fixes 'dead' key reports. Some ++ * RollOver implementations for localized keys (like BACKSLASH/PIPE; HID ++ * 0x31 and 0x32) report multiple keys, even though a localized keyboard ++ * can only have one of them physically available. The 'dead' keys ++ * report constant 0. As all map to the same keycode, they'd confuse ++ * the input layer. If we filter the 'dead' keys on the HID level, we ++ * skip the keycode translation and only forward real events. ++ */ ++ if (!(field->flags & (HID_MAIN_ITEM_RELATIVE | ++ HID_MAIN_ITEM_BUFFERED_BYTE)) && ++ usage->usage_index < field->maxusage && ++ value == field->value[usage->usage_index]) ++ return; ++ + /* report the usage code as scancode if the key status has changed */ + if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) + input_event(input, EV_MSC, MSC_SCAN, usage->hid); diff --git a/queue-3.10/series b/queue-3.10/series index 5f4c7c4a61d..d686cac0e25 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -49,3 +49,11 @@ nilfs2-fix-potential-memory-overrun-on-inode.patch fixed-invalid-assignment-of-64bit-mask-to-host-dma_boundary-for-scatter-gather-segment-boundary-limit.patch clk-sunxi-support-factor-clocks-with-n-factor-starting-not-from-0.patch staging-comedi-comedi_compat32.c-fix-comedi_cmd-copy-back.patch +dm-mirror-do-not-degrade-the-mirror-on-discard-error.patch +dm-io-reject-unsupported-discard-requests-with-eopnotsupp.patch +dm-fix-a-race-condition-in-dm_get_md.patch +dm-snapshot-fix-a-possible-invalid-memory-access-on-unload.patch +staging-comedi-cb_pcidas64-fix-incorrect-ai-range-code-handling.patch +hid-input-fix-confusion-on-conflicting-mappings.patch +hid-fixup-the-conflicting-keyboard-mappings-quirk.patch +drivers-hv-vmbus-incorrect-device-name-is-printed-when-child-device-is-unregistered.patch diff --git a/queue-3.10/staging-comedi-cb_pcidas64-fix-incorrect-ai-range-code-handling.patch b/queue-3.10/staging-comedi-cb_pcidas64-fix-incorrect-ai-range-code-handling.patch new file mode 100644 index 00000000000..94db9de39e1 --- /dev/null +++ b/queue-3.10/staging-comedi-cb_pcidas64-fix-incorrect-ai-range-code-handling.patch @@ -0,0 +1,388 @@ +From be8e89087ec2d2c8a1ad1e3db64bf4efdfc3c298 Mon Sep 17 00:00:00 2001 +From: Ian Abbott +Date: Mon, 19 Jan 2015 14:47:27 +0000 +Subject: staging: comedi: cb_pcidas64: fix incorrect AI range code handling + +From: Ian Abbott + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 +@@ -455,6 +455,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, +@@ -466,6 +489,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, +@@ -487,6 +514,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, +@@ -509,6 +541,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, +@@ -616,6 +653,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 */ +@@ -674,6 +712,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, +@@ -689,6 +728,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, +@@ -703,7 +743,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, +@@ -718,7 +759,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, +@@ -733,7 +775,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, +@@ -748,6 +791,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, +@@ -763,6 +807,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, +@@ -777,6 +822,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, +@@ -792,6 +838,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, +@@ -807,6 +854,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, +@@ -822,6 +870,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, +@@ -835,6 +884,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, + }, +@@ -846,6 +896,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, + }, +@@ -858,6 +909,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, + }, +@@ -871,6 +923,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, +@@ -886,6 +939,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, +@@ -901,6 +955,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, +@@ -916,6 +971,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, +@@ -931,6 +987,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, +@@ -946,6 +1003,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, +@@ -980,6 +1038,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, + }, +@@ -991,7 +1050,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, + }, +@@ -1003,7 +1063,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, + }, +@@ -1015,7 +1076,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, + }, +@@ -1027,7 +1089,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, + }, +@@ -1039,7 +1102,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, + }, +@@ -1051,7 +1115,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, + }, +@@ -1148,45 +1213,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,