ARM64: DTS: Add rk3399-firefly uart4 device, node as /dev/ttyS1
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / cb_pcidas64.c
index c3e5495b4f06aa43b45ec8932ec0d88bee99865a..d33b8fe872a723d2b16987c118bab6ccaa67629f 100644 (file)
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-************************************************************************/
+*/
 
 /*
  * Driver: cb_pcidas64
@@ -85,27 +80,14 @@ TODO:
        make ao fifo size adjustable like ai fifo
 */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/pci.h>
+#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 
-#include "../comedidev.h"
+#include "../comedi_pci.h"
 
-#include "8253.h"
 #include "8255.h"
 #include "plx9080.h"
-#include "comedi_fc.h"
-
-#undef PCIDAS64_DEBUG          /*  disable debugging code */
-/* #define PCIDAS64_DEBUG         enable debugging code */
-
-#ifdef PCIDAS64_DEBUG
-#define DEBUG_PRINT(format, args...)  pr_debug(format, ## args)
-#else
-#define DEBUG_PRINT(format, args...)  no_printk(format, ## args)
-#endif
 
 #define TIMER_BASE 25          /*  40MHz master clock */
 /* 100kHz 'prescaled' clock for slow acquisition,
@@ -173,8 +155,10 @@ static inline unsigned int dac_msb_4020_reg(unsigned int channel)
 }
 
 enum read_only_registers {
-       /*  hardware status register,
-        *  reading this apparently clears pending interrupts as well */
+       /*
+        * hardware status register,
+        * reading this apparently clears pending interrupts as well
+        */
        HW_STATUS_REG = 0x0,
        PIPE1_READ_REG = 0x4,
        ADC_READ_PNTR_REG = 0x8,
@@ -192,7 +176,7 @@ enum read_write_registers {
        DAC_FIFO_REG = 0x300,
 };
 
-/* devpriv->dio_counter_iobase registers */
+/* dev->mmio registers */
 enum dio_counter_registers {
        DIO_8255_OFFSET = 0x0,
        DO_REG = 0x20,
@@ -261,7 +245,8 @@ enum adc_control0_contents {
        ADC_SOFT_GATE_BITS = 0x1,       /*  software gate */
        ADC_EXT_GATE_BITS = 0x2,        /*  external digital gate */
        ADC_ANALOG_GATE_BITS = 0x3,     /*  analog level gate */
-       ADC_GATE_LEVEL_BIT = 0x4,       /*  level-sensitive gate (for digital) */
+       /*  level-sensitive gate (for digital) */
+       ADC_GATE_LEVEL_BIT = 0x4,
        ADC_GATE_POLARITY_BIT = 0x8,    /*  gate active low */
        ADC_START_TRIG_SOFT_BITS = 0x10,
        ADC_START_TRIG_EXT_BITS = 0x20,
@@ -318,7 +303,8 @@ enum calibration_contents {
        CAL_GAIN_BIT = 0x800,
 };
 
-/* calibration sources for 6025 are:
+/*
+ * calibration sources for 6025 are:
  *  0 : ground
  *  1 : 10V
  *  2 : 5V
@@ -442,91 +428,122 @@ static inline uint8_t attenuate_bit(unsigned int channel)
 
 /* analog input ranges for 64xx boards */
 static const struct comedi_lrange ai_ranges_64xx = {
-       8,
-       {
-        BIP_RANGE(10),
-        BIP_RANGE(5),
-        BIP_RANGE(2.5),
-        BIP_RANGE(1.25),
-        UNI_RANGE(10),
-        UNI_RANGE(5),
-        UNI_RANGE(2.5),
-        UNI_RANGE(1.25)
-        }
+       8, {
+               BIP_RANGE(10),
+               BIP_RANGE(5),
+               BIP_RANGE(2.5),
+               BIP_RANGE(1.25),
+               UNI_RANGE(10),
+               UNI_RANGE(5),
+               UNI_RANGE(2.5),
+               UNI_RANGE(1.25)
+       }
+};
+
+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,
-       {
-        BIP_RANGE(10),
-        BIP_RANGE(5),
-        BIP_RANGE(0.5),
-        BIP_RANGE(0.05),
-        }
+       4, {
+               BIP_RANGE(10),
+               BIP_RANGE(5),
+               BIP_RANGE(0.5),
+               BIP_RANGE(0.05)
+       }
+};
+
+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,
-       {
-        BIP_RANGE(10),
-        BIP_RANGE(5),
-        BIP_RANGE(2),
-        BIP_RANGE(1),
-        BIP_RANGE(0.5),
-        BIP_RANGE(0.2),
-        BIP_RANGE(0.1),
-        UNI_RANGE(10),
-        UNI_RANGE(5),
-        UNI_RANGE(2),
-        UNI_RANGE(1),
-        UNI_RANGE(0.5),
-        UNI_RANGE(0.2),
-        UNI_RANGE(0.1),
-        }
+       14, {
+               BIP_RANGE(10),
+               BIP_RANGE(5),
+               BIP_RANGE(2),
+               BIP_RANGE(1),
+               BIP_RANGE(0.5),
+               BIP_RANGE(0.2),
+               BIP_RANGE(0.1),
+               UNI_RANGE(10),
+               UNI_RANGE(5),
+               UNI_RANGE(2),
+               UNI_RANGE(1),
+               UNI_RANGE(0.5),
+               UNI_RANGE(0.2),
+               UNI_RANGE(0.1)
+       }
+};
+
+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,
-       {
-        BIP_RANGE(10),
-        BIP_RANGE(5),
-        BIP_RANGE(2.5),
-        BIP_RANGE(1),
-        BIP_RANGE(0.5),
-        BIP_RANGE(0.25),
-        BIP_RANGE(0.1),
-        BIP_RANGE(0.05),
-        UNI_RANGE(10),
-        UNI_RANGE(5),
-        UNI_RANGE(2),
-        UNI_RANGE(1),
-        UNI_RANGE(0.5),
-        UNI_RANGE(0.2),
-        UNI_RANGE(0.1),
-        }
+       15, {
+               BIP_RANGE(10),
+               BIP_RANGE(5),
+               BIP_RANGE(2.5),
+               BIP_RANGE(1),
+               BIP_RANGE(0.5),
+               BIP_RANGE(0.25),
+               BIP_RANGE(0.1),
+               BIP_RANGE(0.05),
+               UNI_RANGE(10),
+               UNI_RANGE(5),
+               UNI_RANGE(2),
+               UNI_RANGE(1),
+               UNI_RANGE(0.5),
+               UNI_RANGE(0.2),
+               UNI_RANGE(0.1)
+       }
+};
+
+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,
-       {
-        BIP_RANGE(5),
-        BIP_RANGE(1),
-        }
+       2, {
+               BIP_RANGE(5),
+               BIP_RANGE(1)
+       }
 };
 
 /* analog output ranges */
 static const struct comedi_lrange ao_ranges_64xx = {
-       4,
-       {
-        BIP_RANGE(5),
-        BIP_RANGE(10),
-        UNI_RANGE(5),
-        UNI_RANGE(10),
-        }
+       4, {
+               BIP_RANGE(5),
+               BIP_RANGE(10),
+               UNI_RANGE(5),
+               UNI_RANGE(10)
+       }
 };
 
 static const int ao_range_code_64xx[] = {
@@ -541,11 +558,10 @@ static const int ao_range_code_60xx[] = {
 };
 
 static const struct comedi_lrange ao_ranges_6030 = {
-       2,
-       {
-        BIP_RANGE(10),
-        UNI_RANGE(10),
-        }
+       2, {
+               BIP_RANGE(10),
+               UNI_RANGE(10)
+       }
 };
 
 static const int ao_range_code_6030[] = {
@@ -554,11 +570,10 @@ static const int ao_range_code_6030[] = {
 };
 
 static const struct comedi_lrange ao_ranges_4020 = {
-       2,
-       {
-        BIP_RANGE(5),
-        BIP_RANGE(10),
-        }
+       2, {
+               BIP_RANGE(5),
+               BIP_RANGE(10)
+       }
 };
 
 static const int ao_range_code_4020[] = {
@@ -616,6 +631,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 */
@@ -648,8 +664,10 @@ static const struct hw_fifo_info ai_fifo_60xx = {
        .fifo_size_reg_mask = 0x7f,
 };
 
-/* maximum number of dma transfers we will chain together into a ring
- * (and the maximum number of dma buffers we maintain) */
+/*
+ * maximum number of dma transfers we will chain together into a ring
+ * (and the maximum number of dma buffers we maintain)
+ */
 #define MAX_AI_DMA_RING_COUNT (0x80000 / DMA_BUFFER_SIZE)
 #define MIN_AI_DMA_RING_COUNT (0x10000 / DMA_BUFFER_SIZE)
 #define AO_DMA_RING_COUNT (0x10000 / DMA_BUFFER_SIZE)
@@ -657,8 +675,8 @@ static inline unsigned int ai_dma_ring_count(const struct pcidas64_board *board)
 {
        if (board->layout == LAYOUT_4020)
                return MAX_AI_DMA_RING_COUNT;
-       else
-               return MIN_AI_DMA_RING_COUNT;
+
+       return MIN_AI_DMA_RING_COUNT;
 }
 
 static const int bytes_in_sample = 2;
@@ -674,6 +692,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +708,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +723,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +739,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +755,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +771,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +787,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +802,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +818,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +834,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +850,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +864,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +876,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +889,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +903,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +919,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +935,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +951,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +967,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +983,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +1018,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +1030,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +1043,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +1056,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +1069,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +1082,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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 +1095,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
                .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,
        },
@@ -1061,14 +1106,14 @@ static const struct pcidas64_board pcidas64_boards[] = {
 static inline unsigned short se_diff_bit_6xxx(struct comedi_device *dev,
                                              int use_differential)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
 
-       if ((thisboard->layout == LAYOUT_64XX && !use_differential) ||
-           (thisboard->layout == LAYOUT_60XX && use_differential))
+       if ((board->layout == LAYOUT_64XX && !use_differential) ||
+           (board->layout == LAYOUT_60XX && use_differential))
                return ADC_SE_DIFF_BIT;
-       else
-               return 0;
-};
+
+       return 0;
+}
 
 struct ext_clock_info {
        /*  master clock divisor to use for scans with external master clock */
@@ -1085,12 +1130,9 @@ struct pcidas64_private {
        /*  base addresses (ioremapped) */
        void __iomem *plx9080_iobase;
        void __iomem *main_iobase;
-       void __iomem *dio_counter_iobase;
        /*  local address (used by dma controller) */
        uint32_t local0_iobase;
        uint32_t local1_iobase;
-       /*  number of analog input samples remaining */
-       volatile unsigned int ai_count;
        /*  dma buffers for analog input */
        uint16_t *ai_buffer[MAX_AI_DMA_RING_COUNT];
        /*  physical addresses of ai dma buffers */
@@ -1102,7 +1144,7 @@ struct pcidas64_private {
        dma_addr_t ai_dma_desc_bus_addr;
        /*  index of the ai dma descriptor/buffer
         *  that is currently being used */
-       volatile unsigned int ai_dma_index;
+       unsigned int ai_dma_index;
        /*  dma buffers for analog output */
        uint16_t *ao_buffer[AO_DMA_RING_COUNT];
        /*  physical addresses of ao dma buffers */
@@ -1110,107 +1152,63 @@ struct pcidas64_private {
        struct plx_dma_desc *ao_dma_desc;
        dma_addr_t ao_dma_desc_bus_addr;
        /*  keeps track of buffer where the next ao sample should go */
-       volatile unsigned int ao_dma_index;
-       /*  number of analog output samples remaining */
-       volatile unsigned long ao_count;
-       /*  remember what the analog outputs are set to, to allow readback */
-       volatile unsigned int ao_value[2];
+       unsigned int ao_dma_index;
        unsigned int hw_revision;       /*  stc chip hardware revision number */
        /*  last bits sent to INTR_ENABLE_REG register */
-       volatile unsigned int intr_enable_bits;
+       unsigned int intr_enable_bits;
        /*  last bits sent to ADC_CONTROL1_REG register */
-       volatile uint16_t adc_control1_bits;
+       uint16_t adc_control1_bits;
        /*  last bits sent to FIFO_SIZE_REG register */
-       volatile uint16_t fifo_size_bits;
+       uint16_t fifo_size_bits;
        /*  last bits sent to HW_CONFIG_REG register */
-       volatile uint16_t hw_config_bits;
-       volatile uint16_t dac_control1_bits;
+       uint16_t hw_config_bits;
+       uint16_t dac_control1_bits;
        /*  last bits written to plx9080 control register */
-       volatile uint32_t plx_control_bits;
+       uint32_t plx_control_bits;
        /*  last bits written to plx interrupt control and status register */
-       volatile uint32_t plx_intcsr_bits;
+       uint32_t plx_intcsr_bits;
        /*  index of calibration source readable through ai ch0 */
-       volatile int calibration_source;
+       int calibration_source;
        /*  bits written to i2c calibration/range register */
-       volatile uint8_t i2c_cal_range_bits;
+       uint8_t i2c_cal_range_bits;
        /*  configure digital triggers to trigger on falling edge */
-       volatile unsigned int ext_trig_falling;
-       /*  states of various devices stored to enable read-back */
-       unsigned int ad8402_state[2];
-       unsigned int caldac_state[8];
-       volatile short ai_cmd_running;
+       unsigned int ext_trig_falling;
+       short ai_cmd_running;
        unsigned int ai_fifo_segment_length;
        struct ext_clock_info ext_clock;
-       short ao_bounce_buffer[DAC_FIFO_SIZE];
+       unsigned short ao_bounce_buffer[DAC_FIFO_SIZE];
 };
 
 static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev,
                                       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;
+       const struct pcidas64_board *board = dev->board_ptr;
+
+       return board->ai_range_code[range_index] << 8;
 }
 
 static unsigned int hw_revision(const struct comedi_device *dev,
                                uint16_t hw_status_bits)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
 
-       if (thisboard->layout == LAYOUT_4020)
+       if (board->layout == LAYOUT_4020)
                return (hw_status_bits >> 13) & 0x7;
 
        return (hw_status_bits >> 12) & 0xf;
 }
 
 static void set_dac_range_bits(struct comedi_device *dev,
-                              volatile uint16_t *bits, unsigned int channel,
+                              uint16_t *bits, unsigned int channel,
                               unsigned int range)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
-       unsigned int code = thisboard->ao_range_code[range];
+       const struct pcidas64_board *board = dev->board_ptr;
+       unsigned int code = board->ao_range_code[range];
 
        if (channel > 1)
-               comedi_error(dev, "bug! bad channel?");
+               dev_err(dev->class_dev, "bug! bad channel?\n");
        if (code & ~0x3)
-               comedi_error(dev, "bug! bad range code?");
+               dev_err(dev->class_dev, "bug! bad range code?\n");
 
        *bits &= ~(0x3 << (2 * channel));
        *bits |= code << (2 * channel);
@@ -1256,39 +1254,38 @@ static void disable_ai_interrupts(struct comedi_device *dev)
        writew(devpriv->intr_enable_bits,
               devpriv->main_iobase + INTR_ENABLE_REG);
        spin_unlock_irqrestore(&dev->spinlock, flags);
-
-       DEBUG_PRINT("intr enable bits 0x%x\n", devpriv->intr_enable_bits);
 }
 
 static void enable_ai_interrupts(struct comedi_device *dev,
                                 const struct comedi_cmd *cmd)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        uint32_t bits;
        unsigned long flags;
 
        bits = EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT |
               EN_ADC_ACTIVE_INTR_BIT | EN_ADC_STOP_INTR_BIT;
-       /*  Use pio transfer and interrupt on end of conversion
-        *  if TRIG_WAKE_EOS flag is set. */
-       if (cmd->flags & TRIG_WAKE_EOS) {
+       /*
+        * Use pio transfer and interrupt on end of conversion
+        * if CMDF_WAKE_EOS flag is set.
+        */
+       if (cmd->flags & CMDF_WAKE_EOS) {
                /*  4020 doesn't support pio transfers except for fifo dregs */
-               if (thisboard->layout != LAYOUT_4020)
+               if (board->layout != LAYOUT_4020)
                        bits |= ADC_INTR_EOSCAN_BITS | EN_ADC_INTR_SRC_BIT;
        }
        spin_lock_irqsave(&dev->spinlock, flags);
        devpriv->intr_enable_bits |= bits;
        writew(devpriv->intr_enable_bits,
               devpriv->main_iobase + INTR_ENABLE_REG);
-       DEBUG_PRINT("intr enable bits 0x%x\n", devpriv->intr_enable_bits);
        spin_unlock_irqrestore(&dev->spinlock, flags);
 }
 
 /* initialize plx9080 chip */
 static void init_plx9080(struct comedi_device *dev)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        uint32_t bits;
        void __iomem *plx_iobase = devpriv->plx9080_iobase;
@@ -1296,38 +1293,6 @@ static void init_plx9080(struct comedi_device *dev)
        devpriv->plx_control_bits =
                readl(devpriv->plx9080_iobase + PLX_CONTROL_REG);
 
-       /*  plx9080 dump */
-       DEBUG_PRINT(" plx interrupt status 0x%x\n",
-                   readl(plx_iobase + PLX_INTRCS_REG));
-       DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG));
-       DEBUG_PRINT(" plx control reg 0x%x\n", devpriv->plx_control_bits);
-       DEBUG_PRINT(" plx mode/arbitration reg 0x%x\n",
-                   readl(plx_iobase + PLX_MARB_REG));
-       DEBUG_PRINT(" plx region0 reg 0x%x\n",
-                   readl(plx_iobase + PLX_REGION0_REG));
-       DEBUG_PRINT(" plx region1 reg 0x%x\n",
-                   readl(plx_iobase + PLX_REGION1_REG));
-
-       DEBUG_PRINT(" plx revision 0x%x\n",
-                   readl(plx_iobase + PLX_REVISION_REG));
-       DEBUG_PRINT(" plx dma channel 0 mode 0x%x\n",
-                   readl(plx_iobase + PLX_DMA0_MODE_REG));
-       DEBUG_PRINT(" plx dma channel 1 mode 0x%x\n",
-                   readl(plx_iobase + PLX_DMA1_MODE_REG));
-       DEBUG_PRINT(" plx dma channel 0 pci address 0x%x\n",
-                   readl(plx_iobase + PLX_DMA0_PCI_ADDRESS_REG));
-       DEBUG_PRINT(" plx dma channel 0 local address 0x%x\n",
-                   readl(plx_iobase + PLX_DMA0_LOCAL_ADDRESS_REG));
-       DEBUG_PRINT(" plx dma channel 0 transfer size 0x%x\n",
-                   readl(plx_iobase + PLX_DMA0_TRANSFER_SIZE_REG));
-       DEBUG_PRINT(" plx dma channel 0 descriptor 0x%x\n",
-                   readl(plx_iobase + PLX_DMA0_DESCRIPTOR_REG));
-       DEBUG_PRINT(" plx dma channel 0 command status 0x%x\n",
-                   readb(plx_iobase + PLX_DMA0_CS_REG));
-       DEBUG_PRINT(" plx dma channel 0 threshold 0x%x\n",
-                   readl(plx_iobase + PLX_DMA0_THRESHOLD_REG));
-       DEBUG_PRINT(" plx bigend 0x%x\n", readl(plx_iobase + PLX_BIGEND_REG));
-
 #ifdef __BIG_ENDIAN
        bits = BIGEND_DMA0 | BIGEND_DMA1;
 #else
@@ -1361,12 +1326,12 @@ static void init_plx9080(struct comedi_device *dev)
        /*  enable local burst mode */
        bits |= PLX_DMA_LOCAL_BURST_EN_BIT;
        /*  4020 uses 32 bit dma */
-       if (thisboard->layout == LAYOUT_4020)
+       if (board->layout == LAYOUT_4020)
                bits |= PLX_LOCAL_BUS_32_WIDE_BITS;
        else            /*  localspace0 bus is 16 bits wide */
                bits |= PLX_LOCAL_BUS_16_WIDE_BITS;
        writel(bits, plx_iobase + PLX_DMA1_MODE_REG);
-       if (ao_cmd_is_supported(thisboard))
+       if (ao_cmd_is_supported(board))
                writel(bits, plx_iobase + PLX_DMA0_MODE_REG);
 
        /*  enable interrupts on plx 9080 */
@@ -1398,10 +1363,10 @@ static void disable_ai_pacing(struct comedi_device *dev)
 static int set_ai_fifo_segment_length(struct comedi_device *dev,
                                      unsigned int num_entries)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        static const int increment_size = 0x100;
-       const struct hw_fifo_info *const fifo = thisboard->ai_fifo;
+       const struct hw_fifo_info *const fifo = board->ai_fifo;
        unsigned int num_increments;
        uint16_t bits;
 
@@ -1421,19 +1386,18 @@ static int set_ai_fifo_segment_length(struct comedi_device *dev,
 
        devpriv->ai_fifo_segment_length = num_increments * increment_size;
 
-       DEBUG_PRINT("set hardware fifo segment length to %i\n",
-                   devpriv->ai_fifo_segment_length);
-
        return devpriv->ai_fifo_segment_length;
 }
 
-/* adjusts the size of hardware fifo (which determines block size for dma xfers) */
+/*
+ * adjusts the size of hardware fifo (which determines block size for dma xfers)
+ */
 static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        unsigned int num_fifo_entries;
        int retval;
-       const struct hw_fifo_info *const fifo = thisboard->ai_fifo;
+       const struct hw_fifo_info *const fifo = board->ai_fifo;
 
        num_fifo_entries = num_samples / fifo->sample_packing_ratio;
 
@@ -1445,33 +1409,33 @@ static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples)
 
        num_samples = retval * fifo->num_segments * fifo->sample_packing_ratio;
 
-       DEBUG_PRINT("set hardware fifo size to %i\n", num_samples);
-
        return num_samples;
 }
 
 /* query length of fifo */
 static unsigned int ai_fifo_size(struct comedi_device *dev)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
 
        return devpriv->ai_fifo_segment_length *
-              thisboard->ai_fifo->num_segments *
-              thisboard->ai_fifo->sample_packing_ratio;
+              board->ai_fifo->num_segments *
+              board->ai_fifo->sample_packing_ratio;
 }
 
 static void init_stc_registers(struct comedi_device *dev)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        uint16_t bits;
        unsigned long flags;
 
        spin_lock_irqsave(&dev->spinlock, flags);
 
-       /*  bit should be set for 6025,
-        *  although docs say boards with <= 16 chans should be cleared XXX */
+       /*
+        * bit should be set for 6025,
+        * although docs say boards with <= 16 chans should be cleared XXX
+        */
        if (1)
                devpriv->adc_control1_bits |= ADC_QUEUE_CONFIG_BIT;
        writew(devpriv->adc_control1_bits,
@@ -1481,7 +1445,7 @@ static void init_stc_registers(struct comedi_device *dev)
        writew(0xff, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
 
        bits = SLOW_DAC_BIT | DMA_CH_SELECT_BIT;
-       if (thisboard->layout == LAYOUT_4020)
+       if (board->layout == LAYOUT_4020)
                bits |= INTERNAL_CLOCK_4020_BITS;
        devpriv->hw_config_bits |= bits;
        writew(devpriv->hw_config_bits,
@@ -1494,8 +1458,7 @@ static void init_stc_registers(struct comedi_device *dev)
 
        /*  set fifos to maximum size */
        devpriv->fifo_size_bits |= DAC_FIFO_BITS;
-       set_ai_fifo_segment_length(dev,
-                                  thisboard->ai_fifo->max_segment_length);
+       set_ai_fifo_segment_length(dev, board->ai_fifo->max_segment_length);
 
        devpriv->dac_control1_bits = DAC_OUTPUT_ENABLE_BIT;
        devpriv->intr_enable_bits =
@@ -1509,58 +1472,51 @@ static void init_stc_registers(struct comedi_device *dev)
 
 static int alloc_and_init_dma_members(struct comedi_device *dev)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
        struct pcidas64_private *devpriv = dev->private;
        int i;
 
        /*  allocate pci dma buffers */
-       for (i = 0; i < ai_dma_ring_count(thisboard); i++) {
+       for (i = 0; i < ai_dma_ring_count(board); i++) {
                devpriv->ai_buffer[i] =
                        pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE,
                                             &devpriv->ai_buffer_bus_addr[i]);
-               if (devpriv->ai_buffer[i] == NULL)
+               if (!devpriv->ai_buffer[i])
                        return -ENOMEM;
-
        }
        for (i = 0; i < AO_DMA_RING_COUNT; i++) {
-               if (ao_cmd_is_supported(thisboard)) {
+               if (ao_cmd_is_supported(board)) {
                        devpriv->ao_buffer[i] =
                                pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE,
                                                     &devpriv->
                                                      ao_buffer_bus_addr[i]);
-                       if (devpriv->ao_buffer[i] == NULL)
+                       if (!devpriv->ao_buffer[i])
                                return -ENOMEM;
-
                }
        }
        /*  allocate dma descriptors */
        devpriv->ai_dma_desc =
                pci_alloc_consistent(pcidev, sizeof(struct plx_dma_desc) *
-                                    ai_dma_ring_count(thisboard),
+                                    ai_dma_ring_count(board),
                                     &devpriv->ai_dma_desc_bus_addr);
-       if (devpriv->ai_dma_desc == NULL)
+       if (!devpriv->ai_dma_desc)
                return -ENOMEM;
 
-       DEBUG_PRINT("ai dma descriptors start at bus addr 0x%llx\n",
-                   (unsigned long long)devpriv->ai_dma_desc_bus_addr);
-       if (ao_cmd_is_supported(thisboard)) {
+       if (ao_cmd_is_supported(board)) {
                devpriv->ao_dma_desc =
                        pci_alloc_consistent(pcidev,
                                             sizeof(struct plx_dma_desc) *
                                             AO_DMA_RING_COUNT,
                                             &devpriv->ao_dma_desc_bus_addr);
-               if (devpriv->ao_dma_desc == NULL)
+               if (!devpriv->ao_dma_desc)
                        return -ENOMEM;
-
-               DEBUG_PRINT("ao dma descriptors start at bus addr 0x%llx\n",
-                           (unsigned long long)devpriv->ao_dma_desc_bus_addr);
        }
        /*  initialize dma descriptors */
-       for (i = 0; i < ai_dma_ring_count(thisboard); i++) {
+       for (i = 0; i < ai_dma_ring_count(board); i++) {
                devpriv->ai_dma_desc[i].pci_start_addr =
                        cpu_to_le32(devpriv->ai_buffer_bus_addr[i]);
-               if (thisboard->layout == LAYOUT_4020)
+               if (board->layout == LAYOUT_4020)
                        devpriv->ai_dma_desc[i].local_start_addr =
                                cpu_to_le32(devpriv->local1_iobase +
                                            ADC_FIFO_REG);
@@ -1571,12 +1527,12 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
                devpriv->ai_dma_desc[i].transfer_size = cpu_to_le32(0);
                devpriv->ai_dma_desc[i].next =
                        cpu_to_le32((devpriv->ai_dma_desc_bus_addr +
-                                    ((i + 1) % ai_dma_ring_count(thisboard)) *
+                                    ((i + 1) % ai_dma_ring_count(board)) *
                                     sizeof(devpriv->ai_dma_desc[0])) |
                                    PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT |
                                    PLX_XFER_LOCAL_TO_PCI);
        }
-       if (ao_cmd_is_supported(thisboard)) {
+       if (ao_cmd_is_supported(board)) {
                for (i = 0; i < AO_DMA_RING_COUNT; i++) {
                        devpriv->ao_dma_desc[i].pci_start_addr =
                                cpu_to_le32(devpriv->ao_buffer_bus_addr[i]);
@@ -1595,15 +1551,57 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
        return 0;
 }
 
+static void cb_pcidas64_free_dma(struct comedi_device *dev)
+{
+       const struct pcidas64_board *board = dev->board_ptr;
+       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+       struct pcidas64_private *devpriv = dev->private;
+       int i;
+
+       if (!devpriv)
+               return;
+
+       /* free pci dma buffers */
+       for (i = 0; i < ai_dma_ring_count(board); i++) {
+               if (devpriv->ai_buffer[i])
+                       pci_free_consistent(pcidev,
+                                           DMA_BUFFER_SIZE,
+                                           devpriv->ai_buffer[i],
+                                           devpriv->ai_buffer_bus_addr[i]);
+       }
+       for (i = 0; i < AO_DMA_RING_COUNT; i++) {
+               if (devpriv->ao_buffer[i])
+                       pci_free_consistent(pcidev,
+                                           DMA_BUFFER_SIZE,
+                                           devpriv->ao_buffer[i],
+                                           devpriv->ao_buffer_bus_addr[i]);
+       }
+       /* free dma descriptors */
+       if (devpriv->ai_dma_desc)
+               pci_free_consistent(pcidev,
+                                   sizeof(struct plx_dma_desc) *
+                                   ai_dma_ring_count(board),
+                                   devpriv->ai_dma_desc,
+                                   devpriv->ai_dma_desc_bus_addr);
+       if (devpriv->ao_dma_desc)
+               pci_free_consistent(pcidev,
+                                   sizeof(struct plx_dma_desc) *
+                                   AO_DMA_RING_COUNT,
+                                   devpriv->ao_dma_desc,
+                                   devpriv->ao_dma_desc_bus_addr);
+}
+
 static inline void warn_external_queue(struct comedi_device *dev)
 {
-       comedi_error(dev,
-                    "AO command and AI external channel queue cannot be used simultaneously.");
-       comedi_error(dev,
-                    "Use internal AI channel queue (channels must be consecutive and use same range/aref)");
+       dev_err(dev->class_dev,
+               "AO command and AI external channel queue cannot be used simultaneously\n");
+       dev_err(dev->class_dev,
+               "Use internal AI channel queue (channels must be consecutive and use same range/aref)\n");
 }
 
-/* Their i2c requires a huge delay on setting clock or data high for some reason */
+/*
+ * their i2c requires a huge delay on setting clock or data high for some reason
+ */
 static const int i2c_high_udelay = 1000;
 static const int i2c_low_udelay = 10;
 
@@ -1654,8 +1652,6 @@ static void i2c_write_byte(struct comedi_device *dev, uint8_t byte)
        uint8_t bit;
        unsigned int num_bits = 8;
 
-       DEBUG_PRINT("writing to i2c byte 0x%x\n", byte);
-
        for (bit = 1 << (num_bits - 1); bit; bit >>= 1) {
                i2c_set_scl(dev, 0);
                if ((byte & bit))
@@ -1701,8 +1697,10 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
        uint8_t bitstream;
        static const int read_bit = 0x1;
 
-       /* XXX need mutex to prevent simultaneous attempts to access
-        * eeprom and i2c bus */
+       /*
+        * XXX need mutex to prevent simultaneous attempts to access
+        * eeprom and i2c bus
+        */
 
        /*  make sure we dont send anything to eeprom */
        devpriv->plx_control_bits &= ~CTL_EE_CS;
@@ -1716,7 +1714,7 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
 
        /*  get acknowledge */
        if (i2c_read_ack(dev) != 0) {
-               comedi_error(dev, "i2c write failed: no acknowledge");
+               dev_err(dev->class_dev, "failed: no acknowledge\n");
                i2c_stop(dev);
                return;
        }
@@ -1724,7 +1722,7 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
        for (i = 0; i < length; i++) {
                i2c_write_byte(dev, data[i]);
                if (i2c_read_ack(dev) != 0) {
-                       comedi_error(dev, "i2c write failed: no acknowledge");
+                       dev_err(dev->class_dev, "failed: no acknowledge\n");
                        i2c_stop(dev);
                        return;
                }
@@ -1732,17 +1730,37 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
        i2c_stop(dev);
 }
 
+static int cb_pcidas64_ai_eoc(struct comedi_device *dev,
+                             struct comedi_subdevice *s,
+                             struct comedi_insn *insn,
+                             unsigned long context)
+{
+       const struct pcidas64_board *board = dev->board_ptr;
+       struct pcidas64_private *devpriv = dev->private;
+       unsigned int status;
+
+       status = readw(devpriv->main_iobase + HW_STATUS_REG);
+       if (board->layout == LAYOUT_4020) {
+               status = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG);
+               if (status)
+                       return 0;
+       } else {
+               if (pipe_full_bits(status))
+                       return 0;
+       }
+       return -EBUSY;
+}
+
 static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
                    struct comedi_insn *insn, unsigned int *data)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
-       unsigned int bits = 0, n, i;
+       unsigned int bits = 0, n;
        unsigned int channel, range, aref;
        unsigned long flags;
-       static const int timeout = 100;
+       int ret;
 
-       DEBUG_PRINT("chanspec 0x%x\n", insn->chanspec);
        channel = CR_CHAN(insn->chanspec);
        range = CR_RANGE(insn->chanspec);
        aref = CR_AREF(insn->chanspec);
@@ -1760,7 +1778,7 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
               devpriv->main_iobase + ADC_CONTROL1_REG);
        spin_unlock_irqrestore(&dev->spinlock, flags);
 
-       if (thisboard->layout != LAYOUT_4020) {
+       if (board->layout != LAYOUT_4020) {
                /*  use internal queue */
                devpriv->hw_config_bits &= ~EXT_QUEUE_BIT;
                writew(devpriv->hw_config_bits,
@@ -1770,19 +1788,22 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
                if (insn->chanspec & CR_ALT_SOURCE) {
                        unsigned int cal_en_bit;
 
-                       DEBUG_PRINT("reading calibration source\n");
-                       if (thisboard->layout == LAYOUT_60XX)
+                       if (board->layout == LAYOUT_60XX)
                                cal_en_bit = CAL_EN_60XX_BIT;
                        else
                                cal_en_bit = CAL_EN_64XX_BIT;
-                       /*  select internal reference source to connect
-                        *  to channel 0 */
+                       /*
+                        * select internal reference source to connect
+                        * to channel 0
+                        */
                        writew(cal_en_bit |
                               adc_src_bits(devpriv->calibration_source),
                               devpriv->main_iobase + CALIBRATION_REG);
                } else {
-                       /*  make sure internal calibration source
-                        *  is turned off */
+                       /*
+                        * make sure internal calibration source
+                        * is turned off
+                        */
                        writew(0, devpriv->main_iobase + CALIBRATION_REG);
                }
                /*  load internal queue */
@@ -1804,7 +1825,6 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 
                devpriv->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK;
                if (insn->chanspec & CR_ALT_SOURCE) {
-                       DEBUG_PRINT("reading calibration source\n");
                        devpriv->i2c_cal_range_bits |=
                                adc_src_4020_bits(devpriv->calibration_source);
                } else {        /* select BNC inputs */
@@ -1815,24 +1835,28 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
                        devpriv->i2c_cal_range_bits |= attenuate_bit(channel);
                else
                        devpriv->i2c_cal_range_bits &= ~attenuate_bit(channel);
-               /*  update calibration/range i2c register only if necessary,
-                *  as it is very slow */
+               /*
+                * update calibration/range i2c register only if necessary,
+                * as it is very slow
+                */
                if (old_cal_range_bits != devpriv->i2c_cal_range_bits) {
                        uint8_t i2c_data = devpriv->i2c_cal_range_bits;
+
                        i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data,
                                  sizeof(i2c_data));
                }
 
-               /* 4020 manual asks that sample interval register to be set
+               /*
+                * 4020 manual asks that sample interval register to be set
                 * before writing to convert register.
                 * Using somewhat arbitrary setting of 4 master clock ticks
-                * = 0.1 usec */
+                * = 0.1 usec
+                */
                writew(0, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
                writew(2, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG);
        }
 
        for (n = 0; n < insn->n; n++) {
-
                /*  clear adc buffer (inside loop for 4020 sake) */
                writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG);
 
@@ -1841,28 +1865,12 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
                       devpriv->main_iobase + ADC_CONVERT_REG);
 
                /*  wait for data */
-               for (i = 0; i < timeout; i++) {
-                       bits = readw(devpriv->main_iobase + HW_STATUS_REG);
-                       DEBUG_PRINT(" pipe bits 0x%x\n", pipe_full_bits(bits));
-                       if (thisboard->layout == LAYOUT_4020) {
-                               if (readw(devpriv->main_iobase +
-                                         ADC_WRITE_PNTR_REG))
-                                       break;
-                       } else {
-                               if (pipe_full_bits(bits))
-                                       break;
-                       }
-                       udelay(1);
-               }
-               DEBUG_PRINT(" looped %i times waiting for data\n", i);
-               if (i == timeout) {
-                       comedi_error(dev, " analog input read insn timed out");
-                       dev_info(dev->class_dev, "status 0x%x\n", bits);
-                       return -ETIME;
-               }
-               if (thisboard->layout == LAYOUT_4020)
-                       data[n] = readl(devpriv->dio_counter_iobase +
-                                       ADC_FIFO_REG) & 0xffff;
+               ret = comedi_timeout(dev, s, insn, cb_pcidas64_ai_eoc, 0);
+               if (ret)
+                       return ret;
+
+               if (board->layout == LAYOUT_4020)
+                       data[n] = readl(dev->mmio + ADC_FIFO_REG) & 0xffff;
                else
                        data[n] = readw(devpriv->main_iobase + PIPE1_READ_REG);
        }
@@ -1873,12 +1881,12 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
 static int ai_config_calibration_source(struct comedi_device *dev,
                                        unsigned int *data)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        unsigned int source = data[1];
        int num_calibration_sources;
 
-       if (thisboard->layout == LAYOUT_60XX)
+       if (board->layout == LAYOUT_60XX)
                num_calibration_sources = 16;
        else
                num_calibration_sources = 8;
@@ -1888,7 +1896,6 @@ static int ai_config_calibration_source(struct comedi_device *dev,
                return -EINVAL;
        }
 
-       DEBUG_PRINT("setting calibration source to %i\n", source);
        devpriv->calibration_source = source;
 
        return 2;
@@ -1896,9 +1903,9 @@ static int ai_config_calibration_source(struct comedi_device *dev,
 
 static int ai_config_block_size(struct comedi_device *dev, unsigned int *data)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        int fifo_size;
-       const struct hw_fifo_info *const fifo = thisboard->ai_fifo;
+       const struct hw_fifo_info *const fifo = board->ai_fifo;
        unsigned int block_size, requested_block_size;
        int retval;
 
@@ -1911,7 +1918,6 @@ static int ai_config_block_size(struct comedi_device *dev, unsigned int *data)
                retval = set_ai_fifo_size(dev, fifo_size);
                if (retval < 0)
                        return retval;
-
        }
 
        block_size = ai_fifo_size(dev) / fifo->num_segments * bytes_in_sample;
@@ -1940,7 +1946,6 @@ static int ai_config_master_clock_4020(struct comedi_device *dev,
                break;
        default:
                return -EINVAL;
-               break;
        }
 
        data[4] = divisor;
@@ -1951,15 +1956,13 @@ static int ai_config_master_clock_4020(struct comedi_device *dev,
 /* XXX could add support for 60xx series */
 static int ai_config_master_clock(struct comedi_device *dev, unsigned int *data)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
 
-       switch (thisboard->layout) {
+       switch (board->layout) {
        case LAYOUT_4020:
                return ai_config_master_clock_4020(dev, data);
-               break;
        default:
                return -EINVAL;
-               break;
        }
 
        return -EINVAL;
@@ -1973,35 +1976,33 @@ static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s,
        switch (id) {
        case INSN_CONFIG_ALT_SOURCE:
                return ai_config_calibration_source(dev, data);
-               break;
        case INSN_CONFIG_BLOCK_SIZE:
                return ai_config_block_size(dev, data);
-               break;
        case INSN_CONFIG_TIMER_1:
                return ai_config_master_clock(dev, data);
-               break;
        default:
                return -EINVAL;
-               break;
        }
        return -EINVAL;
 }
 
-/* Gets nearest achievable timing given master clock speed, does not
+/*
+ * Gets nearest achievable timing given master clock speed, does not
  * take into account possible minimum/maximum divisor values.  Used
- * by other timing checking functions. */
+ * by other timing checking functions.
+ */
 static unsigned int get_divisor(unsigned int ns, unsigned int flags)
 {
        unsigned int divisor;
 
-       switch (flags & TRIG_ROUND_MASK) {
-       case TRIG_ROUND_UP:
+       switch (flags & CMDF_ROUND_MASK) {
+       case CMDF_ROUND_UP:
                divisor = (ns + TIMER_BASE - 1) / TIMER_BASE;
                break;
-       case TRIG_ROUND_DOWN:
+       case CMDF_ROUND_DOWN:
                divisor = ns / TIMER_BASE;
                break;
-       case TRIG_ROUND_NEAREST:
+       case CMDF_ROUND_NEAREST:
        default:
                divisor = (ns + TIMER_BASE / 2) / TIMER_BASE;
                break;
@@ -2009,14 +2010,17 @@ static unsigned int get_divisor(unsigned int ns, unsigned int flags)
        return divisor;
 }
 
-/* utility function that rounds desired timing to an achievable time, and
+/*
+ * utility function that rounds desired timing to an achievable time, and
  * sets cmd members appropriately.
- * adc paces conversions from master clock by dividing by (x + 3) where x is 24 bit number
+ * adc paces conversions from master clock by dividing by (x + 3) where x is
+ * 24 bit number
  */
 static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
-       unsigned int convert_divisor = 0, scan_divisor;
+       const struct pcidas64_board *board = dev->board_ptr;
+       unsigned long long convert_divisor = 0;
+       unsigned int scan_divisor;
        static const int min_convert_divisor = 3;
        static const int max_convert_divisor =
                max_counter_value + min_convert_divisor;
@@ -2024,7 +2028,7 @@ static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
        unsigned long long max_scan_divisor, min_scan_divisor;
 
        if (cmd->convert_src == TRIG_TIMER) {
-               if (thisboard->layout == LAYOUT_4020) {
+               if (board->layout == LAYOUT_4020) {
                        cmd->convert_arg = 0;
                } else {
                        convert_divisor = get_divisor(cmd->convert_arg,
@@ -2042,7 +2046,6 @@ static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
        if (cmd->scan_begin_src == TRIG_TIMER) {
                scan_divisor = get_divisor(cmd->scan_begin_arg, cmd->flags);
                if (cmd->convert_src == TRIG_TIMER) {
-                       /*  XXX check for integer overflows */
                        min_scan_divisor = convert_divisor * cmd->chanlist_len;
                        max_scan_divisor =
                                (convert_divisor * cmd->chanlist_len - 1) +
@@ -2057,90 +2060,141 @@ static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
                        scan_divisor = min_scan_divisor;
                cmd->scan_begin_arg = scan_divisor * TIMER_BASE;
        }
+}
+
+static int cb_pcidas64_ai_check_chanlist(struct comedi_device *dev,
+                                        struct comedi_subdevice *s,
+                                        struct comedi_cmd *cmd)
+{
+       const struct pcidas64_board *board = dev->board_ptr;
+       unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
+       int i;
 
-       return;
+       for (i = 1; i < cmd->chanlist_len; i++) {
+               unsigned int aref = CR_AREF(cmd->chanlist[i]);
+
+               if (aref != aref0) {
+                       dev_dbg(dev->class_dev,
+                               "all elements in chanlist must use the same analog reference\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (board->layout == LAYOUT_4020) {
+               unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+
+               for (i = 1; i < cmd->chanlist_len; i++) {
+                       unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
+                       if (chan != (chan0 + i)) {
+                               dev_dbg(dev->class_dev,
+                                       "chanlist must use consecutive channels\n");
+                               return -EINVAL;
+                       }
+               }
+               if (cmd->chanlist_len == 3) {
+                       dev_dbg(dev->class_dev,
+                               "chanlist cannot be 3 channels long, use 1, 2, or 4 channels\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
 }
 
 static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
                      struct comedi_cmd *cmd)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        int err = 0;
        unsigned int tmp_arg, tmp_arg2;
-       int i;
-       int aref;
        unsigned int triggers;
 
        /* Step 1 : check if triggers are trivially valid */
 
-       err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
+       err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
 
        triggers = TRIG_TIMER;
-       if (thisboard->layout == LAYOUT_4020)
+       if (board->layout == LAYOUT_4020)
                triggers |= TRIG_OTHER;
        else
                triggers |= TRIG_FOLLOW;
-       err |= cfc_check_trigger_src(&cmd->scan_begin_src, triggers);
+       err |= comedi_check_trigger_src(&cmd->scan_begin_src, triggers);
 
        triggers = TRIG_TIMER;
-       if (thisboard->layout == LAYOUT_4020)
+       if (board->layout == LAYOUT_4020)
                triggers |= TRIG_NOW;
        else
                triggers |= TRIG_EXT;
-       err |= cfc_check_trigger_src(&cmd->convert_src, triggers);
-       err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
-       err |= cfc_check_trigger_src(&cmd->stop_src,
-                                    TRIG_COUNT | TRIG_EXT | TRIG_NONE);
+       err |= comedi_check_trigger_src(&cmd->convert_src, triggers);
+       err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+       err |= comedi_check_trigger_src(&cmd->stop_src,
+                                       TRIG_COUNT | TRIG_EXT | TRIG_NONE);
 
        if (err)
                return 1;
 
        /* Step 2a : make sure trigger sources are unique */
 
-       err |= cfc_check_trigger_is_unique(cmd->start_src);
-       err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
-       err |= cfc_check_trigger_is_unique(cmd->convert_src);
-       err |= cfc_check_trigger_is_unique(cmd->stop_src);
+       err |= comedi_check_trigger_is_unique(cmd->start_src);
+       err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
+       err |= comedi_check_trigger_is_unique(cmd->convert_src);
+       err |= comedi_check_trigger_is_unique(cmd->stop_src);
 
        /* Step 2b : and mutually compatible */
 
        if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER)
                err |= -EINVAL;
-       if (cmd->stop_src != TRIG_COUNT &&
-           cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT)
-               err |= -EINVAL;
 
        if (err)
                return 2;
 
        /* Step 3: check if arguments are trivially valid */
 
+       switch (cmd->start_src) {
+       case TRIG_NOW:
+               err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
+               break;
+       case TRIG_EXT:
+               /*
+                * start_arg is the CR_CHAN | CR_INVERT of the
+                * external trigger.
+                */
+               break;
+       }
+
        if (cmd->convert_src == TRIG_TIMER) {
-               if (thisboard->layout == LAYOUT_4020) {
-                       err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+               if (board->layout == LAYOUT_4020) {
+                       err |= comedi_check_trigger_arg_is(&cmd->convert_arg,
+                                                          0);
                } else {
-                       err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
-                                                        thisboard->ai_speed);
-                       /* if scans are timed faster than conversion rate allows */
-                       if (cmd->scan_begin_src == TRIG_TIMER)
-                               err |= cfc_check_trigger_arg_min(
+                       err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
+                                                           board->ai_speed);
+                       /*
+                        * if scans are timed faster than conversion rate
+                        * allows
+                        */
+                       if (cmd->scan_begin_src == TRIG_TIMER) {
+                               err |= comedi_check_trigger_arg_min(
                                                &cmd->scan_begin_arg,
                                                cmd->convert_arg *
                                                cmd->chanlist_len);
+                       }
                }
        }
 
-       err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
-       err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+       err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1);
+       err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
+                                          cmd->chanlist_len);
 
        switch (cmd->stop_src) {
        case TRIG_EXT:
                break;
        case TRIG_COUNT:
-               err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
+               err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
                break;
        case TRIG_NONE:
-               err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+               err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
                break;
        default:
                break;
@@ -2164,36 +2218,9 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
        if (err)
                return 4;
 
-       /*  make sure user is doesn't change analog reference mid chanlist */
-       if (cmd->chanlist) {
-               aref = CR_AREF(cmd->chanlist[0]);
-               for (i = 1; i < cmd->chanlist_len; i++) {
-                       if (aref != CR_AREF(cmd->chanlist[i])) {
-                               comedi_error(dev,
-                                            "all elements in chanlist must use the same analog reference");
-                               err++;
-                               break;
-                       }
-               }
-               /*  check 4020 chanlist */
-               if (thisboard->layout == LAYOUT_4020) {
-                       unsigned int first_channel = CR_CHAN(cmd->chanlist[0]);
-                       for (i = 1; i < cmd->chanlist_len; i++) {
-                               if (CR_CHAN(cmd->chanlist[i]) !=
-                                   first_channel + i) {
-                                       comedi_error(dev,
-                                                    "chanlist must use consecutive channels");
-                                       err++;
-                                       break;
-                               }
-                       }
-                       if (cmd->chanlist_len == 3) {
-                               comedi_error(dev,
-                                            "chanlist cannot be 3 channels long, use 1, 2, or 4 channels");
-                               err++;
-                       }
-               }
-       }
+       /* Step 5: check channel list if it exists */
+       if (cmd->chanlist && cmd->chanlist_len > 0)
+               err |= cb_pcidas64_ai_check_chanlist(dev, s, cmd);
 
        if (err)
                return 5;
@@ -2208,8 +2235,8 @@ static int use_hw_sample_counter(struct comedi_cmd *cmd)
 
        if (cmd->stop_src == TRIG_COUNT && cmd->stop_arg <= max_counter_value)
                return 1;
-       else
-               return 0;
+
+       return 0;
 }
 
 static void setup_sample_counters(struct comedi_device *dev,
@@ -2217,10 +2244,6 @@ static void setup_sample_counters(struct comedi_device *dev,
 {
        struct pcidas64_private *devpriv = dev->private;
 
-       if (cmd->stop_src == TRIG_COUNT) {
-               /*  set software count */
-               devpriv->ai_count = cmd->stop_arg * cmd->chanlist_len;
-       }
        /*  load hardware conversion counter */
        if (use_hw_sample_counter(cmd)) {
                writew(cmd->stop_arg & 0xffff,
@@ -2234,12 +2257,12 @@ static void setup_sample_counters(struct comedi_device *dev,
 
 static inline unsigned int dma_transfer_size(struct comedi_device *dev)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        unsigned int num_samples;
 
        num_samples = devpriv->ai_fifo_segment_length *
-                     thisboard->ai_fifo->sample_packing_ratio;
+                     board->ai_fifo->sample_packing_ratio;
        if (num_samples > DMA_BUFFER_SIZE / sizeof(uint16_t))
                num_samples = DMA_BUFFER_SIZE / sizeof(uint16_t);
 
@@ -2270,7 +2293,6 @@ static uint32_t ai_scan_counter_6xxx(struct comedi_device *dev,
                break;
        default:
                return 0;
-               break;
        }
        return count - 3;
 }
@@ -2289,7 +2311,7 @@ static uint32_t ai_convert_counter_4020(struct comedi_device *dev,
                divisor = devpriv->ext_clock.divisor;
                break;
        default:                /*  should never happen */
-               comedi_error(dev, "bug! failed to set ai pacing!");
+               dev_err(dev->class_dev, "bug! failed to set ai pacing!\n");
                divisor = 1000;
                break;
        }
@@ -2322,9 +2344,9 @@ static void select_master_clock_4020(struct comedi_device *dev,
 static void select_master_clock(struct comedi_device *dev,
                                const struct comedi_cmd *cmd)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
 
-       switch (thisboard->layout) {
+       switch (board->layout) {
        case LAYOUT_4020:
                select_master_clock_4020(dev, cmd);
                break;
@@ -2354,7 +2376,7 @@ static inline void dma_start_sync(struct comedi_device *dev,
 
 static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        uint32_t convert_counter = 0, scan_counter = 0;
 
@@ -2362,7 +2384,7 @@ static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd)
 
        select_master_clock(dev, cmd);
 
-       if (thisboard->layout == LAYOUT_4020) {
+       if (board->layout == LAYOUT_4020) {
                convert_counter = ai_convert_counter_4020(dev, cmd);
        } else {
                convert_counter = ai_convert_counter_6xxx(dev, cmd);
@@ -2372,7 +2394,6 @@ static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd)
        /*  load lower 16 bits of convert interval */
        writew(convert_counter & 0xffff,
               devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG);
-       DEBUG_PRINT("convert counter 0x%x\n", convert_counter);
        /*  load upper 8 bits of convert interval */
        writew((convert_counter >> 16) & 0xff,
               devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
@@ -2382,7 +2403,6 @@ static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd)
        /*  load upper 8 bits of scan delay */
        writew((scan_counter >> 16) & 0xff,
               devpriv->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG);
-       DEBUG_PRINT("scan counter 0x%x\n", scan_counter);
 }
 
 static int use_internal_queue_6xxx(const struct comedi_cmd *cmd)
@@ -2405,12 +2425,12 @@ static int use_internal_queue_6xxx(const struct comedi_cmd *cmd)
 static int setup_channel_queue(struct comedi_device *dev,
                               const struct comedi_cmd *cmd)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        unsigned short bits;
        int i;
 
-       if (thisboard->layout != LAYOUT_4020) {
+       if (board->layout != LAYOUT_4020) {
                if (use_internal_queue_6xxx(cmd)) {
                        devpriv->hw_config_bits &= ~EXT_QUEUE_BIT;
                        writew(devpriv->hw_config_bits,
@@ -2473,12 +2493,11 @@ static int setup_channel_queue(struct comedi_device *dev,
                                writew(bits,
                                       devpriv->main_iobase +
                                       ADC_QUEUE_FIFO_REG);
-                               DEBUG_PRINT(
-                                           "wrote 0x%x to external channel queue\n",
-                                           bits);
                        }
-                       /* doing a queue clear is not specified in board docs,
-                        * but required for reliable operation */
+                       /*
+                        * doing a queue clear is not specified in board docs,
+                        * but required for reliable operation
+                        */
                        writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG);
                        /*  prime queue holding register */
                        writew(0, devpriv->main_iobase + ADC_QUEUE_LOAD_REG);
@@ -2501,10 +2520,13 @@ static int setup_channel_queue(struct comedi_device *dev,
                                devpriv->i2c_cal_range_bits &=
                                        ~attenuate_bit(channel);
                }
-               /*  update calibration/range i2c register only if necessary,
-                *  as it is very slow */
+               /*
+                * update calibration/range i2c register only if necessary,
+                * as it is very slow
+                */
                if (old_cal_range_bits != devpriv->i2c_cal_range_bits) {
                        uint8_t i2c_data = devpriv->i2c_cal_range_bits;
+
                        i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data,
                                  sizeof(i2c_data));
                }
@@ -2518,11 +2540,13 @@ static inline void load_first_dma_descriptor(struct comedi_device *dev,
 {
        struct pcidas64_private *devpriv = dev->private;
 
-       /* The transfer size, pci address, and local address registers
+       /*
+        * The transfer size, pci address, and local address registers
         * are supposedly unused during chained dma,
         * but I have found that left over values from last operation
         * occasionally cause problems with transfer of first dma
-        * block.  Initializing them to zero seems to fix the problem. */
+        * block.  Initializing them to zero seems to fix the problem.
+        */
        if (dma_channel) {
                writel(0,
                       devpriv->plx9080_iobase + PLX_DMA1_TRANSFER_SIZE_REG);
@@ -2544,7 +2568,7 @@ static inline void load_first_dma_descriptor(struct comedi_device *dev,
 
 static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        struct comedi_async *async = s->async;
        struct comedi_cmd *cmd = &async->cmd;
@@ -2573,7 +2597,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        /* set mode, allow conversions through software gate */
        devpriv->adc_control1_bits |= ADC_SW_GATE_BIT;
        devpriv->adc_control1_bits &= ~ADC_DITHER_BIT;
-       if (thisboard->layout != LAYOUT_4020) {
+       if (board->layout != LAYOUT_4020) {
                devpriv->adc_control1_bits &= ~ADC_MODE_MASK;
                if (cmd->convert_src == TRIG_EXT)
                        /*  good old mode 13 */
@@ -2597,18 +2621,17 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        }
        writew(devpriv->adc_control1_bits,
               devpriv->main_iobase + ADC_CONTROL1_REG);
-       DEBUG_PRINT("control1 bits 0x%x\n", devpriv->adc_control1_bits);
        spin_unlock_irqrestore(&dev->spinlock, flags);
 
        /*  clear adc buffer */
        writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG);
 
-       if ((cmd->flags & TRIG_WAKE_EOS) == 0 ||
-           thisboard->layout == LAYOUT_4020) {
+       if ((cmd->flags & CMDF_WAKE_EOS) == 0 ||
+           board->layout == LAYOUT_4020) {
                devpriv->ai_dma_index = 0;
 
                /*  set dma transfer size */
-               for (i = 0; i < ai_dma_ring_count(thisboard); i++)
+               for (i = 0; i < ai_dma_ring_count(board); i++)
                        devpriv->ai_dma_desc[i].transfer_size =
                                cpu_to_le32(dma_transfer_size(dev) *
                                            sizeof(uint16_t));
@@ -2623,7 +2646,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
                dma_start_sync(dev, 1);
        }
 
-       if (thisboard->layout == LAYOUT_4020) {
+       if (board->layout == LAYOUT_4020) {
                /* set source for external triggers */
                bits = 0;
                if (cmd->start_src == TRIG_EXT && CR_CHAN(cmd->start_arg))
@@ -2637,29 +2660,27 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 
        /* enable pacing, triggering, etc */
        bits = ADC_ENABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT;
-       if (cmd->flags & TRIG_WAKE_EOS)
+       if (cmd->flags & CMDF_WAKE_EOS)
                bits |= ADC_DMA_DISABLE_BIT;
        /*  set start trigger */
        if (cmd->start_src == TRIG_EXT) {
                bits |= ADC_START_TRIG_EXT_BITS;
                if (cmd->start_arg & CR_INVERT)
                        bits |= ADC_START_TRIG_FALLING_BIT;
-       } else if (cmd->start_src == TRIG_NOW)
+       } else if (cmd->start_src == TRIG_NOW) {
                bits |= ADC_START_TRIG_SOFT_BITS;
+       }
        if (use_hw_sample_counter(cmd))
                bits |= ADC_SAMPLE_COUNTER_EN_BIT;
        writew(bits, devpriv->main_iobase + ADC_CONTROL0_REG);
-       DEBUG_PRINT("control0 bits 0x%x\n", bits);
 
        devpriv->ai_cmd_running = 1;
 
        spin_unlock_irqrestore(&dev->spinlock, flags);
 
        /*  start acquisition */
-       if (cmd->start_src == TRIG_NOW) {
+       if (cmd->start_src == TRIG_NOW)
                writew(0, devpriv->main_iobase + ADC_START_REG);
-               DEBUG_PRINT("soft trig\n");
-       }
 
        return 0;
 }
@@ -2669,8 +2690,6 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev)
 {
        struct pcidas64_private *devpriv = dev->private;
        struct comedi_subdevice *s = dev->read_subdev;
-       struct comedi_async *async = s->async;
-       struct comedi_cmd *cmd = &async->cmd;
        unsigned int i;
        uint16_t prepost_bits;
        int read_segment, read_index, write_segment, write_index;
@@ -2682,55 +2701,49 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev)
                             0x7fff;
                write_index = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG) &
                              0x7fff;
-               /* Get most significant bits (grey code).
+               /*
+                * Get most significant bits (grey code).
                 * Different boards use different code so use a scheme
                 * that doesn't depend on encoding.  This read must
                 * occur after reading least significant 15 bits to avoid race
-                * with fifo switching to next segment. */
+                * with fifo switching to next segment.
+                */
                prepost_bits = readw(devpriv->main_iobase + PREPOST_REG);
 
-               /* if read and write pointers are not on the same fifo segment,
-                * read to the end of the read segment */
+               /*
+                * if read and write pointers are not on the same fifo segment,
+                * read to the end of the read segment
+                */
                read_segment = adc_upper_read_ptr_code(prepost_bits);
                write_segment = adc_upper_write_ptr_code(prepost_bits);
 
-               DEBUG_PRINT(" rd seg %i, wrt seg %i, rd idx %i, wrt idx %i\n",
-                           read_segment, write_segment, read_index,
-                           write_index);
-
                if (read_segment != write_segment)
                        num_samples =
                                devpriv->ai_fifo_segment_length - read_index;
                else
                        num_samples = write_index - read_index;
-
-               if (cmd->stop_src == TRIG_COUNT) {
-                       if (devpriv->ai_count == 0)
-                               break;
-                       if (num_samples > devpriv->ai_count)
-                               num_samples = devpriv->ai_count;
-
-                       devpriv->ai_count -= num_samples;
-               }
-
                if (num_samples < 0) {
                        dev_err(dev->class_dev,
                                "cb_pcidas64: bug! num_samples < 0\n");
                        break;
                }
 
-               DEBUG_PRINT(" read %i samples from fifo\n", num_samples);
+               num_samples = comedi_nsamples_left(s, num_samples);
+               if (num_samples == 0)
+                       break;
 
                for (i = 0; i < num_samples; i++) {
-                       cfc_write_to_buffer(s,
-                                           readw(devpriv->main_iobase +
-                                                 ADC_FIFO_REG));
+                       unsigned short val;
+
+                       val = readw(devpriv->main_iobase + ADC_FIFO_REG);
+                       comedi_buf_write_samples(s, &val, 1);
                }
 
        } while (read_segment != write_segment);
 }
 
-/* Read from 32 bit wide ai fifo of 4020 - deal with insane grey coding of
+/*
+ * Read from 32 bit wide ai fifo of 4020 - deal with insane grey coding of
  * pointers.  The pci-4020 hardware only supports dma transfers (it only
  * supports the use of pio for draining the last remaining points from the
  * fifo when a data acquisition operation has completed).
@@ -2739,41 +2752,38 @@ static void pio_drain_ai_fifo_32(struct comedi_device *dev)
 {
        struct pcidas64_private *devpriv = dev->private;
        struct comedi_subdevice *s = dev->read_subdev;
-       struct comedi_async *async = s->async;
-       struct comedi_cmd *cmd = &async->cmd;
+       unsigned int nsamples;
        unsigned int i;
-       unsigned int max_transfer = 100000;
        uint32_t fifo_data;
        int write_code =
                readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff;
        int read_code =
                readw(devpriv->main_iobase + ADC_READ_PNTR_REG) & 0x7fff;
 
-       if (cmd->stop_src == TRIG_COUNT) {
-               if (max_transfer > devpriv->ai_count)
-                       max_transfer = devpriv->ai_count;
+       nsamples = comedi_nsamples_left(s, 100000);
+       for (i = 0; read_code != write_code && i < nsamples;) {
+               unsigned short val;
 
-       }
-       for (i = 0; read_code != write_code && i < max_transfer;) {
-               fifo_data = readl(devpriv->dio_counter_iobase + ADC_FIFO_REG);
-               cfc_write_to_buffer(s, fifo_data & 0xffff);
+               fifo_data = readl(dev->mmio + ADC_FIFO_REG);
+               val = fifo_data & 0xffff;
+               comedi_buf_write_samples(s, &val, 1);
                i++;
-               if (i < max_transfer) {
-                       cfc_write_to_buffer(s, (fifo_data >> 16) & 0xffff);
+               if (i < nsamples) {
+                       val = (fifo_data >> 16) & 0xffff;
+                       comedi_buf_write_samples(s, &val, 1);
                        i++;
                }
                read_code = readw(devpriv->main_iobase + ADC_READ_PNTR_REG) &
                            0x7fff;
        }
-       devpriv->ai_count -= i;
 }
 
 /* empty fifo */
 static void pio_drain_ai_fifo(struct comedi_device *dev)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
 
-       if (thisboard->layout == LAYOUT_4020)
+       if (board->layout == LAYOUT_4020)
                pio_drain_ai_fifo_32(dev);
        else
                pio_drain_ai_fifo_16(dev);
@@ -2781,9 +2791,9 @@ static void pio_drain_ai_fifo(struct comedi_device *dev)
 
 static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
-       struct comedi_async *async = dev->read_subdev->async;
+       struct comedi_subdevice *s = dev->read_subdev;
        uint32_t next_transfer_addr;
        int j;
        int num_samples = 0;
@@ -2802,35 +2812,26 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel)
              devpriv->ai_buffer_bus_addr[devpriv->ai_dma_index] ||
              next_transfer_addr >=
              devpriv->ai_buffer_bus_addr[devpriv->ai_dma_index] +
-             DMA_BUFFER_SIZE) && j < ai_dma_ring_count(thisboard); j++) {
+             DMA_BUFFER_SIZE) && j < ai_dma_ring_count(board); j++) {
                /*  transfer data from dma buffer to comedi buffer */
-               num_samples = dma_transfer_size(dev);
-               if (async->cmd.stop_src == TRIG_COUNT) {
-                       if (num_samples > devpriv->ai_count)
-                               num_samples = devpriv->ai_count;
-                       devpriv->ai_count -= num_samples;
-               }
-               cfc_write_array_to_buffer(dev->read_subdev,
-                                         devpriv->ai_buffer[devpriv->
-                                                            ai_dma_index],
-                                         num_samples * sizeof(uint16_t));
+               num_samples = comedi_nsamples_left(s, dma_transfer_size(dev));
+               comedi_buf_write_samples(s,
+                               devpriv->ai_buffer[devpriv->ai_dma_index],
+                               num_samples);
                devpriv->ai_dma_index = (devpriv->ai_dma_index + 1) %
-                                       ai_dma_ring_count(thisboard);
-
-               DEBUG_PRINT("next buffer addr 0x%lx\n",
-                           (unsigned long)devpriv->
-                           ai_buffer_bus_addr[devpriv->ai_dma_index]);
-               DEBUG_PRINT("pci addr reg 0x%x\n", next_transfer_addr);
+                                       ai_dma_ring_count(board);
        }
-       /* XXX check for dma ring buffer overrun
-        * (use end-of-chain bit to mark last unused buffer) */
+       /*
+        * XXX check for dma ring buffer overrun
+        * (use end-of-chain bit to mark last unused buffer)
+        */
 }
 
 static void handle_ai_interrupt(struct comedi_device *dev,
                                unsigned short status,
                                unsigned int plx_status)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        struct comedi_subdevice *s = dev->read_subdev;
        struct comedi_async *async = s->async;
@@ -2840,8 +2841,8 @@ static void handle_ai_interrupt(struct comedi_device *dev,
 
        /*  check for fifo overrun */
        if (status & ADC_OVERRUN_BIT) {
-               comedi_error(dev, "fifo overrun");
-               async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+               dev_err(dev->class_dev, "fifo overrun\n");
+               async->events |= COMEDI_CB_ERROR;
        }
        /*  spin lock makes sure no one else changes plx dma control reg */
        spin_lock_irqsave(&dev->spinlock, flags);
@@ -2849,38 +2850,32 @@ static void handle_ai_interrupt(struct comedi_device *dev,
        if (plx_status & ICS_DMA1_A) {  /*  dma chan 1 interrupt */
                writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT,
                       devpriv->plx9080_iobase + PLX_DMA1_CS_REG);
-               DEBUG_PRINT("dma1 status 0x%x\n", dma1_status);
 
                if (dma1_status & PLX_DMA_EN_BIT)
                        drain_dma_buffers(dev, 1);
-
-               DEBUG_PRINT(" cleared dma ch1 interrupt\n");
        }
        spin_unlock_irqrestore(&dev->spinlock, flags);
 
-       if (status & ADC_DONE_BIT)
-               DEBUG_PRINT("adc done interrupt\n");
-
        /*  drain fifo with pio */
        if ((status & ADC_DONE_BIT) ||
-           ((cmd->flags & TRIG_WAKE_EOS) &&
+           ((cmd->flags & CMDF_WAKE_EOS) &&
             (status & ADC_INTR_PENDING_BIT) &&
-            (thisboard->layout != LAYOUT_4020))) {
-               DEBUG_PRINT("pio fifo drain\n");
+            (board->layout != LAYOUT_4020))) {
                spin_lock_irqsave(&dev->spinlock, flags);
                if (devpriv->ai_cmd_running) {
                        spin_unlock_irqrestore(&dev->spinlock, flags);
                        pio_drain_ai_fifo(dev);
-               } else
+               } else {
                        spin_unlock_irqrestore(&dev->spinlock, flags);
+               }
        }
        /*  if we are have all the data, then quit */
-       if ((cmd->stop_src == TRIG_COUNT && (int)devpriv->ai_count <= 0) ||
-           (cmd->stop_src == TRIG_EXT && (status & ADC_STOP_BIT))) {
+       if ((cmd->stop_src == TRIG_COUNT &&
+            async->scans_done >= cmd->stop_arg) ||
+           (cmd->stop_src == TRIG_EXT && (status & ADC_STOP_BIT)))
                async->events |= COMEDI_CB_EOA;
-       }
 
-       cfc_handle_events(dev, s);
+       comedi_handle_events(dev, s);
 }
 
 static inline unsigned int prev_ao_dma_index(struct comedi_device *dev)
@@ -2915,22 +2910,6 @@ static int last_ao_dma_load_completed(struct comedi_device *dev)
        return 1;
 }
 
-static int ao_stopped_by_error(struct comedi_device *dev,
-                              const struct comedi_cmd *cmd)
-{
-       struct pcidas64_private *devpriv = dev->private;
-
-       if (cmd->stop_src == TRIG_NONE)
-               return 1;
-       if (cmd->stop_src == TRIG_COUNT) {
-               if (devpriv->ao_count)
-                       return 1;
-               if (last_ao_dma_load_completed(dev) == 0)
-                       return 1;
-       }
-       return 0;
-}
-
 static inline int ao_dma_needs_restart(struct comedi_device *dev,
                                       unsigned short dma_status)
 {
@@ -2951,58 +2930,59 @@ static void restart_ao_dma(struct comedi_device *dev)
        dma_desc_bits =
                readl(devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG);
        dma_desc_bits &= ~PLX_END_OF_CHAIN_BIT;
-       DEBUG_PRINT("restarting ao dma, descriptor reg 0x%x\n", dma_desc_bits);
        load_first_dma_descriptor(dev, 0, dma_desc_bits);
 
        dma_start_sync(dev, 0);
 }
 
+static unsigned int cb_pcidas64_ao_fill_buffer(struct comedi_device *dev,
+                                              struct comedi_subdevice *s,
+                                              unsigned short *dest,
+                                              unsigned int max_bytes)
+{
+       unsigned int nsamples = comedi_bytes_to_samples(s, max_bytes);
+       unsigned int actual_bytes;
+
+       nsamples = comedi_nsamples_left(s, nsamples);
+       actual_bytes = comedi_buf_read_samples(s, dest, nsamples);
+
+       return comedi_bytes_to_samples(s, actual_bytes);
+}
+
 static unsigned int load_ao_dma_buffer(struct comedi_device *dev,
                                       const struct comedi_cmd *cmd)
 {
        struct pcidas64_private *devpriv = dev->private;
-       unsigned int num_bytes, buffer_index, prev_buffer_index;
+       struct comedi_subdevice *s = dev->write_subdev;
+       unsigned int buffer_index = devpriv->ao_dma_index;
+       unsigned int prev_buffer_index = prev_ao_dma_index(dev);
+       unsigned int nsamples;
+       unsigned int nbytes;
        unsigned int next_bits;
 
-       buffer_index = devpriv->ao_dma_index;
-       prev_buffer_index = prev_ao_dma_index(dev);
-
-       DEBUG_PRINT("attempting to load ao buffer %i (0x%llx)\n", buffer_index,
-                   (unsigned long long)devpriv->ao_buffer_bus_addr[
-                                                               buffer_index]);
-
-       num_bytes = comedi_buf_read_n_available(dev->write_subdev->async);
-       if (num_bytes > DMA_BUFFER_SIZE)
-               num_bytes = DMA_BUFFER_SIZE;
-       if (cmd->stop_src == TRIG_COUNT && num_bytes > devpriv->ao_count)
-               num_bytes = devpriv->ao_count;
-       num_bytes -= num_bytes % bytes_in_sample;
-
-       if (num_bytes == 0)
+       nsamples = cb_pcidas64_ao_fill_buffer(dev, s,
+                                             devpriv->ao_buffer[buffer_index],
+                                             DMA_BUFFER_SIZE);
+       if (nsamples == 0)
                return 0;
 
-       DEBUG_PRINT("loading %i bytes\n", num_bytes);
-
-       num_bytes = cfc_read_array_from_buffer(dev->write_subdev,
-                                              devpriv->
-                                              ao_buffer[buffer_index],
-                                              num_bytes);
-       devpriv->ao_dma_desc[buffer_index].transfer_size =
-               cpu_to_le32(num_bytes);
+       nbytes = comedi_samples_to_bytes(s, nsamples);
+       devpriv->ao_dma_desc[buffer_index].transfer_size = cpu_to_le32(nbytes);
        /* set end of chain bit so we catch underruns */
        next_bits = le32_to_cpu(devpriv->ao_dma_desc[buffer_index].next);
        next_bits |= PLX_END_OF_CHAIN_BIT;
        devpriv->ao_dma_desc[buffer_index].next = cpu_to_le32(next_bits);
-       /* clear end of chain bit on previous buffer now that we have set it
-        * for the last buffer */
+       /*
+        * clear end of chain bit on previous buffer now that we have set it
+        * for the last buffer
+        */
        next_bits = le32_to_cpu(devpriv->ao_dma_desc[prev_buffer_index].next);
        next_bits &= ~PLX_END_OF_CHAIN_BIT;
        devpriv->ao_dma_desc[prev_buffer_index].next = cpu_to_le32(next_bits);
 
        devpriv->ao_dma_index = (buffer_index + 1) % AO_DMA_RING_COUNT;
-       devpriv->ao_count -= num_bytes;
 
-       return num_bytes;
+       return nbytes;
 }
 
 static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
@@ -3039,7 +3019,7 @@ static void handle_ao_interrupt(struct comedi_device *dev,
        unsigned long flags;
 
        /* board might not support ao, in which case write_subdev is NULL */
-       if (s == NULL)
+       if (!s)
                return;
        async = s->async;
        cmd = &async->cmd;
@@ -3056,30 +3036,25 @@ static void handle_ao_interrupt(struct comedi_device *dev,
                        writeb(PLX_CLEAR_DMA_INTR_BIT,
                               devpriv->plx9080_iobase + PLX_DMA0_CS_REG);
                spin_unlock_irqrestore(&dev->spinlock, flags);
-               DEBUG_PRINT("dma0 status 0x%x\n", dma0_status);
                if (dma0_status & PLX_DMA_EN_BIT) {
                        load_ao_dma(dev, cmd);
                        /* try to recover from dma end-of-chain event */
                        if (ao_dma_needs_restart(dev, dma0_status))
                                restart_ao_dma(dev);
                }
-               DEBUG_PRINT(" cleared dma ch0 interrupt\n");
        } else {
                spin_unlock_irqrestore(&dev->spinlock, flags);
        }
 
        if ((status & DAC_DONE_BIT)) {
-               async->events |= COMEDI_CB_EOA;
-               if (ao_stopped_by_error(dev, cmd))
+               if ((cmd->stop_src == TRIG_COUNT &&
+                    async->scans_done >= cmd->stop_arg) ||
+                   last_ao_dma_load_completed(dev))
+                       async->events |= COMEDI_CB_EOA;
+               else
                        async->events |= COMEDI_CB_ERROR;
-               DEBUG_PRINT("plx dma0 desc reg 0x%x\n",
-                           readl(devpriv->plx9080_iobase +
-                                 PLX_DMA0_DESCRIPTOR_REG));
-               DEBUG_PRINT("plx dma0 address reg 0x%x\n",
-                           readl(devpriv->plx9080_iobase +
-                                 PLX_DMA0_PCI_ADDRESS_REG));
        }
-       cfc_handle_events(dev, s);
+       comedi_handle_events(dev, s);
 }
 
 static irqreturn_t handle_interrupt(int irq, void *d)
@@ -3093,15 +3068,14 @@ static irqreturn_t handle_interrupt(int irq, void *d)
        plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG);
        status = readw(devpriv->main_iobase + HW_STATUS_REG);
 
-       DEBUG_PRINT("hw status 0x%x, plx status 0x%x\n", status, plx_status);
-
-       /* an interrupt before all the postconfig stuff gets done could
+       /*
+        * an interrupt before all the postconfig stuff gets done could
         * cause a NULL dereference if we continue through the
-        * interrupt handler */
-       if (!dev->attached) {
-               DEBUG_PRINT("premature interrupt, ignoring\n");
+        * interrupt handler
+        */
+       if (!dev->attached)
                return IRQ_HANDLED;
-       }
+
        handle_ai_interrupt(dev, status, plx_status);
        handle_ao_interrupt(dev, status, plx_status);
 
@@ -3109,11 +3083,8 @@ static irqreturn_t handle_interrupt(int irq, void *d)
        if (plx_status & ICS_LDIA) {    /*  clear local doorbell interrupt */
                plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG);
                writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG);
-               DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits);
        }
 
-       DEBUG_PRINT("exiting handler\n");
-
        return IRQ_HANDLED;
 }
 
@@ -3134,14 +3105,13 @@ static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 
        abort_dma(dev, 1);
 
-       DEBUG_PRINT("ai canceled\n");
        return 0;
 }
 
 static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
                    struct comedi_insn *insn, unsigned int *data)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        int chan = CR_CHAN(insn->chanspec);
        int range = CR_RANGE(insn->chanspec);
@@ -3155,7 +3125,7 @@ static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
               devpriv->main_iobase + DAC_CONTROL1_REG);
 
        /*  write to channel */
-       if (thisboard->layout == LAYOUT_4020) {
+       if (board->layout == LAYOUT_4020) {
                writew(data[0] & 0xff,
                       devpriv->main_iobase + dac_lsb_4020_reg(chan));
                writew((data[0] >> 8) & 0xf,
@@ -3165,18 +3135,7 @@ static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
        }
 
        /*  remember output value */
-       devpriv->ao_value[chan] = data[0];
-
-       return 1;
-}
-
-static int ao_readback_insn(struct comedi_device *dev,
-                           struct comedi_subdevice *s,
-                           struct comedi_insn *insn, unsigned int *data)
-{
-       struct pcidas64_private *devpriv = dev->private;
-
-       data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)];
+       s->readback[chan] = data[0];
 
        return 1;
 }
@@ -3232,7 +3191,8 @@ static void set_dac_select_reg(struct comedi_device *dev,
        first_channel = CR_CHAN(cmd->chanlist[0]);
        last_channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
        if (last_channel < first_channel)
-               comedi_error(dev, "bug! last ao channel < first ao channel");
+               dev_err(dev->class_dev,
+                       "bug! last ao channel < first ao channel\n");
 
        bits = (first_channel & 0x7) | (last_channel & 0x7) << 3;
 
@@ -3255,7 +3215,7 @@ static void set_dac_interval_regs(struct comedi_device *dev,
 
        divisor = get_ao_divisor(cmd->scan_begin_arg, cmd->flags);
        if (divisor > max_counter_value) {
-               comedi_error(dev, "bug! ao divisor too big");
+               dev_err(dev->class_dev, "bug! ao divisor too big\n");
                divisor = max_counter_value;
        }
        writew(divisor & 0xffff,
@@ -3267,30 +3227,35 @@ static void set_dac_interval_regs(struct comedi_device *dev,
 static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
 {
        struct pcidas64_private *devpriv = dev->private;
-       unsigned int num_bytes;
+       struct comedi_subdevice *s = dev->write_subdev;
+       unsigned int nsamples;
+       unsigned int nbytes;
        int i;
 
-       /* clear queue pointer too, since external queue has
-        * weird interactions with ao fifo */
+       /*
+        * clear queue pointer too, since external queue has
+        * weird interactions with ao fifo
+        */
        writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG);
        writew(0, devpriv->main_iobase + DAC_BUFFER_CLEAR_REG);
 
-       num_bytes = (DAC_FIFO_SIZE / 2) * bytes_in_sample;
-       if (cmd->stop_src == TRIG_COUNT &&
-           num_bytes / bytes_in_sample > devpriv->ao_count)
-               num_bytes = devpriv->ao_count * bytes_in_sample;
-       num_bytes = cfc_read_array_from_buffer(dev->write_subdev,
-                                              devpriv->ao_bounce_buffer,
-                                              num_bytes);
-       for (i = 0; i < num_bytes / bytes_in_sample; i++) {
+       nsamples = cb_pcidas64_ao_fill_buffer(dev, s,
+                                             devpriv->ao_bounce_buffer,
+                                             DAC_FIFO_SIZE);
+       if (nsamples == 0)
+               return -1;
+
+       for (i = 0; i < nsamples; i++) {
                writew(devpriv->ao_bounce_buffer[i],
                       devpriv->main_iobase + DAC_FIFO_REG);
        }
-       devpriv->ao_count -= num_bytes / bytes_in_sample;
-       if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count == 0)
+
+       if (cmd->stop_src == TRIG_COUNT &&
+           s->async->scans_done >= cmd->stop_arg)
                return 0;
-       num_bytes = load_ao_dma_buffer(dev, cmd);
-       if (num_bytes == 0)
+
+       nbytes = load_ao_dma_buffer(dev, cmd);
+       if (nbytes == 0)
                return -1;
        load_ao_dma(dev, cmd);
 
@@ -3299,15 +3264,17 @@ static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
        return 0;
 }
 
-static inline int external_ai_queue_in_use(struct comedi_device *dev)
+static inline int external_ai_queue_in_use(struct comedi_device *dev,
+                                          struct comedi_subdevice *s,
+                                          struct comedi_cmd *cmd)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
 
-       if (dev->read_subdev->busy)
+       if (s->busy)
                return 0;
-       if (thisboard->layout == LAYOUT_4020)
+       if (board->layout == LAYOUT_4020)
                return 0;
-       else if (use_internal_queue_6xxx(&dev->read_subdev->async->cmd))
+       else if (use_internal_queue_6xxx(cmd))
                return 0;
        return 1;
 }
@@ -3319,7 +3286,7 @@ static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
        struct comedi_cmd *cmd = &s->async->cmd;
        int retval;
 
-       if (trig_num != 0)
+       if (trig_num != cmd->start_arg)
                return -EINVAL;
 
        retval = prep_ao_dma(dev, cmd);
@@ -3341,7 +3308,7 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        struct pcidas64_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
 
-       if (external_ai_queue_in_use(dev)) {
+       if (external_ai_queue_in_use(dev, s, cmd)) {
                warn_external_queue(dev);
                return -EBUSY;
        }
@@ -3349,7 +3316,6 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        writew(0x0, devpriv->main_iobase + DAC_CONTROL0_REG);
 
        devpriv->ao_dma_index = 0;
-       devpriv->ao_count = cmd->stop_arg * cmd->chanlist_len;
 
        set_dac_select_reg(dev, cmd);
        set_dac_interval_regs(dev, cmd);
@@ -3362,30 +3328,49 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        return 0;
 }
 
+static int cb_pcidas64_ao_check_chanlist(struct comedi_device *dev,
+                                        struct comedi_subdevice *s,
+                                        struct comedi_cmd *cmd)
+{
+       unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
+       int i;
+
+       for (i = 1; i < cmd->chanlist_len; i++) {
+               unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
+               if (chan != (chan0 + i)) {
+                       dev_dbg(dev->class_dev,
+                               "chanlist must use consecutive channels\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
                      struct comedi_cmd *cmd)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        int err = 0;
        unsigned int tmp_arg;
-       int i;
 
        /* Step 1 : check if triggers are trivially valid */
 
-       err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT);
-       err |= cfc_check_trigger_src(&cmd->scan_begin_src,
-                                    TRIG_TIMER | TRIG_EXT);
-       err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
-       err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
-       err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
+       err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT);
+       err |= comedi_check_trigger_src(&cmd->scan_begin_src,
+                                       TRIG_TIMER | TRIG_EXT);
+       err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+       err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+       err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
 
        if (err)
                return 1;
 
        /* Step 2a : make sure trigger sources are unique */
 
-       err |= cfc_check_trigger_is_unique(cmd->start_src);
-       err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
+       err |= comedi_check_trigger_is_unique(cmd->start_src);
+       err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
 
        /* Step 2b : and mutually compatible */
 
@@ -3400,9 +3385,11 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
 
        /* Step 3: check if arguments are trivially valid */
 
+       err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
+
        if (cmd->scan_begin_src == TRIG_TIMER) {
-               err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
-                                                thisboard->ao_scan_speed);
+               err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
+                                                   board->ao_scan_speed);
                if (get_ao_divisor(cmd->scan_begin_arg, cmd->flags) >
                    max_counter_value) {
                        cmd->scan_begin_arg = (max_counter_value + 2) *
@@ -3411,8 +3398,9 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
                }
        }
 
-       err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
-       err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+       err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1);
+       err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
+                                          cmd->chanlist_len);
 
        if (err)
                return 3;
@@ -3430,17 +3418,9 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
        if (err)
                return 4;
 
-       if (cmd->chanlist) {
-               unsigned int first_channel = CR_CHAN(cmd->chanlist[0]);
-               for (i = 1; i < cmd->chanlist_len; i++) {
-                       if (CR_CHAN(cmd->chanlist[i]) != first_channel + i) {
-                               comedi_error(dev,
-                                            "chanlist must use consecutive channels");
-                               err++;
-                               break;
-                       }
-               }
-       }
+       /* Step 5: check channel list if it exists */
+       if (cmd->chanlist && cmd->chanlist_len > 0)
+               err |= cb_pcidas64_ao_check_chanlist(dev, s, cmd);
 
        if (err)
                return 5;
@@ -3457,36 +3437,24 @@ static int ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
        return 0;
 }
 
-static int dio_callback(int dir, int port, int data, unsigned long arg)
+static int dio_callback_4020(struct comedi_device *dev,
+                            int dir, int port, int data, unsigned long iobase)
 {
-       void __iomem *iobase = (void __iomem *)arg;
-       if (dir) {
-               writeb(data, iobase + port);
-               DEBUG_PRINT("wrote 0x%x to port %i\n", data, port);
-               return 0;
-       } else {
-               return readb(iobase + port);
-       }
-}
+       struct pcidas64_private *devpriv = dev->private;
 
-static int dio_callback_4020(int dir, int port, int data, unsigned long arg)
-{
-       void __iomem *iobase = (void __iomem *)arg;
        if (dir) {
-               writew(data, iobase + 2 * port);
+               writew(data, devpriv->main_iobase + iobase + 2 * port);
                return 0;
-       } else {
-               return readw(iobase + 2 * port);
        }
+       return readw(devpriv->main_iobase + iobase + 2 * port);
 }
 
 static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
                    struct comedi_insn *insn, unsigned int *data)
 {
-       struct pcidas64_private *devpriv = dev->private;
        unsigned int bits;
 
-       bits = readb(devpriv->dio_counter_iobase + DI_REG);
+       bits = readb(dev->mmio + DI_REG);
        bits &= 0xf;
        data[1] = bits;
        data[0] = 0;
@@ -3494,18 +3462,13 @@ static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
        return insn->n;
 }
 
-static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
-                   struct comedi_insn *insn, unsigned int *data)
+static int do_wbits(struct comedi_device *dev,
+                   struct comedi_subdevice *s,
+                   struct comedi_insn *insn,
+                   unsigned int *data)
 {
-       struct pcidas64_private *devpriv = dev->private;
-
-       data[0] &= 0xf;
-       /*  zero bits we are going to change */
-       s->state &= ~data[0];
-       /*  set new bits */
-       s->state |= data[0] & data[1];
-
-       writeb(s->state, devpriv->dio_counter_iobase + DO_REG);
+       if (comedi_dio_update_state(s, data))
+               writeb(s->state, dev->mmio + DO_REG);
 
        data[1] = s->state;
 
@@ -3514,51 +3477,35 @@ static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
 
 static int dio_60xx_config_insn(struct comedi_device *dev,
                                struct comedi_subdevice *s,
-                               struct comedi_insn *insn, unsigned int *data)
+                               struct comedi_insn *insn,
+                               unsigned int *data)
 {
-       struct pcidas64_private *devpriv = dev->private;
-       unsigned int mask;
-
-       mask = 1 << CR_CHAN(insn->chanspec);
+       int ret;
 
-       switch (data[0]) {
-       case INSN_CONFIG_DIO_INPUT:
-               s->io_bits &= ~mask;
-               break;
-       case INSN_CONFIG_DIO_OUTPUT:
-               s->io_bits |= mask;
-               break;
-       case INSN_CONFIG_DIO_QUERY:
-               data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
-               return 2;
-       default:
-               return -EINVAL;
-       }
+       ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+       if (ret)
+               return ret;
 
-       writeb(s->io_bits,
-              devpriv->dio_counter_iobase + DIO_DIRECTION_60XX_REG);
+       writeb(s->io_bits, dev->mmio + DIO_DIRECTION_60XX_REG);
 
-       return 1;
+       return insn->n;
 }
 
-static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
-                         struct comedi_insn *insn, unsigned int *data)
+static int dio_60xx_wbits(struct comedi_device *dev,
+                         struct comedi_subdevice *s,
+                         struct comedi_insn *insn,
+                         unsigned int *data)
 {
-       struct pcidas64_private *devpriv = dev->private;
-
-       if (data[0]) {
-               s->state &= ~data[0];
-               s->state |= (data[0] & data[1]);
-               writeb(s->state,
-                      devpriv->dio_counter_iobase + DIO_DATA_60XX_REG);
-       }
+       if (comedi_dio_update_state(s, data))
+               writeb(s->state, dev->mmio + DIO_DATA_60XX_REG);
 
-       data[1] = readb(devpriv->dio_counter_iobase + DIO_DATA_60XX_REG);
+       data[1] = readb(dev->mmio + DIO_DATA_60XX_REG);
 
        return insn->n;
 }
 
-/* pci-6025 8800 caldac:
+/*
+ * pci-6025 8800 caldac:
  * address 0 == dac channel 0 offset
  * address 1 == dac channel 0 gain
  * address 2 == dac channel 1 offset
@@ -3568,7 +3515,8 @@ static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
  * address 6 == coarse adc gain
  * address 7 == fine adc gain
  */
-/* pci-6402/16 uses all 8 channels for dac:
+/*
+ * pci-6402/16 uses all 8 channels for dac:
  * address 0 == dac channel 0 fine gain
  * address 1 == dac channel 0 coarse gain
  * address 2 == dac channel 0 coarse offset
@@ -3577,7 +3525,7 @@ static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
  * address 5 == dac channel 1 coarse gain
  * address 6 == dac channel 0 fine offset
  * address 7 == dac channel 1 fine offset
-*/
+ */
 
 static int caldac_8800_write(struct comedi_device *dev, unsigned int address,
                             uint8_t value)
@@ -3590,7 +3538,7 @@ static int caldac_8800_write(struct comedi_device *dev, unsigned int address,
        static const int caldac_8800_udelay = 1;
 
        if (address >= num_caldac_channels) {
-               comedi_error(dev, "illegal caldac channel");
+               dev_err(dev->class_dev, "illegal caldac channel\n");
                return -1;
        }
        for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) {
@@ -3662,9 +3610,8 @@ static int caldac_i2c_write(struct comedi_device *dev,
                serial_bytes[0] = GAIN_1_3;
                break;
        default:
-               comedi_error(dev, "invalid caldac channel\n");
+               dev_err(dev->class_dev, "invalid caldac channel\n");
                return -1;
-               break;
        }
        serial_bytes[1] = NOT_CLEAR_REGISTERS | ((value >> 8) & 0xf);
        serial_bytes[2] = value & 0xff;
@@ -3675,12 +3622,9 @@ static int caldac_i2c_write(struct comedi_device *dev,
 static void caldac_write(struct comedi_device *dev, unsigned int channel,
                         unsigned int value)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
-       struct pcidas64_private *devpriv = dev->private;
+       const struct pcidas64_board *board = dev->board_ptr;
 
-       devpriv->caldac_state[channel] = value;
-
-       switch (thisboard->layout) {
+       switch (board->layout) {
        case LAYOUT_60XX:
        case LAYOUT_64XX:
                caldac_8800_write(dev, channel, value);
@@ -3693,33 +3637,27 @@ static void caldac_write(struct comedi_device *dev, unsigned int channel,
        }
 }
 
-static int calib_write_insn(struct comedi_device *dev,
-                           struct comedi_subdevice *s,
-                           struct comedi_insn *insn, unsigned int *data)
+static int cb_pcidas64_calib_insn_write(struct comedi_device *dev,
+                                       struct comedi_subdevice *s,
+                                       struct comedi_insn *insn,
+                                       unsigned int *data)
 {
-       struct pcidas64_private *devpriv = dev->private;
-       int channel = CR_CHAN(insn->chanspec);
+       unsigned int chan = CR_CHAN(insn->chanspec);
 
-       /* return immediately if setting hasn't changed, since
-        * programming these things is slow */
-       if (devpriv->caldac_state[channel] == data[0])
-               return 1;
-
-       caldac_write(dev, channel, data[0]);
-
-       return 1;
-}
-
-static int calib_read_insn(struct comedi_device *dev,
-                          struct comedi_subdevice *s, struct comedi_insn *insn,
-                          unsigned int *data)
-{
-       struct pcidas64_private *devpriv = dev->private;
-       unsigned int channel = CR_CHAN(insn->chanspec);
+       /*
+        * Programming the calib device is slow. Only write the
+        * last data value if the value has changed.
+        */
+       if (insn->n) {
+               unsigned int val = data[insn->n - 1];
 
-       data[0] = devpriv->caldac_state[channel];
+               if (s->readback[chan] != val) {
+                       caldac_write(dev, chan, val);
+                       s->readback[chan] = val;
+               }
+       }
 
-       return 1;
+       return insn->n;
 }
 
 static void ad8402_write(struct comedi_device *dev, unsigned int channel,
@@ -3731,8 +3669,6 @@ static void ad8402_write(struct comedi_device *dev, unsigned int channel,
        unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff);
        static const int ad8402_udelay = 1;
 
-       devpriv->ad8402_state[channel] = value;
-
        register_bits = SELECT_8402_64XX_BIT;
        udelay(ad8402_udelay);
        writew(register_bits, devpriv->main_iobase + CALIBRATION_REG);
@@ -3754,35 +3690,27 @@ static void ad8402_write(struct comedi_device *dev, unsigned int channel,
 }
 
 /* for pci-das6402/16, channel 0 is analog input gain and channel 1 is offset */
-static int ad8402_write_insn(struct comedi_device *dev,
-                            struct comedi_subdevice *s,
-                            struct comedi_insn *insn, unsigned int *data)
+static int cb_pcidas64_ad8402_insn_write(struct comedi_device *dev,
+                                        struct comedi_subdevice *s,
+                                        struct comedi_insn *insn,
+                                        unsigned int *data)
 {
-       struct pcidas64_private *devpriv = dev->private;
-       int channel = CR_CHAN(insn->chanspec);
-
-       /* return immediately if setting hasn't changed, since
-        * programming these things is slow */
-       if (devpriv->ad8402_state[channel] == data[0])
-               return 1;
-
-       devpriv->ad8402_state[channel] = data[0];
-
-       ad8402_write(dev, channel, data[0]);
-
-       return 1;
-}
+       unsigned int chan = CR_CHAN(insn->chanspec);
 
-static int ad8402_read_insn(struct comedi_device *dev,
-                           struct comedi_subdevice *s,
-                           struct comedi_insn *insn, unsigned int *data)
-{
-       struct pcidas64_private *devpriv = dev->private;
-       unsigned int channel = CR_CHAN(insn->chanspec);
+       /*
+        * Programming the calib device is slow. Only write the
+        * last data value if the value has changed.
+        */
+       if (insn->n) {
+               unsigned int val = data[insn->n - 1];
 
-       data[0] = devpriv->ad8402_state[channel];
+               if (s->readback[chan] != val) {
+                       ad8402_write(dev, chan, val);
+                       s->readback[chan] = val;
+               }
+       }
 
-       return 1;
+       return insn->n;
 }
 
 static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address)
@@ -3857,14 +3785,14 @@ static int eeprom_read_insn(struct comedi_device *dev,
        return 1;
 }
 
-/* Allocate and initialize the subdevice structures.
+/*
+ * Allocate and initialize the subdevice structures.
  */
 static int setup_subdevices(struct comedi_device *dev)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
+       const struct pcidas64_board *board = dev->board_ptr;
        struct pcidas64_private *devpriv = dev->private;
        struct comedi_subdevice *s;
-       void __iomem *dio_8255_iobase;
        int i;
        int ret;
 
@@ -3877,24 +3805,26 @@ static int setup_subdevices(struct comedi_device *dev)
        dev->read_subdev = s;
        s->type = COMEDI_SUBD_AI;
        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DITHER | SDF_CMD_READ;
-       if (thisboard->layout == LAYOUT_60XX)
+       if (board->layout == LAYOUT_60XX)
                s->subdev_flags |= SDF_COMMON | SDF_DIFF;
-       else if (thisboard->layout == LAYOUT_64XX)
+       else if (board->layout == LAYOUT_64XX)
                s->subdev_flags |= SDF_DIFF;
        /* XXX Number of inputs in differential mode is ignored */
-       s->n_chan = thisboard->ai_se_chans;
+       s->n_chan = board->ai_se_chans;
        s->len_chanlist = 0x2000;
-       s->maxdata = (1 << thisboard->ai_bits) - 1;
-       s->range_table = thisboard->ai_range_table;
+       s->maxdata = (1 << board->ai_bits) - 1;
+       s->range_table = board->ai_range_table;
        s->insn_read = ai_rinsn;
        s->insn_config = ai_config_insn;
        s->do_cmd = ai_cmd;
        s->do_cmdtest = ai_cmdtest;
        s->cancel = ai_cancel;
-       if (thisboard->layout == LAYOUT_4020) {
+       if (board->layout == LAYOUT_4020) {
                uint8_t data;
-               /*  set adc to read from inputs
-                *  (not internal calibration sources) */
+               /*
+                * set adc to read from inputs
+                * (not internal calibration sources)
+                */
                devpriv->i2c_cal_range_bits = adc_src_4020_bits(4);
                /*  set channels to +-5 volt input ranges */
                for (i = 0; i < s->n_chan; i++)
@@ -3905,20 +3835,24 @@ static int setup_subdevices(struct comedi_device *dev)
 
        /* analog output subdevice */
        s = &dev->subdevices[1];
-       if (thisboard->ao_nchan) {
+       if (board->ao_nchan) {
                s->type = COMEDI_SUBD_AO;
                s->subdev_flags = SDF_READABLE | SDF_WRITABLE |
                                  SDF_GROUND | SDF_CMD_WRITE;
-               s->n_chan = thisboard->ao_nchan;
-               s->maxdata = (1 << thisboard->ao_bits) - 1;
-               s->range_table = thisboard->ao_range_table;
-               s->insn_read = ao_readback_insn;
+               s->n_chan = board->ao_nchan;
+               s->maxdata = (1 << board->ao_bits) - 1;
+               s->range_table = board->ao_range_table;
                s->insn_write = ao_winsn;
-               if (ao_cmd_is_supported(thisboard)) {
+
+               ret = comedi_alloc_subdev_readback(s);
+               if (ret)
+                       return ret;
+
+               if (ao_cmd_is_supported(board)) {
                        dev->write_subdev = s;
                        s->do_cmdtest = ao_cmdtest;
                        s->do_cmd = ao_cmd;
-                       s->len_chanlist = thisboard->ao_nchan;
+                       s->len_chanlist = board->ao_nchan;
                        s->cancel = ao_cancel;
                }
        } else {
@@ -3927,47 +3861,49 @@ static int setup_subdevices(struct comedi_device *dev)
 
        /*  digital input */
        s = &dev->subdevices[2];
-       if (thisboard->layout == LAYOUT_64XX) {
+       if (board->layout == LAYOUT_64XX) {
                s->type = COMEDI_SUBD_DI;
                s->subdev_flags = SDF_READABLE;
                s->n_chan = 4;
                s->maxdata = 1;
                s->range_table = &range_digital;
                s->insn_bits = di_rbits;
-       } else
+       } else {
                s->type = COMEDI_SUBD_UNUSED;
+       }
 
        /*  digital output */
-       if (thisboard->layout == LAYOUT_64XX) {
+       if (board->layout == LAYOUT_64XX) {
                s = &dev->subdevices[3];
                s->type = COMEDI_SUBD_DO;
-               s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+               s->subdev_flags = SDF_WRITABLE;
                s->n_chan = 4;
                s->maxdata = 1;
                s->range_table = &range_digital;
                s->insn_bits = do_wbits;
-       } else
+       } else {
                s->type = COMEDI_SUBD_UNUSED;
+       }
 
        /* 8255 */
        s = &dev->subdevices[4];
-       if (thisboard->has_8255) {
-               if (thisboard->layout == LAYOUT_4020) {
-                       dio_8255_iobase = devpriv->main_iobase + I8255_4020_REG;
-                       subdev_8255_init(dev, s, dio_callback_4020,
-                                        (unsigned long)dio_8255_iobase);
+       if (board->has_8255) {
+               if (board->layout == LAYOUT_4020) {
+                       ret = subdev_8255_init(dev, s, dio_callback_4020,
+                                              I8255_4020_REG);
                } else {
-                       dio_8255_iobase =
-                               devpriv->dio_counter_iobase + DIO_8255_OFFSET;
-                       subdev_8255_init(dev, s, dio_callback,
-                                        (unsigned long)dio_8255_iobase);
+                       ret = subdev_8255_mm_init(dev, s, NULL,
+                                                 DIO_8255_OFFSET);
                }
-       } else
+               if (ret)
+                       return ret;
+       } else {
                s->type = COMEDI_SUBD_UNUSED;
+       }
 
        /*  8 channel dio for 60xx */
        s = &dev->subdevices[5];
-       if (thisboard->layout == LAYOUT_60XX) {
+       if (board->layout == LAYOUT_60XX) {
                s->type = COMEDI_SUBD_DIO;
                s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
                s->n_chan = 8;
@@ -3975,36 +3911,50 @@ static int setup_subdevices(struct comedi_device *dev)
                s->range_table = &range_digital;
                s->insn_config = dio_60xx_config_insn;
                s->insn_bits = dio_60xx_wbits;
-       } else
+       } else {
                s->type = COMEDI_SUBD_UNUSED;
+       }
 
        /*  caldac */
        s = &dev->subdevices[6];
        s->type = COMEDI_SUBD_CALIB;
        s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
        s->n_chan = 8;
-       if (thisboard->layout == LAYOUT_4020)
+       if (board->layout == LAYOUT_4020)
                s->maxdata = 0xfff;
        else
                s->maxdata = 0xff;
-       s->insn_read = calib_read_insn;
-       s->insn_write = calib_write_insn;
-       for (i = 0; i < s->n_chan; i++)
+       s->insn_write = cb_pcidas64_calib_insn_write;
+
+       ret = comedi_alloc_subdev_readback(s);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < s->n_chan; i++) {
                caldac_write(dev, i, s->maxdata / 2);
+               s->readback[i] = s->maxdata / 2;
+       }
 
        /*  2 channel ad8402 potentiometer */
        s = &dev->subdevices[7];
-       if (thisboard->layout == LAYOUT_64XX) {
+       if (board->layout == LAYOUT_64XX) {
                s->type = COMEDI_SUBD_CALIB;
                s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
                s->n_chan = 2;
-               s->insn_read = ad8402_read_insn;
-               s->insn_write = ad8402_write_insn;
                s->maxdata = 0xff;
-               for (i = 0; i < s->n_chan; i++)
+               s->insn_write = cb_pcidas64_ad8402_insn_write;
+
+               ret = comedi_alloc_subdev_readback(s);
+               if (ret)
+                       return ret;
+
+               for (i = 0; i < s->n_chan; i++) {
                        ad8402_write(dev, i, s->maxdata / 2);
-       } else
+                       s->readback[i] = s->maxdata / 2;
+               }
+       } else {
                s->type = COMEDI_SUBD_UNUSED;
+       }
 
        /* serial EEPROM, if present */
        s = &dev->subdevices[8];
@@ -4014,8 +3964,9 @@ static int setup_subdevices(struct comedi_device *dev)
                s->n_chan = 128;
                s->maxdata = 0xffff;
                s->insn_read = eeprom_read_insn;
-       } else
+       } else {
                s->type = COMEDI_SUBD_UNUSED;
+       }
 
        /*  user counter subd XXX */
        s = &dev->subdevices[9];
@@ -4028,21 +3979,20 @@ static int auto_attach(struct comedi_device *dev,
                       unsigned long context)
 {
        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-       const struct pcidas64_board *thisboard = NULL;
+       const struct pcidas64_board *board = NULL;
        struct pcidas64_private *devpriv;
        uint32_t local_range, local_decode;
        int retval;
 
        if (context < ARRAY_SIZE(pcidas64_boards))
-               thisboard = &pcidas64_boards[context];
-       if (!thisboard)
+               board = &pcidas64_boards[context];
+       if (!board)
                return -ENODEV;
-       dev->board_ptr = thisboard;
+       dev->board_ptr = board;
 
-       devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+       devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
        if (!devpriv)
                return -ENOMEM;
-       dev->private = devpriv;
 
        retval = comedi_pci_enable(dev);
        if (retval)
@@ -4050,26 +4000,20 @@ static int auto_attach(struct comedi_device *dev,
        pci_set_master(pcidev);
 
        /* Initialize dev->board_name */
-       dev->board_name = thisboard->name;
+       dev->board_name = board->name;
 
        devpriv->main_phys_iobase = pci_resource_start(pcidev, 2);
        devpriv->dio_counter_phys_iobase = pci_resource_start(pcidev, 3);
 
        devpriv->plx9080_iobase = pci_ioremap_bar(pcidev, 0);
        devpriv->main_iobase = pci_ioremap_bar(pcidev, 2);
-       devpriv->dio_counter_iobase = pci_ioremap_bar(pcidev, 3);
+       dev->mmio = pci_ioremap_bar(pcidev, 3);
 
-       if (!devpriv->plx9080_iobase || !devpriv->main_iobase
-           || !devpriv->dio_counter_iobase) {
+       if (!devpriv->plx9080_iobase || !devpriv->main_iobase || !dev->mmio) {
                dev_warn(dev->class_dev, "failed to remap io memory\n");
                return -ENOMEM;
        }
 
-       DEBUG_PRINT(" plx9080 remapped to 0x%p\n", devpriv->plx9080_iobase);
-       DEBUG_PRINT(" main remapped to 0x%p\n", devpriv->main_iobase);
-       DEBUG_PRINT(" diocounter remapped to 0x%p\n",
-                   devpriv->dio_counter_iobase);
-
        /*  figure out what local addresses are */
        local_range = readl(devpriv->plx9080_iobase + PLX_LAS0RNG_REG) &
                      LRNG_MEM_MASK;
@@ -4084,9 +4028,6 @@ static int auto_attach(struct comedi_device *dev,
        devpriv->local1_iobase = ((uint32_t)devpriv->dio_counter_phys_iobase &
                                  ~local_range) | local_decode;
 
-       DEBUG_PRINT(" local 0 io addr 0x%x\n", devpriv->local0_iobase);
-       DEBUG_PRINT(" local 1 io addr 0x%x\n", devpriv->local1_iobase);
-
        retval = alloc_and_init_dma_members(dev);
        if (retval < 0)
                return retval;
@@ -4097,12 +4038,13 @@ static int auto_attach(struct comedi_device *dev,
                devpriv->hw_revision);
        init_plx9080(dev);
        init_stc_registers(dev);
-       /*  get irq */
-       if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
-                       "cb_pcidas64", dev)) {
+
+       retval = request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
+                            dev->board_name, dev);
+       if (retval) {
                dev_dbg(dev->class_dev, "unable to allocate irq %u\n",
                        pcidev->irq);
-               return -EINVAL;
+               return retval;
        }
        dev->irq = pcidev->irq;
        dev_dbg(dev->class_dev, "irq %u\n", dev->irq);
@@ -4116,55 +4058,22 @@ static int auto_attach(struct comedi_device *dev,
 
 static void detach(struct comedi_device *dev)
 {
-       const struct pcidas64_board *thisboard = comedi_board(dev);
-       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
        struct pcidas64_private *devpriv = dev->private;
-       unsigned int i;
 
        if (dev->irq)
                free_irq(dev->irq, dev);
        if (devpriv) {
-               if (pcidev) {
-                       if (devpriv->plx9080_iobase) {
-                               disable_plx_interrupts(dev);
-                               iounmap(devpriv->plx9080_iobase);
-                       }
-                       if (devpriv->main_iobase)
-                               iounmap(devpriv->main_iobase);
-                       if (devpriv->dio_counter_iobase)
-                               iounmap(devpriv->dio_counter_iobase);
-                       /*  free pci dma buffers */
-                       for (i = 0; i < ai_dma_ring_count(thisboard); i++) {
-                               if (devpriv->ai_buffer[i])
-                                       pci_free_consistent(pcidev,
-                                               DMA_BUFFER_SIZE,
-                                               devpriv->ai_buffer[i],
-                                               devpriv->ai_buffer_bus_addr[i]);
-                       }
-                       for (i = 0; i < AO_DMA_RING_COUNT; i++) {
-                               if (devpriv->ao_buffer[i])
-                                       pci_free_consistent(pcidev,
-                                               DMA_BUFFER_SIZE,
-                                               devpriv->ao_buffer[i],
-                                               devpriv->ao_buffer_bus_addr[i]);
-                       }
-                       /*  free dma descriptors */
-                       if (devpriv->ai_dma_desc)
-                               pci_free_consistent(pcidev,
-                                       sizeof(struct plx_dma_desc) *
-                                       ai_dma_ring_count(thisboard),
-                                       devpriv->ai_dma_desc,
-                                       devpriv->ai_dma_desc_bus_addr);
-                       if (devpriv->ao_dma_desc)
-                               pci_free_consistent(pcidev,
-                                       sizeof(struct plx_dma_desc) *
-                                       AO_DMA_RING_COUNT,
-                                       devpriv->ao_dma_desc,
-                                       devpriv->ao_dma_desc_bus_addr);
+               if (devpriv->plx9080_iobase) {
+                       disable_plx_interrupts(dev);
+                       iounmap(devpriv->plx9080_iobase);
                }
+               if (devpriv->main_iobase)
+                       iounmap(devpriv->main_iobase);
+               if (dev->mmio)
+                       iounmap(dev->mmio);
        }
-       comedi_spriv_free(dev, 4);
        comedi_pci_disable(dev);
+       cb_pcidas64_free_dma(dev);
 }
 
 static struct comedi_driver cb_pcidas64_driver = {
@@ -4181,7 +4090,7 @@ static int cb_pcidas64_pci_probe(struct pci_dev *dev,
                                      id->driver_data);
 }
 
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidas64_pci_table) = {
+static const struct pci_device_id cb_pcidas64_pci_table[] = {
        { PCI_VDEVICE(CB, 0x001d), BOARD_PCIDAS6402_16 },
        { PCI_VDEVICE(CB, 0x001e), BOARD_PCIDAS6402_12 },
        { PCI_VDEVICE(CB, 0x0035), BOARD_PCIDAS64_M1_16 },