Index: comedi/comedi_fops.c
===================================================================
RCS file: /cvs/comedi/comedi/comedi/comedi_fops.c,v
retrieving revision 1.163
diff -u -r1.163 comedi_fops.c
--- comedi/comedi_fops.c	12 Jun 2006 01:10:38 -0000	1.163
+++ comedi/comedi_fops.c	11 Jul 2006 18:47:32 -0000
@@ -637,6 +637,9 @@
 	case INSN_CONFIG_BIDIRECTIONAL_DATA:
 		if( insn->n == 2 ) return 0;
 		break;
+	case INSN_CONFIG_SET_RTSI_CLOCK_MODE:
+		if( insn->n == 2 || insn->n == 3 ) return 0;
+		break;
 	//by default we allow the insn since we don't have checks for all possible cases yet 
 	default:
 		rt_printk("No check for data length of config insn id %i implemented.  Assuming n=%i is correct.\n",
Index: comedi/drivers/ni_mio_common.c
===================================================================
RCS file: /cvs/comedi/comedi/comedi/drivers/ni_mio_common.c,v
retrieving revision 1.255
diff -u -r1.255 ni_mio_common.c
--- comedi/drivers/ni_mio_common.c	19 Apr 2006 02:10:10 -0000	1.255
+++ comedi/drivers/ni_mio_common.c	11 Jul 2006 18:47:35 -0000
@@ -260,7 +260,7 @@
 
 static int ni_8255_callback(int dir,int port,int data,unsigned long arg);
 
-static int ni_ns_to_timer(int *nanosec,int round_mode);
+static int ni_ns_to_timer(comedi_device *dev, int *nanosec,int round_mode);
 
 
 /*GPCT function def's*/
@@ -1615,9 +1615,21 @@
 	}
 }
 
-#define TIMER_BASE 50 /* 20 Mhz base */
+// TIMER_BASE used to be #defined to be 50, but now it must access a
+// device-specific variable since individual devices can use either an
+// external (and not necessarily 20 MHz) clock or the internal 20 MHz
+// clock.  TIMER_BASE should be considered deprecated; use
+// ni_get_timer_base(comedi_device *dev) instead.
+#define TIMER_BASE ni_get_timer_base(dev)
 
-static int ni_ns_to_timer(int *nanosec,int round_mode)
+static inline unsigned int ni_get_timer_base(comedi_device *dev)
+{
+	return devpriv->time_base_ns;
+}
+
+// ni_ns_to_timer is device specific since internal-vs-external clock
+// source is board specific and external clocks need not be 20 MHz.
+static int ni_ns_to_timer(comedi_device *dev, int *nanosec,int round_mode)
 {
 	int divider,base;
 
@@ -1797,13 +1809,13 @@
 
 	if(cmd->scan_begin_src==TRIG_TIMER){
 		tmp=cmd->scan_begin_arg;
-		ni_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);
+		ni_ns_to_timer(dev, &cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);
 		if(tmp!=cmd->scan_begin_arg)err++;
 	}
 	if(cmd->convert_src==TRIG_TIMER){
 		if((boardtype.reg_type != ni_reg_611x) && (boardtype.reg_type != ni_reg_6143)){
 			tmp=cmd->convert_arg;
-			ni_ns_to_timer(&cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
+			ni_ns_to_timer(dev, &cmd->convert_arg,cmd->flags&TRIG_ROUND_MASK);
 			if(tmp!=cmd->convert_arg)err++;
 			if(cmd->scan_begin_src==TRIG_TIMER &&
 			cmd->scan_begin_arg<cmd->convert_arg*cmd->scan_end_arg){
@@ -1951,7 +1963,7 @@
 		devpriv->stc_writew(dev, mode2, AI_Mode_2_Register);
 
 		/* load SI */
-		timer=ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
+		timer=ni_ns_to_timer(dev, &cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
 		devpriv->stc_writel(dev, timer,AI_SI_Load_A_Registers);
 		devpriv->stc_writew(dev, AI_SI_Load,AI_Command_1_Register);
 		break;
@@ -1975,7 +1987,7 @@
 		if( cmd->convert_arg == 0 || cmd->convert_src == TRIG_NOW )
 			timer = 1;
 		else
-			timer=ni_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST);
+			timer=ni_ns_to_timer(dev, &cmd->convert_arg, TRIG_ROUND_NEAREST);
 		devpriv->stc_writew(dev, 1,AI_SI2_Load_A_Register); /* 0,0 does not work. */
 		devpriv->stc_writew(dev, timer,AI_SI2_Load_B_Register);
 
@@ -2483,7 +2495,7 @@
 		comedi_error(dev, "cannot run command without an irq");
 		return -EIO;
 	}
-	trigvar = ni_ns_to_timer(&cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
+	trigvar = ni_ns_to_timer(dev, &cmd->scan_begin_arg,TRIG_ROUND_NEAREST);
 
 	devpriv->stc_writew(dev, AO_Configuration_Start,Joint_Reset_Register);
 
@@ -2690,7 +2702,7 @@
 	/* step 4: fix up any arguments */
 
 	tmp = cmd->scan_begin_arg;
-	ni_ns_to_timer(&cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);
+	ni_ns_to_timer(dev, &cmd->scan_begin_arg,cmd->flags&TRIG_ROUND_MASK);
 	if(tmp!=cmd->scan_begin_arg)err++;
 
 	if(err)return 4;
@@ -3211,7 +3223,7 @@
 	s=dev->subdevices+10;
 	s->type=COMEDI_SUBD_DIO;
 	s->subdev_flags=SDF_READABLE|SDF_WRITABLE|SDF_INTERNAL;
-	s->n_chan=8;
+	s->n_chan=7;
 	s->maxdata=1;
 	s->insn_bits = ni_rtsi_insn_bits;
 	s->insn_config = ni_rtsi_insn_config;
@@ -4120,6 +4132,8 @@
 		//use the fast 20MHz one at this time.  Tim  Ousley 5/1/01
 		//NOTE: This is not the final interface, ideally the user
 		//will never need to know the int. clk. freq.
+		//
+		// TODO: Use ni_get_timer_base(comedi_device *dev) instead?
 		data[1]=50;//50ns = 20MHz = internal timebase of STC
 		break;
 	case GPCT_SET_OPERATION:
@@ -4255,8 +4269,12 @@
 {
 	// Initialises the RTSI bus signal switch to a default state
 	
-	// Set clock mode to internal
+	// Set clock mode to internal and RTSI trigger lines to input
 	devpriv->stc_writew(dev, COMEDI_RTSI_CLOCK_MODE_INTERNAL, RTSI_Trig_Direction_Register);
+	// This initialization of devpriv->time_base_ns "should" be early
+	// enough, but if needed it could be moved elsewhere (e.g.
+	// ni_alloc_private).
+	devpriv->time_base_ns = 50; // 20 MHz
 
 	// Standard internal lines are routed to standard RTSI bus lines
 	devpriv->stc_writew(dev, 0x3210, RTSI_Trig_A_Output_Register);
@@ -4281,15 +4299,49 @@
 {
 	unsigned int chan;
 	unsigned int bit;
+	unsigned int mode;
+	unsigned int ns;
 
 	if(insn->n < 1) return -EINVAL;
 
 	if(data[0] == INSN_CONFIG_SET_RTSI_CLOCK_MODE){
-		if(data[1] > 3)
-			return -EINVAL;
+		// data[1] should be one of COMEDI_RTSI_CLOCK_MODE_*.
+		//
+		// For COMEDI_RTSI_CLOCK_MODE_SLAVE, data[2] can be used to
+		// specify the external timebase period in ns.  If data[2]
+		// is not supplied (e.g. if insn->n == 2), the timebase
+		// period is set to 50 ns (20 MHz).
+		//
+		// For all other clock modes, the timebase period is set to
+		// 50 ns (20 MHz) and data[2], if present, is ignored.
+
+		// Validate data[1]
+		switch(data[1]) {
+			case COMEDI_RTSI_CLOCK_MODE_INTERNAL:
+			case COMEDI_RTSI_CLOCK_MODE_OUTPUT:
+			case COMEDI_RTSI_CLOCK_MODE_SLAVE:
+			case COMEDI_RTSI_CLOCK_MODE_MASTER:
+				break;
+			default:
+				return -EINVAL;
+		}
+
+		mode = data[1];
+		ns = 50;
+
+		// If slave mode is being selected and a timebase period
+		// has been provided, use it and validate it.
+		if(mode == COMEDI_RTSI_CLOCK_MODE_SLAVE && insn->n > 2) {
+			ns = data[2];
+			// Enforce 50 ns minimum period (20 MHz max freq)
+			if(ns < 50) {
+				return -EINVAL;
+			}
+		}
 
+		devpriv->time_base_ns = ns;
 		devpriv->rtsi_trig_direction_reg &= ~0x03;
-		devpriv->rtsi_trig_direction_reg |= data[1];
+		devpriv->rtsi_trig_direction_reg |= mode;
 		devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register);
 	}
 	else {
Index: comedi/drivers/ni_stc.h
===================================================================
RCS file: /cvs/comedi/comedi/comedi/drivers/ni_stc.h,v
retrieving revision 1.85
diff -u -r1.85 ni_stc.h
--- comedi/drivers/ni_stc.h	7 Mar 2006 02:44:34 -0000	1.85
+++ comedi/drivers/ni_stc.h	11 Jul 2006 18:47:36 -0000
@@ -1141,6 +1141,7 @@
 	volatile unsigned short int_b_enable_reg;			\
 	unsigned short io_bidirection_pin_reg;			\
 	unsigned short rtsi_trig_direction_reg;			\
+	unsigned int time_base_ns;				\
 								\
 	unsigned short atrig_mode;				\
 	unsigned short atrig_high;				\

