These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / comedi / drivers / adl_pci9118.c
index fb3043d..0dff1db 100644 (file)
 #include "amcc_s5933.h"
 #include "comedi_8254.h"
 
-#define IORANGE_9118   64      /* I hope */
-#define PCI9118_CHANLEN        255     /*
-                                * len of chanlist, some source say 256,
-                                * but reality looks like 255 :-(
-                                */
-
 /*
  * PCI BAR2 Register map (dev->iobase)
  */
 #define PCI9118_AI_FIFO_REG            0x10
 #define PCI9118_AO_REG(x)              (0x10 + ((x) * 4))
 #define PCI9118_AI_STATUS_REG          0x18
-#define PCI9118_AI_STATUS_NFULL                (1 << 8)  /* 0=FIFO full (fatal) */
-#define PCI9118_AI_STATUS_NHFULL       (1 << 7)  /* 0=FIFO half full */
-#define PCI9118_AI_STATUS_NEPTY                (1 << 6)  /* 0=FIFO empty */
-#define PCI9118_AI_STATUS_ACMP         (1 << 5)  /* 1=about trigger complete */
-#define PCI9118_AI_STATUS_DTH          (1 << 4)  /* 1=ext. digital trigger */
-#define PCI9118_AI_STATUS_BOVER                (1 << 3)  /* 1=burst overrun (fatal) */
-#define PCI9118_AI_STATUS_ADOS         (1 << 2)  /* 1=A/D over speed (warn) */
-#define PCI9118_AI_STATUS_ADOR         (1 << 1)  /* 1=A/D overrun (fatal) */
-#define PCI9118_AI_STATUS_ADRDY                (1 << 0)  /* 1=A/D ready */
+#define PCI9118_AI_STATUS_NFULL                BIT(8)  /* 0=FIFO full (fatal) */
+#define PCI9118_AI_STATUS_NHFULL       BIT(7)  /* 0=FIFO half full */
+#define PCI9118_AI_STATUS_NEPTY                BIT(6)  /* 0=FIFO empty */
+#define PCI9118_AI_STATUS_ACMP         BIT(5)  /* 1=about trigger complete */
+#define PCI9118_AI_STATUS_DTH          BIT(4)  /* 1=ext. digital trigger */
+#define PCI9118_AI_STATUS_BOVER                BIT(3)  /* 1=burst overrun (fatal) */
+#define PCI9118_AI_STATUS_ADOS         BIT(2)  /* 1=A/D over speed (warn) */
+#define PCI9118_AI_STATUS_ADOR         BIT(1)  /* 1=A/D overrun (fatal) */
+#define PCI9118_AI_STATUS_ADRDY                BIT(0)  /* 1=A/D ready */
 #define PCI9118_AI_CTRL_REG            0x18
-#define PCI9118_AI_CTRL_UNIP           (1 << 7)  /* 1=unipolar */
-#define PCI9118_AI_CTRL_DIFF           (1 << 6)  /* 1=differential inputs */
-#define PCI9118_AI_CTRL_SOFTG          (1 << 5)  /* 1=8254 software gate */
-#define PCI9118_AI_CTRL_EXTG           (1 << 4)  /* 1=8254 TGIN(pin 46) gate */
-#define PCI9118_AI_CTRL_EXTM           (1 << 3)  /* 1=ext. trigger (pin 44) */
-#define PCI9118_AI_CTRL_TMRTR          (1 << 2)  /* 1=8254 is trigger source */
-#define PCI9118_AI_CTRL_INT            (1 << 1)  /* 1=enable interrupt */
-#define PCI9118_AI_CTRL_DMA            (1 << 0)  /* 1=enable DMA */
+#define PCI9118_AI_CTRL_UNIP           BIT(7)  /* 1=unipolar */
+#define PCI9118_AI_CTRL_DIFF           BIT(6)  /* 1=differential inputs */
+#define PCI9118_AI_CTRL_SOFTG          BIT(5)  /* 1=8254 software gate */
+#define PCI9118_AI_CTRL_EXTG           BIT(4)  /* 1=8254 TGIN(pin 46) gate */
+#define PCI9118_AI_CTRL_EXTM           BIT(3)  /* 1=ext. trigger (pin 44) */
+#define PCI9118_AI_CTRL_TMRTR          BIT(2)  /* 1=8254 is trigger source */
+#define PCI9118_AI_CTRL_INT            BIT(1)  /* 1=enable interrupt */
+#define PCI9118_AI_CTRL_DMA            BIT(0)  /* 1=enable DMA */
 #define PCI9118_DIO_REG                        0x1c
 #define PCI9118_SOFTTRG_REG            0x20
 #define PCI9118_AI_CHANLIST_REG                0x24
 #define PCI9118_AI_BURST_NUM_REG       0x28
 #define PCI9118_AI_AUTOSCAN_MODE_REG   0x2c
 #define PCI9118_AI_CFG_REG             0x30
-#define PCI9118_AI_CFG_PDTRG           (1 << 7)  /* 1=positive trigger */
-#define PCI9118_AI_CFG_PETRG           (1 << 6)  /* 1=positive ext. trigger */
-#define PCI9118_AI_CFG_BSSH            (1 << 5)  /* 1=with sample & hold */
-#define PCI9118_AI_CFG_BM              (1 << 4)  /* 1=burst mode */
-#define PCI9118_AI_CFG_BS              (1 << 3)  /* 1=burst mode start */
-#define PCI9118_AI_CFG_PM              (1 << 2)  /* 1=post trigger */
-#define PCI9118_AI_CFG_AM              (1 << 1)  /* 1=about trigger */
-#define PCI9118_AI_CFG_START           (1 << 0)  /* 1=trigger start */
+#define PCI9118_AI_CFG_PDTRG           BIT(7)  /* 1=positive trigger */
+#define PCI9118_AI_CFG_PETRG           BIT(6)  /* 1=positive ext. trigger */
+#define PCI9118_AI_CFG_BSSH            BIT(5)  /* 1=with sample & hold */
+#define PCI9118_AI_CFG_BM              BIT(4)  /* 1=burst mode */
+#define PCI9118_AI_CFG_BS              BIT(3)  /* 1=burst mode start */
+#define PCI9118_AI_CFG_PM              BIT(2)  /* 1=post trigger */
+#define PCI9118_AI_CFG_AM              BIT(1)  /* 1=about trigger */
+#define PCI9118_AI_CFG_START           BIT(0)  /* 1=trigger start */
 #define PCI9118_FIFO_RESET_REG         0x34
 #define PCI9118_INT_CTRL_REG           0x38
-#define PCI9118_INT_CTRL_TIMER         (1 << 3)  /* timer interrupt */
-#define PCI9118_INT_CTRL_ABOUT         (1 << 2)  /* about trigger complete */
-#define PCI9118_INT_CTRL_HFULL         (1 << 1)  /* A/D FIFO half full */
-#define PCI9118_INT_CTRL_DTRG          (1 << 0)  /* ext. digital trigger */
+#define PCI9118_INT_CTRL_TIMER         BIT(3)  /* timer interrupt */
+#define PCI9118_INT_CTRL_ABOUT         BIT(2)  /* about trigger complete */
+#define PCI9118_INT_CTRL_HFULL         BIT(1)  /* A/D FIFO half full */
+#define PCI9118_INT_CTRL_DTRG          BIT(0)  /* ext. digital trigger */
 
 #define START_AI_EXT   0x01    /* start measure on external trigger */
 #define STOP_AI_EXT    0x02    /* stop measure on external trigger */
 #define STOP_AI_INT    0x08    /* stop measure on internal trigger */
 
-#define PCI9118_HALF_FIFO_SZ   (1024 / 2)
-
 static const struct comedi_lrange pci9118_ai_range = {
        8, {
                BIP_RANGE(5),
@@ -169,11 +161,6 @@ static const struct comedi_lrange pci9118hg_ai_range = {
        }
 };
 
-#define PCI9118_BIPOLAR_RANGES 4       /*
-                                        * used for test on mixture
-                                        * of BIP/UNI ranges
-                                        */
-
 enum pci9118_boardid {
        BOARD_PCI9118DG,
        BOARD_PCI9118HG,
@@ -296,51 +283,44 @@ static void pci9118_ai_reset_fifo(struct comedi_device *dev)
        outl(0, dev->iobase + PCI9118_FIFO_RESET_REG);
 }
 
-static int check_channel_list(struct comedi_device *dev,
-                             struct comedi_subdevice *s, int n_chan,
-                             unsigned int *chanlist, int frontadd, int backadd)
+static int pci9118_ai_check_chanlist(struct comedi_device *dev,
+                                    struct comedi_subdevice *s,
+                                    struct comedi_cmd *cmd)
 {
        struct pci9118_private *devpriv = dev->private;
-       unsigned int i, differencial = 0, bipolar = 0;
+       unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
+       unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
+       int i;
 
-       /* correct channel and range number check itself comedi/range.c */
-       if (n_chan < 1) {
-               dev_err(dev->class_dev, "range/channel list is empty!\n");
+       /* single channel scans are always ok */
+       if (cmd->chanlist_len == 1)
                return 0;
-       }
-       if ((frontadd + n_chan + backadd) > s->len_chanlist) {
-               dev_err(dev->class_dev,
-                       "range/channel list is too long for actual configuration!\n");
-               return 0;
-       }
 
-       if (CR_AREF(chanlist[0]) == AREF_DIFF)
-               differencial = 1;       /* all input must be diff */
-       if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES)
-               bipolar = 1;    /* all input must be bipolar */
-       if (n_chan > 1)
-               for (i = 1; i < n_chan; i++) {  /* check S.E/diff */
-                       if ((CR_AREF(chanlist[i]) == AREF_DIFF) !=
-                           (differencial)) {
-                               dev_err(dev->class_dev,
-                                       "Differential and single ended inputs can't be mixed!\n");
-                               return 0;
-                       }
-                       if ((CR_RANGE(chanlist[i]) < PCI9118_BIPOLAR_RANGES) !=
-                           (bipolar)) {
-                               dev_err(dev->class_dev,
-                                       "Bipolar and unipolar ranges can't be mixed!\n");
-                               return 0;
-                       }
-                       if (!devpriv->usemux && differencial &&
-                           (CR_CHAN(chanlist[i]) >= (s->n_chan / 2))) {
-                               dev_err(dev->class_dev,
-                                       "AREF_DIFF is only available for the first 8 channels!\n");
-                               return 0;
-                       }
+       for (i = 1; i < cmd->chanlist_len; i++) {
+               unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+               unsigned int range = CR_RANGE(cmd->chanlist[i]);
+               unsigned int aref = CR_AREF(cmd->chanlist[i]);
+
+               if (aref != aref0) {
+                       dev_err(dev->class_dev,
+                               "Differential and single ended inputs can't be mixed!\n");
+                       return -EINVAL;
+               }
+               if (comedi_range_is_bipolar(s, range) !=
+                   comedi_range_is_bipolar(s, range0)) {
+                       dev_err(dev->class_dev,
+                               "Bipolar and unipolar ranges can't be mixed!\n");
+                       return -EINVAL;
                }
+               if (!devpriv->usemux && aref == AREF_DIFF &&
+                   (chan >= (s->n_chan / 2))) {
+                       dev_err(dev->class_dev,
+                               "AREF_DIFF is only available for the first 8 channels!\n");
+                       return -EINVAL;
+               }
+       }
 
-       return 1;
+       return 0;
 }
 
 static void pci9118_set_chanlist(struct comedi_device *dev,
@@ -406,8 +386,8 @@ static void pci9118_set_chanlist(struct comedi_device *dev,
        /* udelay(100); important delay, or first sample will be crippled */
 }
 
-static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev,
-                                             unsigned int next_buf)
+static void pci9118_ai_mode4_switch(struct comedi_device *dev,
+                                   unsigned int next_buf)
 {
        struct pci9118_private *devpriv = dev->private;
        struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[next_buf];
@@ -421,9 +401,9 @@ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev,
        outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
 }
 
-static unsigned int valid_samples_in_act_dma_buf(struct comedi_device *dev,
-                                                struct comedi_subdevice *s,
-                                                unsigned int n_raw_samples)
+static unsigned int pci9118_ai_samples_ready(struct comedi_device *dev,
+                                            struct comedi_subdevice *s,
+                                            unsigned int n_raw_samples)
 {
        struct pci9118_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
@@ -477,7 +457,7 @@ static unsigned int valid_samples_in_act_dma_buf(struct comedi_device *dev,
        return n_samples;
 }
 
-static void move_block_from_dma(struct comedi_device *dev,
+static void pci9118_ai_dma_xfer(struct comedi_device *dev,
                                struct comedi_subdevice *s,
                                unsigned short *dma_buffer,
                                unsigned int n_raw_samples)
@@ -634,8 +614,8 @@ static void pci9118_ai_munge(struct comedi_device *dev,
        }
 }
 
-static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
-                                          struct comedi_subdevice *s)
+static void pci9118_ai_get_onesample(struct comedi_device *dev,
+                                    struct comedi_subdevice *s)
 {
        struct pci9118_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
@@ -651,8 +631,8 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev,
        }
 }
 
-static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
-                                    struct comedi_subdevice *s)
+static void pci9118_ai_get_dma(struct comedi_device *dev,
+                              struct comedi_subdevice *s)
 {
        struct pci9118_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
@@ -662,21 +642,19 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
        bool more_dma;
 
        /* determine whether more DMA buffers to do after this one */
-       n_valid = valid_samples_in_act_dma_buf(dev, s, n_all);
+       n_valid = pci9118_ai_samples_ready(dev, s, n_all);
        more_dma = n_valid < comedi_nsamples_left(s, n_valid + 1);
 
        /* switch DMA buffers and restart DMA if double buffering */
        if (more_dma && devpriv->dma_doublebuf) {
                devpriv->dma_actbuf = 1 - devpriv->dma_actbuf;
                pci9118_amcc_setup_dma(dev, devpriv->dma_actbuf);
-               if (devpriv->ai_do == 4) {
-                       interrupt_pci9118_ai_mode4_switch(dev,
-                                                         devpriv->dma_actbuf);
-               }
+               if (devpriv->ai_do == 4)
+                       pci9118_ai_mode4_switch(dev, devpriv->dma_actbuf);
        }
 
        if (n_all)
-               move_block_from_dma(dev, s, dmabuf->virt, n_all);
+               pci9118_ai_dma_xfer(dev, s, dmabuf->virt, n_all);
 
        if (!devpriv->ai_neverending) {
                if (s->async->scans_done >= cmd->stop_arg)
@@ -690,7 +668,7 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev,
        if (more_dma && !devpriv->dma_doublebuf) {
                pci9118_amcc_setup_dma(dev, 0);
                if (devpriv->ai_do == 4)
-                       interrupt_pci9118_ai_mode4_switch(dev, 0);
+                       pci9118_ai_mode4_switch(dev, 0);
        }
 }
 
@@ -779,9 +757,9 @@ static irqreturn_t pci9118_interrupt(int irq, void *d)
        }
 
        if (devpriv->usedma)
-               interrupt_pci9118_ai_dma(dev, s);
+               pci9118_ai_get_dma(dev, s);
        else
-               interrupt_pci9118_ai_onesample(dev, s);
+               pci9118_ai_get_onesample(dev, s);
 
 interrupt_exit:
        comedi_handle_events(dev, s);
@@ -816,17 +794,18 @@ static int pci9118_ai_inttrig(struct comedi_device *dev,
        return 1;
 }
 
-static int Compute_and_setup_dma(struct comedi_device *dev,
-                                struct comedi_subdevice *s)
+static int pci9118_ai_setup_dma(struct comedi_device *dev,
+                               struct comedi_subdevice *s)
 {
        struct pci9118_private *devpriv = dev->private;
        struct comedi_cmd *cmd = &s->async->cmd;
        struct pci9118_dmabuf *dmabuf0 = &devpriv->dmabuf[0];
        struct pci9118_dmabuf *dmabuf1 = &devpriv->dmabuf[1];
-       unsigned int dmalen0, dmalen1, i;
+       unsigned int dmalen0 = dmabuf0->size;
+       unsigned int dmalen1 = dmabuf1->size;
+       unsigned int scan_bytes = devpriv->ai_n_realscanlen *
+                                 comedi_bytes_per_sample(s);
 
-       dmalen0 = dmabuf0->size;
-       dmalen1 = dmabuf1->size;
        /* isn't output buff smaller that our DMA buff? */
        if (dmalen0 > s->async->prealloc_bufsz) {
                /* align to 32bit down */
@@ -839,15 +818,15 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
 
        /* we want wake up every scan? */
        if (devpriv->ai_flags & CMDF_WAKE_EOS) {
-               if (dmalen0 < (devpriv->ai_n_realscanlen << 1)) {
+               if (dmalen0 < scan_bytes) {
                        /* uff, too short DMA buffer, disable EOS support! */
                        devpriv->ai_flags &= (~CMDF_WAKE_EOS);
                        dev_info(dev->class_dev,
                                 "WAR: DMA0 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n",
-                                 dmalen0, devpriv->ai_n_realscanlen << 1);
+                                 dmalen0, scan_bytes);
                } else {
                        /* short first DMA buffer to one scan */
-                       dmalen0 = devpriv->ai_n_realscanlen << 1;
+                       dmalen0 = scan_bytes;
                        if (dmalen0 < 4) {
                                dev_info(dev->class_dev,
                                         "ERR: DMA0 buf len bug? (%d<4)\n",
@@ -857,15 +836,15 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
                }
        }
        if (devpriv->ai_flags & CMDF_WAKE_EOS) {
-               if (dmalen1 < (devpriv->ai_n_realscanlen << 1)) {
+               if (dmalen1 < scan_bytes) {
                        /* uff, too short DMA buffer, disable EOS support! */
                        devpriv->ai_flags &= (~CMDF_WAKE_EOS);
                        dev_info(dev->class_dev,
                                 "WAR: DMA1 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n",
-                                dmalen1, devpriv->ai_n_realscanlen << 1);
+                                dmalen1, scan_bytes);
                } else {
                        /* short second DMA buffer to one scan */
-                       dmalen1 = devpriv->ai_n_realscanlen << 1;
+                       dmalen1 = scan_bytes;
                        if (dmalen1 < 4) {
                                dev_info(dev->class_dev,
                                         "ERR: DMA1 buf len bug? (%d<4)\n",
@@ -877,45 +856,39 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
 
        /* transfer without CMDF_WAKE_EOS */
        if (!(devpriv->ai_flags & CMDF_WAKE_EOS)) {
+               unsigned int tmp;
+
                /* if it's possible then align DMA buffers to length of scan */
-               i = dmalen0;
-               dmalen0 =
-                   (dmalen0 / (devpriv->ai_n_realscanlen << 1)) *
-                   (devpriv->ai_n_realscanlen << 1);
+               tmp = dmalen0;
+               dmalen0 = (dmalen0 / scan_bytes) * scan_bytes;
                dmalen0 &= ~3L;
                if (!dmalen0)
-                       dmalen0 = i;    /* uff. very long scan? */
-               i = dmalen1;
-               dmalen1 =
-                   (dmalen1 / (devpriv->ai_n_realscanlen << 1)) *
-                   (devpriv->ai_n_realscanlen << 1);
+                       dmalen0 = tmp;  /* uff. very long scan? */
+               tmp = dmalen1;
+               dmalen1 = (dmalen1 / scan_bytes) * scan_bytes;
                dmalen1 &= ~3L;
                if (!dmalen1)
-                       dmalen1 = i;    /* uff. very long scan? */
+                       dmalen1 = tmp;  /* uff. very long scan? */
                /*
                 * if measure isn't neverending then test, if it fits whole
                 * into one or two DMA buffers
                 */
                if (!devpriv->ai_neverending) {
+                       unsigned long long scanlen;
+
+                       scanlen = (unsigned long long)scan_bytes *
+                                 cmd->stop_arg;
+
                        /* fits whole measure into one DMA buffer? */
-                       if (dmalen0 >
-                           ((devpriv->ai_n_realscanlen << 1) *
-                            cmd->stop_arg)) {
-                               dmalen0 =
-                                   (devpriv->ai_n_realscanlen << 1) *
-                                   cmd->stop_arg;
+                       if (dmalen0 > scanlen) {
+                               dmalen0 = scanlen;
                                dmalen0 &= ~3L;
-                       } else {        /*
-                                        * fits whole measure into
-                                        * two DMA buffer?
-                                        */
-                               if (dmalen1 >
-                                   ((devpriv->ai_n_realscanlen << 1) *
-                                    cmd->stop_arg - dmalen0))
-                                       dmalen1 =
-                                           (devpriv->ai_n_realscanlen << 1) *
-                                           cmd->stop_arg - dmalen0;
-                               dmalen1 &= ~3L;
+                       } else {
+                               /* fits whole measure into two DMA buffer? */
+                               if (dmalen1 > (scanlen - dmalen0)) {
+                                       dmalen1 = scanlen - dmalen0;
+                                       dmalen1 &= ~3L;
+                               }
                        }
                }
        }
@@ -945,6 +918,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        struct comedi_8254 *pacer = dev->pacer;
        struct comedi_cmd *cmd = &s->async->cmd;
        unsigned int addchans = 0;
+       unsigned int scanlen;
 
        devpriv->ai12_startstop = 0;
        devpriv->ai_flags = cmd->flags;
@@ -1030,19 +1004,20 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
                }
        }
        /* well, we now know what must be all added */
-       devpriv->ai_n_realscanlen =     /*
-                                        * what we must take from card in real
-                                        * to have cmd->scan_end_arg on output?
-                                        */
-           (devpriv->ai_add_front + cmd->chanlist_len +
-            devpriv->ai_add_back) * (cmd->scan_end_arg /
-                                     cmd->chanlist_len);
-
-       /* check and setup channel list */
-       if (!check_channel_list(dev, s, cmd->chanlist_len,
-                               cmd->chanlist, devpriv->ai_add_front,
-                               devpriv->ai_add_back))
+       scanlen = devpriv->ai_add_front + cmd->chanlist_len +
+                 devpriv->ai_add_back;
+       /*
+        * what we must take from card in real to have cmd->scan_end_arg
+        * on output?
+        */
+       devpriv->ai_n_realscanlen = scanlen *
+                                   (cmd->scan_end_arg / cmd->chanlist_len);
+
+       if (scanlen > s->len_chanlist) {
+               dev_err(dev->class_dev,
+                       "range/channel list is too long for actual configuration!\n");
                return -EINVAL;
+       }
 
        /*
         * Configure analog input and load the chanlist.
@@ -1141,7 +1116,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        devpriv->ai_act_dmapos = 0;
 
        if (devpriv->usedma) {
-               Compute_and_setup_dma(dev, s);
+               pci9118_ai_setup_dma(dev, s);
 
                outl(0x02000000 | AINT_WRITE_COMPL,
                     devpriv->iobase_a + AMCC_OP_REG_INTCSR);
@@ -1205,9 +1180,6 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev,
        if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT)
                err |= -EINVAL;
 
-       if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT)
-               err |= -EINVAL;
-
        if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) &&
            (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW))))
                err |= -EINVAL;
@@ -1315,10 +1287,13 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev,
        if (err)
                return 4;
 
+       /* Step 5: check channel list if it exists */
+
        if (cmd->chanlist)
-               if (!check_channel_list(dev, s, cmd->chanlist_len,
-                                       cmd->chanlist, 0, 0))
-                       return 5;       /* incorrect channels list */
+               err |= pci9118_ai_check_chanlist(dev, s, cmd);
+
+       if (err)
+               return 5;
 
        return 0;
 }
@@ -1608,7 +1583,7 @@ static int pci9118_common_attach(struct comedi_device *dev,
        if (dev->irq) {
                dev->read_subdev = s;
                s->subdev_flags |= SDF_CMD_READ;
-               s->len_chanlist = PCI9118_CHANLEN;
+               s->len_chanlist = 255;
                s->do_cmdtest   = pci9118_ai_cmdtest;
                s->do_cmd       = pci9118_ai_cmd;
                s->cancel       = pci9118_ai_cancel;