fixed ai channel queue setup
authorFrank Mori Hess <fmhess@speakeasy.net>
Thu, 11 Sep 2003 21:27:41 +0000 (21:27 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Thu, 11 Sep 2003 21:27:41 +0000 (21:27 +0000)
comedi/drivers/cb_pcidas64.c

index 5f2c7b417045df18e31666cceb4741c2b16a94c9..c78f23d1599d8fd750d62fc4eebcfa6496cfb849 100644 (file)
@@ -976,14 +976,20 @@ static struct pci_device_id pcidas64_pci_table[] __devinitdata = {
 };
 MODULE_DEVICE_TABLE(pci, pcidas64_pci_table);
 
-/*
- * Useful for shorthand access to the particular board structure
- */
 static inline pcidas64_board* board( const comedi_device *dev )
 {
        return (pcidas64_board *)dev->board_ptr;
 }
 
+static inline unsigned short se_diff_bit_6xxx(comedi_device *dev, int use_differential)
+{
+       if((board(dev)->layout == LAYOUT_64XX && !use_differential) ||
+               (board(dev)->layout == LAYOUT_60XX && use_differential))
+               return ADC_SE_DIFF_BIT;
+       else
+               return 0;
+};
+
 struct ext_clock_info
 {
        unsigned int divisor;   // master clock divisor to use for scans with external master clock
@@ -1400,6 +1406,9 @@ static void init_stc_registers( comedi_device *dev )
                priv(dev)->adc_control1_bits |= ADC_QUEUE_CONFIG_BIT;
        writew( priv(dev)->adc_control1_bits, priv(dev)->main_iobase + ADC_CONTROL1_REG );
 
+       // 6402/16 manual says this register must be initialized to 0xff?
+       writew(0xff, priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG);
+
        bits = SLOW_DAC_BIT | DMA_CH_SELECT_BIT;
        if(board(dev)->layout == LAYOUT_4020)
                bits |= INTERNAL_CLOCK_4020_BITS;
@@ -1414,6 +1423,8 @@ static void init_stc_registers( comedi_device *dev )
        // set fifos to maximum size
        priv(dev)->fifo_size_bits |= DAC_FIFO_BITS;
        set_ai_fifo_segment_length( dev, board(dev)->ai_fifo->max_segment_length );
+
+       disable_ai_pacing(dev);
 };
 
 /*
@@ -1662,9 +1673,7 @@ static int ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsa
                // set gain
                bits |= ai_range_bits_6xxx( dev, CR_RANGE(insn->chanspec) );
                // set single-ended / differential
-               if( ( board(dev)->layout == LAYOUT_64XX && aref != AREF_DIFF ) ||
-                       ( board(dev)->layout == LAYOUT_60XX && aref == AREF_DIFF ) )
-                       bits |= ADC_SE_DIFF_BIT;
+               bits |= se_diff_bit_6xxx(dev, aref == AREF_DIFF);
                if( aref == AREF_COMMON)
                        bits |= ADC_COMMON_BIT;
                // ALT_SOURCE is internal calibration reference
@@ -1686,10 +1695,10 @@ static int ai_rinsn(comedi_device *dev,comedi_subdevice *s,comedi_insn *insn,lsa
                        writew(0, priv(dev)->main_iobase + CALIBRATION_REG);
                }
                bits |= adc_chan_bits( channel );
-               // set start channel, and rest of settings
-               writew(bits, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG);
                // set stop channel
                writew( adc_chan_bits( channel ), priv(dev)->main_iobase + ADC_QUEUE_HIGH_REG );
+               // set start channel, and rest of settings
+               writew(bits, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG);
        }else
        {
                uint8_t old_cal_range_bits = priv(dev)->i2c_cal_range_bits;
@@ -2108,7 +2117,7 @@ static void disable_ai_pacing( comedi_device *dev )
        disable_ai_interrupts( dev );
 
        /* disable pacing, triggering, etc */
-       writew( ADC_DMA_DISABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT,
+       writew( ADC_ENABLE_BIT | ADC_DMA_DISABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT,
                priv(dev)->main_iobase + ADC_CONTROL0_REG );
 
        comedi_spin_lock_irqsave( &dev->spinlock, flags );
@@ -2261,71 +2270,92 @@ static void set_ai_pacing( comedi_device *dev, comedi_cmd *cmd )
        DEBUG_PRINT("scan counter 0x%x\n", scan_counter );
 }
 
-static int ai_cmd(comedi_device *dev,comedi_subdevice *s)
+static int use_internal_queue_6xxx(const comedi_cmd *cmd)
 {
-       comedi_async *async = s->async;
-       comedi_cmd *cmd = &async->cmd;
-       uint32_t bits;
-       unsigned int i;
-       unsigned long flags;
-
-       disable_ai_pacing( dev );
-
-       // make sure internal calibration source is turned off
-       writew(0, priv(dev)->main_iobase + CALIBRATION_REG);
-
-       set_ai_pacing( dev, cmd );
+       int i;
+       for(i = 0; i + 1 < cmd->chanlist_len; i++)
+       {
+               if(CR_CHAN(cmd->chanlist[i + 1]) != CR_CHAN(cmd->chanlist[i]) + 1)
+                       return 0;
+               if(CR_RANGE(cmd->chanlist[i + 1]) != CR_RANGE(cmd->chanlist[i]))
+                       return 0;
+               if(CR_AREF(cmd->chanlist[i + 1]) != CR_AREF(cmd->chanlist[i]))
+                       return 0;
+       }
+       return 1;
+}
 
-       setup_sample_counters( dev, cmd );
+static void setup_channel_queue(comedi_device *dev, const comedi_cmd *cmd)
+{
+       unsigned short bits;
+       int i;
 
        if(board(dev)->layout != LAYOUT_4020)
        {
-               // use external queue
-               priv(dev)->hw_config_bits |= EXT_QUEUE_BIT;
-               writew(priv(dev)->hw_config_bits, priv(dev)->main_iobase + HW_CONFIG_REG);
-
-               /* XXX cannot write to queue fifo while dac fifo is being written to
-               * ( need spinlock, or try to use internal queue instead */
-               // clear queue pointer
-               writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG);
-               // load external queue
-               for(i = 0; i < cmd->chanlist_len; i++)
+               if(use_internal_queue_6xxx(cmd))
                {
+                       priv(dev)->hw_config_bits &= ~EXT_QUEUE_BIT;
+                       writew(priv(dev)->hw_config_bits, priv(dev)->main_iobase + HW_CONFIG_REG);
                        bits = 0;
                        // set channel
-                       bits |= adc_chan_bits( CR_CHAN( cmd->chanlist[i] ) );
+                       bits |= adc_chan_bits(CR_CHAN(cmd->chanlist[0]));
                        // set gain
-                       bits |= ai_range_bits_6xxx( dev, CR_RANGE( cmd->chanlist[i] ) );
+                       bits |= ai_range_bits_6xxx(dev, CR_RANGE(cmd->chanlist[0]));
                        // set single-ended / differential
-                       if( ( board(dev)->layout == LAYOUT_64XX && CR_AREF(cmd->chanlist[i]) != AREF_DIFF ) ||
-                               ( board(dev)->layout == LAYOUT_60XX && CR_AREF(cmd->chanlist[i]) == AREF_DIFF ) )
-                               bits |= ADC_SE_DIFF_BIT;
-                       if(CR_AREF(cmd->chanlist[i]) == AREF_COMMON)
+                       bits |= se_diff_bit_6xxx(dev, CR_AREF(cmd->chanlist[0]) == AREF_DIFF);
+                       if(CR_AREF(cmd->chanlist[0]) == AREF_COMMON)
                                bits |= ADC_COMMON_BIT;
-                       // mark end of queue
-                       if(i == cmd->chanlist_len - 1)
-                               bits |= QUEUE_EOSCAN_BIT | QUEUE_EOSEQ_BIT;
-                       writew(bits, priv(dev)->main_iobase + ADC_QUEUE_FIFO_REG);
+                       // set stop channel
+                       writew(adc_chan_bits(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])), priv(dev)->main_iobase + ADC_QUEUE_HIGH_REG);
+                       // set start channel, and rest of settings
+                       writew(bits, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG);
+               }else
+               {
+                       // use external queue
+                       priv(dev)->hw_config_bits |= EXT_QUEUE_BIT;
+                       writew(priv(dev)->hw_config_bits, priv(dev)->main_iobase + HW_CONFIG_REG);
+                       /* XXX cannot write to queue fifo while dac fifo is being used
+                       * (maybe spinlock?).*/
+                       // clear queue pointer
+                       writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG);
+                       // load external queue
+                       for(i = 0; i < cmd->chanlist_len; i++)
+                       {
+                               bits = 0;
+                               // set channel
+                               bits |= adc_chan_bits(CR_CHAN(cmd->chanlist[i]));
+                               // set gain
+                               bits |= ai_range_bits_6xxx(dev, CR_RANGE(cmd->chanlist[i]));
+                               // set single-ended / differential
+                               bits |= se_diff_bit_6xxx(dev, CR_AREF(cmd->chanlist[i]) == AREF_DIFF);
+                               if(CR_AREF(cmd->chanlist[i]) == AREF_COMMON)
+                                       bits |= ADC_COMMON_BIT;
+                               // mark end of queue
+                               if(i == cmd->chanlist_len - 1)
+                                       bits |= QUEUE_EOSCAN_BIT | QUEUE_EOSEQ_BIT;
+                               writew(bits, priv(dev)->main_iobase + ADC_QUEUE_FIFO_REG);
+                       }
+                       writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG);
+                       // prime queue holding register
+                       writew(0, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG);
                }
-               // prime queue holding register
-               writew(0, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG);
        }else
        {
-               uint8_t old_cal_range_bits = priv(dev)->i2c_cal_range_bits;
+               unsigned short old_cal_range_bits = priv(dev)->i2c_cal_range_bits;
 
                priv(dev)->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK;
                //select BNC inputs
-               priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits( 4 );
+               priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits(4);
                // select ranges
                for(i = 0; i < cmd->chanlist_len; i++)
                {
                        unsigned int channel = CR_CHAN(cmd->chanlist[i]);
                        unsigned int range = CR_RANGE(cmd->chanlist[i]);
 
-                       if( ai_range_bits_6xxx( dev, range ) ) 
-                               priv(dev)->i2c_cal_range_bits |= attenuate_bit( channel );
+                       if(ai_range_bits_6xxx(dev, range))
+                               priv(dev)->i2c_cal_range_bits |= attenuate_bit(channel);
                        else
-                               priv(dev)->i2c_cal_range_bits &= ~attenuate_bit( channel );
+                               priv(dev)->i2c_cal_range_bits &= ~attenuate_bit(channel);
                }
                // update calibration/range i2c register only if necessary, as it is very slow
                if(old_cal_range_bits != priv(dev)->i2c_cal_range_bits)
@@ -2334,6 +2364,26 @@ static int ai_cmd(comedi_device *dev,comedi_subdevice *s)
                        i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data, sizeof(i2c_data));
                }
        }
+}
+
+static int ai_cmd(comedi_device *dev,comedi_subdevice *s)
+{
+       comedi_async *async = s->async;
+       comedi_cmd *cmd = &async->cmd;
+       uint32_t bits;
+       unsigned int i;
+       unsigned long flags;
+
+       disable_ai_pacing( dev );
+
+       // make sure internal calibration source is turned off
+       writew(0, priv(dev)->main_iobase + CALIBRATION_REG);
+
+       set_ai_pacing( dev, cmd );
+
+       setup_sample_counters( dev, cmd );
+
+       setup_channel_queue(dev, cmd);
 
        // clear adc buffer
        writew(0, priv(dev)->main_iobase + ADC_BUFFER_CLEAR_REG);