Added support for changing routing of signals to RTSI pins. Fixed
authorFrank Mori Hess <fmhess@speakeasy.net>
Mon, 23 Oct 2006 19:33:24 +0000 (19:33 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Mon, 23 Oct 2006 19:33:24 +0000 (19:33 +0000)
various bugs in syncronization to external clock sources.

Documentation/comedi/insn_config
comedi/comedi_fops.c
comedi/drivers/ni_mio_common.c
comedi/drivers/ni_pcimio.c
comedi/drivers/ni_stc.h
include/linux/comedi.h

index aa71851c993a84a62f3b90302bad69393aa4f1c5..765f55344a6e6629256854ee2b6eb12bcf2c2ef9 100644 (file)
@@ -166,11 +166,32 @@ Applications:
     invert output on gate?primary:secondary source trigger
 
 
-ID=INSN_CONFIG_ALT_SOURCE: select alternate input source (internal calibration reference)
+ID=INSN_CONFIG_ALT_SOURCE: Select alternate input source.  This is
+       used by comedi_calibrate to configure an
+       analog input channel which can be redirected to read internal calibration
+       references.
+       You need to set the CR_ALT_SOURCE flag in the chanlist/chanspec when
+       reading to read from the configured alternate input source.
 
   [0] - ID
   [1] - source
 
+ID=INSN_CONFIG_SET_ROUTING: This is used to configure an output channel
+       which can be multiplexed to output a variety of
+       different signals (such as NI's RTSI and PFI lines).
+
+  chanspec: channel whose routing is being configured
+
+  [0] - ID
+  [1] - source
+
+ID=INSN_CONFIG_GET_ROUTING: Queries the routing configuration.  See
+       INSN_CONFIG_SET_ROUTING.
+
+  chanspec: channel whose routing is being queried
+
+  [0] - ID
+  [1] - source
 
 ID=INSN_CONFIG_TIMER_1: Deprecated.  Use INSN_CONFIG_SET_CLOCK_SRC and
        TRIG_COUNT or TRIG_TIMER.
@@ -218,3 +239,4 @@ ID=INSN_CONFIG_GET_CLOCK_SRC: Ask which master clock is being used
        [0] - ID
        [1] - clock source
        [2] - clock period (nanoseconds)
+
index a14856a5a7e49802024ae53e7ac26c968c19aa8a..f61339cc72fb8a4b7843729e478b04c1cca03615 100644 (file)
@@ -640,6 +640,8 @@ static int check_insn_config_length(comedi_insn *insn, lsampl_t *data)
        case INSN_CONFIG_8254_READ_STATUS:
        case INSN_CONFIG_SET_GATE_SRC:
        case INSN_CONFIG_GET_GATE_SRC:
+       case INSN_CONFIG_SET_ROUTING:
+       case INSN_CONFIG_GET_ROUTING:
                if(insn->n == 2) return 0;
                break;
        case INSN_CONFIG_SET_CLOCK_SRC:
index f440874d4c2115b33b58b6d3e202fade9ec37406..f5d72f097a5ee0648d20c1d507c7502d190ffef1 100644 (file)
@@ -70,8 +70,8 @@
 #endif
 
 /* A timeout count */
-
 #define NI_TIMEOUT 1000
+static const unsigned old_RTSI_clock_channel = 7;
 
 /* Note: this table must match the ai_gain_* definitions */
 static short ni_gainlkup[][16]={
@@ -3258,11 +3258,11 @@ static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
        devpriv->serial_hw_mode = 0;
 
        /* RTSI */
-       s=dev->subdevices+10;
-       s->type=COMEDI_SUBD_DIO;
-       s->subdev_flags=SDF_READABLE|SDF_WRITABLE|SDF_INTERNAL;
-       s->n_chan=8;
-       s->maxdata=1;
+       s=dev->subdevices + 10;
+       s->type = COMEDI_SUBD_DIO;
+       s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+       s->n_chan = 8;
+       s->maxdata = 1;
        s->insn_bits = ni_rtsi_insn_bits;
        s->insn_config = ni_rtsi_insn_config;
        ni_rtsi_init(dev);
@@ -4310,9 +4310,20 @@ static void ni_rtsi_init(comedi_device *dev)
        {
                rt_printk("ni_set_master_clock failed, bug?");
        }
-       // Standard internal lines are routed to standard RTSI bus lines
-       devpriv->stc_writew(dev, 0x3210, RTSI_Trig_A_Output_Register);
-       devpriv->stc_writew(dev, 0x0654, RTSI_Trig_B_Output_Register);
+       // default internal lines routing to RTSI bus lines
+       devpriv->rtsi_trig_a_output_reg = RTSI_Trig_Output_Bits(0, NI_RTSI_OUTPUT_ADR_START1) |
+               RTSI_Trig_Output_Bits(1, NI_RTSI_OUTPUT_ADR_START2) |
+               RTSI_Trig_Output_Bits(2, NI_RTSI_OUTPUT_SCLKG) |
+               RTSI_Trig_Output_Bits(3, NI_RTSI_OUTPUT_DACUPDN);
+       devpriv->stc_writew(dev, devpriv->rtsi_trig_a_output_reg,
+               RTSI_Trig_A_Output_Register);
+       devpriv->rtsi_trig_b_output_reg = RTSI_Trig_Output_Bits(4, NI_RTSI_OUTPUT_DA_START1) |
+               RTSI_Trig_Output_Bits(5, NI_RTSI_OUTPUT_G_SRC_0) |
+               RTSI_Trig_Output_Bits(6, NI_RTSI_OUTPUT_G_GATE_0);
+       if(boardtype.reg_type == ni_reg_m_series)
+               devpriv->rtsi_trig_b_output_reg |= RTSI_Trig_Output_Bits(7, NI_RTSI_OUTPUT_RTSI_OSC);
+       devpriv->stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
+               RTSI_Trig_B_Output_Register);
 
        // Sets the source and direction of the 4 on board lines
 //     devpriv->stc_writew(dev, 0x0000, RTSI_Board_Register);
@@ -4335,10 +4346,10 @@ static int ni_mseries_get_pll_parameters(unsigned reference_period_ns,
 {
        unsigned div;
        unsigned best_div = 1;
-       static const unsigned max_div = 16;
+       static const unsigned max_div = 0x10;
        unsigned mult;
        unsigned best_mult = 1;
-       static const unsigned max_mult = 256;
+       static const unsigned max_mult = 0x100;
        static const unsigned pico_per_nano = 1000;
 
        const unsigned reference_picosec = reference_period_ns * pico_per_nano;
@@ -4367,12 +4378,20 @@ static int ni_mseries_get_pll_parameters(unsigned reference_period_ns,
        }
        *freq_divider = best_div;
        *freq_multiplier = best_mult;
-       *actual_period_ns = best_period_picosec + (pico_per_nano / 2) / pico_per_nano;
+       static const unsigned fudge_factor_80_to_20Mhz = 4;
+       *actual_period_ns = (best_period_picosec * fudge_factor_80_to_20Mhz + (pico_per_nano / 2)) / pico_per_nano;
        return 0;
 }
 
+static inline unsigned num_configurable_rtsi_channels(comedi_device *dev)
+{
+       if(boardtype.reg_type == ni_reg_m_series) return 8;
+       else return 7;
+}
+
 static int ni_mseries_set_pll_master_clock(comedi_device *dev, unsigned source, unsigned period_ns)
 {
+       if(source == NI_MIO_PLL_PXI10_CLOCK) period_ns = 100;
        // these limits are somewhat arbitrary, but NI advertises 1 to 20MHz range so we'll use that
        static const unsigned min_period_ns = 50;
        static const unsigned max_period_ns = 1000;
@@ -4401,13 +4420,14 @@ static int ni_mseries_set_pll_master_clock(comedi_device *dev, unsigned source,
        case NI_MIO_PLL_PXI10_CLOCK:
                /* pxi clock is 10MHz */
                devpriv->clock_and_fout2 |= MSeries_PLL_In_Source_Select_PXI_Clock10;
-               retval = ni_mseries_get_pll_parameters(100, &freq_divider,
+               retval = ni_mseries_get_pll_parameters(period_ns, &freq_divider,
                        &freq_multiplier, &devpriv->clock_ns);
                if(retval < 0) return retval;
+               break;
        default:
                {
                        unsigned rtsi_channel;
-                       static const unsigned max_rtsi_channel = 7; /* channel 7 should be rtsi clock */
+                       static const unsigned max_rtsi_channel = 7;
                        for(rtsi_channel = 0; rtsi_channel <= max_rtsi_channel; ++rtsi_channel)
                        {
                                if(source == NI_MIO_PLL_RTSI_CLOCK(rtsi_channel))
@@ -4425,7 +4445,8 @@ static int ni_mseries_set_pll_master_clock(comedi_device *dev, unsigned source,
        }
        ni_writew(devpriv->clock_and_fout2, M_Offset_Clock_and_Fout2);
        pll_control_bits |= MSeries_PLL_Divisor_Bits(freq_divider) | MSeries_PLL_Multiplier_Bits(freq_multiplier);
-       // rt_printk("using divider=%i, multiplier=%i for PLL.\n", freq_divider, freq_multiplier);
+//     rt_printk("using divider=%i, multiplier=%i for PLL.  pll_control_bits = 0x%x\n", freq_divider, freq_multiplier, pll_control_bits);
+//     rt_printk("clock_ns=%d\n", devpriv->clock_ns);
        ni_writew(pll_control_bits, M_Offset_PLL_Control);
        devpriv->clock_source = source;
        unsigned i;
@@ -4450,9 +4471,8 @@ static int ni_mseries_set_pll_master_clock(comedi_device *dev, unsigned source,
 
 static int ni_set_master_clock(comedi_device *dev, unsigned source, unsigned period_ns)
 {
-       switch(source)
+       if(source == NI_MIO_INTERNAL_CLOCK)
        {
-       case NI_MIO_INTERNAL_CLOCK:
                devpriv->rtsi_trig_direction_reg &= ~Use_RTSI_Clock_Bit;
                devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
                devpriv->clock_ns = 50;
@@ -4463,63 +4483,135 @@ static int ni_set_master_clock(comedi_device *dev, unsigned source, unsigned per
                        ni_writew(0, M_Offset_PLL_Control);
                }
                devpriv->clock_source = source;
-               break;
-       case NI_MIO_RTSI_CLOCK:
-               devpriv->rtsi_trig_direction_reg |= Use_RTSI_Clock_Bit;
-               devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
-               devpriv->clock_ns = period_ns;
+       }else
+       {
                if(boardtype.reg_type == ni_reg_m_series)
                {
-                       devpriv->clock_and_fout2 &= ~(MSeries_Timebase1_Select_Bit | MSeries_Timebase3_Select_Bit);
-                       devpriv->clock_and_fout2 |= MSeries_RTSI_10MHz_Bit;
-                       ni_writew(devpriv->clock_and_fout2, M_Offset_Clock_and_Fout2);
-                       ni_writew(0, M_Offset_PLL_Control);
+                       return ni_mseries_set_pll_master_clock(dev, source, period_ns);
+               }else
+               {
+                       if(source == NI_MIO_RTSI_CLOCK)
+                       {
+                               devpriv->rtsi_trig_direction_reg |= Use_RTSI_Clock_Bit;
+                               devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
+                               devpriv->clock_ns = period_ns;
+                               devpriv->clock_source = source;
+                       }else
+                               return -EINVAL;
                }
-               devpriv->clock_source = source;
-               break;
-       default:
-               if(boardtype.reg_type == ni_reg_m_series)
+       }
+       return 3;
+}
+
+int ni_valid_rtsi_output_source(comedi_device *dev, unsigned chan, unsigned source)
+{
+       if(chan >= num_configurable_rtsi_channels(dev))
+       {
+               if(chan == old_RTSI_clock_channel)
                {
-                       return ni_mseries_set_pll_master_clock(dev, source, period_ns);
+                       if(source == NI_RTSI_OUTPUT_RTSI_OSC) return 1;
+                       else
+                       {
+                               rt_printk("%s: invalid source for channel=%i, channel %i is always the RTSI clock for pre-m-series boards.\n",
+                                       __FUNCTION__, chan, old_RTSI_clock_channel);
+                               return 0;
+                       }
                }
+               return 0;
+       }
+       switch(source)
+       {
+       case NI_RTSI_OUTPUT_ADR_START1:
+       case NI_RTSI_OUTPUT_ADR_START2:
+       case NI_RTSI_OUTPUT_SCLKG:
+       case NI_RTSI_OUTPUT_DACUPDN:
+       case NI_RTSI_OUTPUT_DA_START1:
+       case NI_RTSI_OUTPUT_G_SRC_0:
+       case NI_RTSI_OUTPUT_G_GATE_0:
+       case NI_RTSI_OUTPUT_RGOUT0:
+       case NI_RTSI_OUTPUT_RTSI_BRD_0:
+               return 1;
+               break;
+       case NI_RTSI_OUTPUT_RTSI_OSC:
+               if(boardtype.reg_type == ni_reg_m_series)
+                       return 1;
+               else return 0;
+               break;
+       default:
+               return 0;
+               break;
+       }
+}
+
+int ni_set_rtsi_routing(comedi_device *dev, unsigned chan, unsigned source)
+{
+       if(ni_valid_rtsi_output_source(dev, chan, source) == 0) return -EINVAL;
+       if(chan < 4)
+       {
+               devpriv->rtsi_trig_a_output_reg &= ~RTSI_Trig_Output_Mask(chan);
+               devpriv->rtsi_trig_a_output_reg |= RTSI_Trig_Output_Bits(chan, source);
+               devpriv->stc_writew(dev, devpriv->rtsi_trig_a_output_reg,
+                       RTSI_Trig_A_Output_Register);
+       }else if(chan < 8)
+       {
+               devpriv->rtsi_trig_b_output_reg &= ~RTSI_Trig_Output_Mask(chan);
+               devpriv->rtsi_trig_b_output_reg |= RTSI_Trig_Output_Bits(chan, source);
+               devpriv->stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
+                       RTSI_Trig_B_Output_Register);
+       }
+       return 2;
+}
+
+unsigned ni_get_rtsi_routing(comedi_device *dev, unsigned chan)
+{
+       if(chan < 4)
+       {
+               return RTSI_Trig_Output_Source(chan, devpriv->rtsi_trig_a_output_reg);
+       }else if(chan < num_configurable_rtsi_channels(dev))
+       {
+               return RTSI_Trig_Output_Source(chan, devpriv->rtsi_trig_b_output_reg);
+       }else
+       {
+               if(chan == old_RTSI_clock_channel)
+                       return NI_RTSI_OUTPUT_RTSI_OSC;
+               rt_printk("%s: invalid channel=%i\n", __FUNCTION__, chan);
                return -EINVAL;
        }
-       return 3;
 }
 
 static int ni_rtsi_insn_config(comedi_device *dev,comedi_subdevice *s,
        comedi_insn *insn,lsampl_t *data)
 {
        unsigned int chan = CR_CHAN(insn->chanspec);
-       static const unsigned RTSI_clock_channel = 7;
        switch(data[0]){
        case INSN_CONFIG_DIO_OUTPUT:
-               if(chan == RTSI_clock_channel)
+               if(chan < num_configurable_rtsi_channels(dev))
                {
-                       devpriv->rtsi_trig_direction_reg |= Drive_RTSI_Clock_Bit;
-               }else
+                       devpriv->rtsi_trig_direction_reg |= RTSI_Output_Bit(chan, boardtype.reg_type == ni_reg_m_series);
+               }else if(chan == old_RTSI_clock_channel)
                {
-                       devpriv->rtsi_trig_direction_reg |= RTSI_Output_Bit(chan);
+                       devpriv->rtsi_trig_direction_reg |= Drive_RTSI_Clock_Bit;
                }
                devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
                break;
        case INSN_CONFIG_DIO_INPUT:
-               if(chan == RTSI_clock_channel)
+               if(chan < num_configurable_rtsi_channels(dev))
                {
-                       devpriv->rtsi_trig_direction_reg &= ~Drive_RTSI_Clock_Bit;
-               }else
+                       devpriv->rtsi_trig_direction_reg &= ~RTSI_Output_Bit(chan, boardtype.reg_type == ni_reg_m_series);
+               }else if(chan == old_RTSI_clock_channel)
                {
-                       devpriv->rtsi_trig_direction_reg &= ~RTSI_Output_Bit(chan);
+                       devpriv->rtsi_trig_direction_reg &= ~Drive_RTSI_Clock_Bit;
                }
                devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
                break;
        case INSN_CONFIG_DIO_QUERY:
-               if(chan == RTSI_clock_channel)
+               if(chan < num_configurable_rtsi_channels(dev))
                {
-                       data[1] = (devpriv->rtsi_trig_direction_reg & Drive_RTSI_Clock_Bit) ? INSN_CONFIG_DIO_OUTPUT : INSN_CONFIG_DIO_INPUT;
-               }else
+                       data[1] = (devpriv->rtsi_trig_direction_reg & RTSI_Output_Bit(chan, boardtype.reg_type == ni_reg_m_series)) ?
+                               INSN_CONFIG_DIO_OUTPUT : INSN_CONFIG_DIO_INPUT;
+               }else if(chan == old_RTSI_clock_channel)
                {
-                       data[1] = (devpriv->rtsi_trig_direction_reg & RTSI_Output_Bit(chan)) ? INSN_CONFIG_DIO_OUTPUT : INSN_CONFIG_DIO_INPUT;
+                       data[1] = (devpriv->rtsi_trig_direction_reg & Drive_RTSI_Clock_Bit) ? INSN_CONFIG_DIO_OUTPUT : INSN_CONFIG_DIO_INPUT;
                }
                return 2;
                break;
@@ -4531,8 +4623,16 @@ static int ni_rtsi_insn_config(comedi_device *dev,comedi_subdevice *s,
                data[2] = devpriv->clock_ns;
                return 3;
                break;
+       case INSN_CONFIG_SET_ROUTING:
+               return ni_set_rtsi_routing(dev, chan, data[1]);
+               break;
+       case INSN_CONFIG_GET_ROUTING:
+               data[1] = ni_get_rtsi_routing(dev, chan);
+               return 2;
+               break;
        default:
                return -EINVAL;
+               break;
        }
        return 1;
 }
index 07be0fb9b9b267a1178814969091790d636a2ae5..f189617b040ec992d9f2478506b27ad6ebdf3ffd 100644 (file)
@@ -1218,12 +1218,7 @@ static void m_series_stc_writew(comedi_device *dev, uint16_t data, int reg)
        case RTSI_Trig_B_Output_Register:
                offset = M_Offset_RTSI_Trig_B_Output;
                break;
-       case RTSI_Board_Register:
-               offset = M_Offset_RTSI_Shared_MUX;
-               break;
        case RTSI_Trig_Direction_Register:
-               /* m-series register map bit shifts all the RTSI direction bits by one,
-               compared to the e-series, but I'm guessing that's a typo. */
                offset = M_Offset_RTSI_Trig_Direction;
                break;
        /* FIXME: DIO_Output_Register (16 bit reg) is replaced by M_Offset_Static_Digital_Output (32 bit)
index 6c48aeadb79cbc0b4b7d2bea5d601e33daf03763..9bfafa836b67fbae177bc0681b0d98c6db770dea 100644 (file)
@@ -310,14 +310,25 @@ enum RTSI_Trig_Direction_Bits
        Drive_RTSI_Clock_Bit = 0x1,
        Use_RTSI_Clock_Bit = 0x2,
 };
-static inline unsigned RTSI_Output_Bit(unsigned channel)
+static inline unsigned RTSI_Output_Bit(unsigned channel, int is_mseries)
 {
-       if(channel > 6)
+       unsigned max_channel;
+       unsigned base_bit_shift;
+       if(is_mseries)
+       {
+               base_bit_shift = 8;
+               max_channel = 7;
+       }else
+       {
+               base_bit_shift = 9;
+               max_channel = 6;
+       }
+       if(channel > max_channel)
        {
                rt_printk("%s: bug, invalid RTSI_channel=%i\n", __FUNCTION__, channel);
                return 0;
        }
-       return 1 << (9 + channel);
+       return 1 << (base_bit_shift + channel);
 }
 
 #define Interrupt_Control_Register     59
@@ -457,6 +468,24 @@ enum AO_Personal_Bits
 };
 #define        RTSI_Trig_A_Output_Register     79
 #define        RTSI_Trig_B_Output_Register     80
+enum RTSI_Trig_B_Output_Bits
+{
+       RTSI_Sub_Selection_1_Bit = 0x8000       // not for m-series
+};
+static inline unsigned RTSI_Trig_Output_Bits(unsigned rtsi_channel, unsigned source)
+{
+       return (source & 0xf) << ((rtsi_channel % 4) * 4);
+};
+static inline unsigned RTSI_Trig_Output_Mask(unsigned rtsi_channel)
+{
+       return 0xf << ((rtsi_channel % 4) * 4);
+};
+// inverse to RTSI_Trig_Output_Bits()
+static inline unsigned RTSI_Trig_Output_Source(unsigned rtsi_channel, unsigned bits)
+{
+       return (bits >> ((rtsi_channel % 4) * 4)) & 0xf;
+};
+
 #define        RTSI_Board_Register             81
 #define Write_Strobe_0_Register                82
 #define Write_Strobe_1_Register                83
@@ -1047,7 +1076,10 @@ enum MSeries_Clock_and_Fout2_Bits
        MSeries_PLL_In_Source_Select_Mask = 0x1f,
        MSeries_Timebase1_Select_Bit = 0x20,    // use PLL for timebase 1
        MSeries_Timebase3_Select_Bit = 0x40,    // use PLL for timebase 3
-       MSeries_RTSI_10MHz_Bit = 0x80   // use 10MHz instead of 20MHz for RTSI clock frequency
+       /* use 10MHz instead of 20MHz for RTSI clock frequency.  Appears
+        to have no effect, at least on pxi-6281, which always uses
+        20MHz rtsi clock frequency */
+       MSeries_RTSI_10MHz_Bit = 0x80
 };
 static inline unsigned MSeries_PLL_In_Source_Select_RTSI_Bits(unsigned RTSI_channel)
 {
@@ -1066,7 +1098,7 @@ enum MSeries_PLL_Control_Bits
        MSeries_PLL_VCO_Mode_200_325MHz_Bits = 0x0,
        MSeries_PLL_VCO_Mode_175_225MHz_Bits  = 0x2000,
        MSeries_PLL_VCO_Mode_100_225MHz_Bits  = 0x4000,
-       MSeries_PLL_VCO_Mode_75_150MHz_Bits   = 0x7000,
+       MSeries_PLL_VCO_Mode_75_150MHz_Bits   = 0x6000,
 };
 static inline unsigned MSeries_PLL_Divisor_Bits(unsigned divisor)
 {
@@ -1147,7 +1179,6 @@ static inline unsigned MSeries_Cal_PWM_Low_Time_Bits(unsigned count)
        return count & 0xffff;
 }
 
-
 #define M_SERIES_EEPROM_SIZE 1024
 
 typedef struct ni_board_struct{
@@ -1240,7 +1271,9 @@ static ni_board ni_boards[];
        volatile unsigned short int_b_enable_reg;                       \
        unsigned short io_bidirection_pin_reg;                  \
        unsigned short rtsi_trig_direction_reg;                 \
-                                                               \
+       unsigned short rtsi_trig_a_output_reg; \
+       unsigned short rtsi_trig_b_output_reg; \
+       \
        unsigned clock_ns; \
        unsigned clock_source; \
        \
index 9a2e1cd8ab5f37ba2fda91ba75c057d14fc481cc..076b088f001ee8f78a06923f362012f409fc55d9 100644 (file)
@@ -248,7 +248,9 @@ enum configuration_ids
        INSN_CONFIG_SET_CLOCK_SRC = 2003,       // Set master clock source
        INSN_CONFIG_GET_CLOCK_SRC = 2004,       // Get master clock source
        INSN_CONFIG_8254_SET_MODE = 4097,
-       INSN_CONFIG_8254_READ_STATUS = 4098
+       INSN_CONFIG_8254_READ_STATUS = 4098,
+       INSN_CONFIG_SET_ROUTING = 4099,
+       INSN_CONFIG_GET_ROUTING = 4109,
 };
 
 
@@ -524,7 +526,8 @@ enum i8254_mode
 enum ni_mio_clock_source
 {
        NI_MIO_INTERNAL_CLOCK = 0,
-       NI_MIO_RTSI_CLOCK = 1,
+       NI_MIO_RTSI_CLOCK = 1,  /* doesn't work for m-series, use NI_MIO_PLL_RTSI_CLOCK() */
+       /* the NI_MIO_PLL_* sources are m-series only */
        NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK = 2,
        NI_MIO_PLL_PXI10_CLOCK = 3,
        NI_MIO_PLL_RTSI0_CLOCK = 4
@@ -534,17 +537,26 @@ static inline unsigned NI_MIO_PLL_RTSI_CLOCK(unsigned rtsi_channel)
        return NI_MIO_PLL_RTSI0_CLOCK + rtsi_channel;
 }
 
-/* RTSI BUS pin usage in standard configuration */
-#define NI_RTSI_STD_AI_START1          0
-#define NI_RTSI_STD_AI_START2          1
-#define NI_RTSI_STD_AI_CONV            2
-#define NI_RTSI_STD_CT1_SRC            3
-#define NI_RTSI_STD_CT1_GATE           4
-#define NI_RTSI_STD_AO_SAMP_CLOCK      5
-#define NI_RTSI_STD_AO_START_TRIG      6
-#define NI_RTSI_STD_AI_SAMP_CLOCK      7
-#define NI_RTSI_STD_CTR0_SRC           8
-#define NI_RTSI_STD_CTR0_GATE          9
+/* Signals which can be routed to an NI RTSI pin with INSN_CONFIG_SET_ROUTING.
+ The numbers are assigned are not arbitrary, they correspond to the bits required
+ to program the board. */
+enum ni_rtsi_output
+{
+       NI_RTSI_OUTPUT_ADR_START1 = 0,
+       NI_RTSI_OUTPUT_ADR_START2 = 1,
+       NI_RTSI_OUTPUT_SCLKG = 2,
+       NI_RTSI_OUTPUT_DACUPDN = 3,
+       NI_RTSI_OUTPUT_DA_START1 = 4,
+       NI_RTSI_OUTPUT_G_SRC_0 = 5,
+       NI_RTSI_OUTPUT_G_GATE_0 = 6,
+       NI_RTSI_OUTPUT_RGOUT0 = 7,
+       NI_RTSI_OUTPUT_RTSI_BRD_0 = 8,
+       NI_RTSI_OUTPUT_RTSI_OSC = 12 /* m-series only */
+};
+static inline unsigned NI_RTSI_OUTPUT_RTSI_BRD(unsigned n)
+{
+       return NI_RTSI_OUTPUT_RTSI_BRD_0 + n;
+}
 
 /* NI External Trigger lines */
 #define NI_EXT_PFI_0                   0