--- /dev/null
+From 2bec1f4a8832e74ebbe859f176d8a9cb20dd97f4 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Tue, 17 Feb 2015 14:30:53 -0500
+Subject: dm: fix a race condition in dm_get_md
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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)
--- /dev/null
+From 37527b869207ad4c208b1e13967d69b8bba1fbf9 Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Fri, 13 Feb 2015 11:05:37 -0800
+Subject: dm io: reject unsupported DISCARD requests with EOPNOTSUPP
+
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+
+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 <darrick.wong@oracle.com>
+Acked-by: "Martin K. Petersen" <martin.petersen@oracle.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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.
--- /dev/null
+From f2ed51ac64611d717d1917820a01930174c2f236 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Thu, 12 Feb 2015 10:09:20 -0500
+Subject: dm mirror: do not degrade the mirror on discard error
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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);
--- /dev/null
+From 22aa66a3ee5b61e0f4a0bfeabcaa567861109ec3 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Tue, 17 Feb 2015 14:34:00 -0500
+Subject: dm snapshot: fix a possible invalid memory access on unload
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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)
--- /dev/null
+From 84672369ffb98a51d4ddf74c20a23636da3ad615 Mon Sep 17 00:00:00 2001
+From: Fernando Soto <fsoto@bluecatnetworks.com>
+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 <fsoto@bluecatnetworks.com>
+
+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 <fsoto@bluecatnetworks.com>
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Cc: Joseph Salisbury <joseph.salisbury@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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));
+ }
+
+
--- /dev/null
+From 8e7b341037db1835ee6eea64663013cbfcf33575 Mon Sep 17 00:00:00 2001
+From: Jiri Kosina <jkosina@suse.cz>
+Date: Tue, 6 Jan 2015 22:34:19 +0100
+Subject: HID: fixup the conflicting keyboard mappings quirk
+
+From: Jiri Kosina <jkosina@suse.cz>
+
+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 <megahallon@gmail.com>
+Reported-by: David Herrmann <dh.herrmann@gmail.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
--- /dev/null
+From 6ce901eb61aa30ba8565c62049ee80c90728ef14 Mon Sep 17 00:00:00 2001
+From: David Herrmann <dh.herrmann@gmail.com>
+Date: Mon, 29 Dec 2014 15:21:26 +0100
+Subject: HID: input: fix confusion on conflicting mappings
+
+From: David Herrmann <dh.herrmann@gmail.com>
+
+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 <adam@spicenitz.org>
+Reported-by: Fredrik Hallenberg <megahallon@gmail.com>
+Tested-by: Fredrik Hallenberg <megahallon@gmail.com>
+Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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);
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
--- /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
+@@ -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,