[prev in list] [next in list] [prev in thread] [next in thread] 

List:       comedi
Subject:    Newest patch-scxi
From:       Caleb Tennis <caleb () aei-tech ! com>
Date:       2002-03-20 13:21:41
[Download RAW message or body]

This is a MIME-formatted message.  If you see this text it means that your
E-mail software does not support MIME-formatted messages.


Dave,

I've updated this to work with the latest version of comedi.  Please replace 
the existing patch with this one.




["patch-scxi-0.7.63" (text/x-diff)]

diff -ur comedi-0.7.63/comedi/drivers/ni_mio_common.c comscxi-0.7.63/comedi/drivers/ni_mio_common.c
--- comedi-0.7.63/comedi/drivers/ni_mio_common.c	Sat Jan 26 21:28:10 2002
+++ comscxi-0.7.63/comedi/drivers/ni_mio_common.c	Fri Feb  8 15:08:05 2002
@@ -180,6 +180,10 @@
 };
 
 
+static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
+				 comedi_insn *insn,lsampl_t *data);
+static int ni_serial_insn_bits(comedi_device *dev,comedi_subdevice *s,
+			       comedi_insn *insn,lsampl_t *data);
 
 static int ni_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
 	comedi_insn *insn,lsampl_t *data);
@@ -257,6 +261,12 @@
 #define AIMODE_SCAN		2
 #define AIMODE_SAMPLE		3
 
+/* supported serial clock intervals */
+#define SERIAL_DISABLED         0
+#define SERIAL_600NS          600
+#define SERIAL_1_2US         1200
+#define SERIAL_10US         10000
+
 static void handle_a_interrupt(comedi_device *dev,unsigned short status);
 static void handle_b_interrupt(comedi_device *dev,unsigned short status);
 #ifdef PCIDMA
@@ -1978,9 +1988,9 @@
 static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
 {
 	comedi_subdevice *s;
-	
-	dev->n_subdevices=7;
-	
+
+	dev->n_subdevices=8;
+
 	if(alloc_subdevices(dev)<0)
 		return -ENOMEM;
 	
@@ -2026,7 +2036,7 @@
 	}else{
 		s->type=COMEDI_SUBD_UNUSED;
 	}
-	
+
 	/* digital i/o subdevice */
 	
 	s=dev->subdevices+2;
@@ -2079,14 +2089,28 @@
 	s->n_chan=512;
 	s->maxdata=0xff;
 	s->insn_read=ni_eeprom_insn_read;
-	
+
+	/* SPI serial I/O */
+	s=dev->subdevices+7;
+	s->type=COMEDI_SUBD_SERIAL;
+	s->subdev_flags=SDF_READABLE|SDF_WRITEABLE|SDF_INTERNAL;
+	s->n_chan=1;
+	s->maxdata=0xff;
+	s->insn_bits=ni_serial_insn_bits;
+	s->insn_config=ni_serial_insn_config;
+
+	/* serial configuration */
+	devpriv->serial_interval_ns = 0;
+	devpriv->serial_hw_mode = 0;
+
+
 	/* ai configuration */
 	ni_ai_reset(dev,dev->subdevices+0);
-	win_out(0x1ba0,Clock_and_FOUT_Register);
-
+	devpriv->clock_and_fout = 0x1ba0;
+	win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
 
 	/* analog output configuration */
-	
+
 	devpriv->ao0p=0x0000;
 	ni_writew(devpriv->ao0p,AO_Configuration);
 	devpriv->ao1p=AO_Channel(1);
@@ -2125,6 +2149,203 @@
 	return 0;
 }
 
+static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
+				 comedi_insn *insn,lsampl_t *data)
+{
+#ifdef DEBUG_DIO
+	printk("SPI serial I/O Config %d\n", data[0]);
+#endif
+
+	if(insn->n!=1)return -EINVAL;
+	devpriv->serial_interval_ns = data[0];
+	devpriv->serial_hw_mode = 1;
+	devpriv->dio_control |= DIO_HW_Serial_Enable;
+	switch(data[0]) {
+	default:
+	case SERIAL_DISABLED:
+		/* Disable (or use software serial) */
+		devpriv->serial_hw_mode = 0;
+		devpriv->dio_control &= ~(DIO_HW_Serial_Enable |
+					  DIO_Software_Serial_Control);
+		break;
+	case SERIAL_600NS:
+		/* Warning: this clock speed is too fast to reliably
+		   control SCXI. */
+		devpriv->dio_control &= ~DIO_HW_Serial_Timebase;
+		devpriv->clock_and_fout |= Slow_Internal_Timebase;
+		devpriv->clock_and_fout &= ~DIO_Serial_Out_Divide_By_2;
+		break;
+	case SERIAL_1_2US:
+		devpriv->dio_control &= ~DIO_HW_Serial_Timebase;
+		devpriv->clock_and_fout |= Slow_Internal_Timebase |
+			DIO_Serial_Out_Divide_By_2;
+		break;
+	case SERIAL_10US:
+		devpriv->dio_control |= DIO_HW_Serial_Timebase;
+		devpriv->clock_and_fout |= Slow_Internal_Timebase |
+			DIO_Serial_Out_Divide_By_2;
+		/* Note: DIO_Serial_Out_Divide_By_2 only affects
+		   600ns/1.2us. If you turn divide_by_2 off with the
+		   slow clock, you will still get 10us, except then
+		   all your delays are wrong. */
+		break;
+	}
+	win_out(devpriv->dio_control,DIO_Control_Register);
+	win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
+	return 1;
+}
+
+static int ni_serial_hw_readwrite8(comedi_device *dev,comedi_subdevice *s,
+				   unsigned char data_out,
+				   unsigned char *data_in)
+{
+	unsigned int status1;
+	int err = 0, count = 20;
+
+#ifdef DEBUG_DIO
+	printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out);
+#endif
+
+	if(devpriv->serial_interval_ns == 0) {
+		err = -EINVAL;
+		goto Error;
+	}
+
+	devpriv->dio_output &= ~DIO_Serial_Data_Mask;
+	devpriv->dio_output |= DIO_Serial_Data_Out(data_out);
+	win_out(devpriv->dio_output,DIO_Output_Register);
+
+	status1 = win_in(Joint_Status_1_Register);
+	if(status1 & DIO_Serial_IO_In_Progress_St) {
+		err = -EBUSY;
+		goto Error;
+	}
+
+	devpriv->dio_control |= DIO_HW_Serial_Start;
+	win_out(devpriv->dio_control,DIO_Control_Register);
+	devpriv->dio_control &= ~DIO_HW_Serial_Start;
+
+	/* Wait until STC says we're done, but don't loop infinitely. Also,
+	   we don't have to keep updating the window address for this. */
+	ni_writew(Joint_Status_1_Register,Window_Address);
+	while((status1 = ni_readw(Window_Data)) & DIO_Serial_IO_In_Progress_St) {
+		/* Delay one bit per loop */
+		nanodelay(devpriv->serial_interval_ns);
+		if(--count < 0) {
+			printk("ni_serial_hw_readwrite8: SPI serial I/O didn't finish in time!\n");
+			err = -ETIME;
+			goto Error;
+		}
+	}
+
+	/* Delay for last bit. This delay is absolutely necessary, because
+	   DIO_Serial_IO_In_Progress_St goes high one bit too early. */
+	nanodelay(devpriv->serial_interval_ns);
+
+	if(data_in != NULL) {
+		*data_in = win_in(DIO_Serial_Input_Register);
+#ifdef DEBUG_DIO
+		printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in);
+#endif
+	}
+
+ Error:
+	win_out(devpriv->dio_control,DIO_Control_Register);
+
+	return err;
+}
+
+static int ni_serial_sw_readwrite8(comedi_device *dev,comedi_subdevice *s,
+				   unsigned char data_out,
+				   unsigned char *data_in)
+{
+	unsigned char mask, input = 0;
+
+#ifdef DEBUG_DIO
+	printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out);
+#endif
+
+	/* Wait for one bit before transfer */
+	nanodelay(devpriv->serial_interval_ns);
+
+	for(mask = 0x80; mask; mask >>= 1) {
+		/* Output current bit; note that we cannot touch s->state
+	   because it is a per-subdevice field, and serial is
+		   a separate subdevice from DIO. */
+		devpriv->dio_output &= ~DIO_SDOUT;
+		if(data_out & mask) {
+			devpriv->dio_output |= DIO_SDOUT;
+		}
+		win_out(devpriv->dio_output,DIO_Output_Register);
+
+		/* Assert SDCLK (active low, inverted), wait for half of
+		   the delay, deassert SDCLK, and wait for the other half. */
+		devpriv->dio_control |= DIO_Software_Serial_Control;
+		win_out(devpriv->dio_control,DIO_Control_Register);
+
+		nanodelay(devpriv->serial_interval_ns / 2);
+
+		devpriv->dio_control &= ~DIO_Software_Serial_Control;
+		win_out(devpriv->dio_control,DIO_Control_Register);
+
+		nanodelay(devpriv->serial_interval_ns / 2);
+
+		/* Input current bit */
+		if(ni_readw(DIO_Parallel_Input) & DIO_SDIN) {
+			input |= mask;
+		}
+	}
+#ifdef DEBUG_DIO
+	printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input);
+#endif
+	if(data_in) *data_in = input;
+
+	return 0;
+}
+
+static int ni_serial_insn_bits(comedi_device *dev,comedi_subdevice *s,
+			       comedi_insn *insn,lsampl_t *data)
+{
+	int err = insn->n;
+	lsampl_t data_out, data_in, num_bits;
+	unsigned char byteOut, byteIn;
+
+#ifdef DEBUG_DIO
+	printk("ni_serial_insn_bits: num_bits=0x%x data_out=0x%x\n", data[0],
+	       data[1]);
+#endif
+
+	if(insn->n!=2) return -EINVAL;
+
+	num_bits = data[0];
+
+	if((num_bits % 8) != 0) return -EINVAL;
+
+	data_out = data[1];
+	data_in = 0;
+	while(num_bits > 0) {
+		/* Read from MSB to LSB */
+		data_in <<= 8;
+
+		byteOut = (data_out >> (num_bits - 8)) & 0xff;
+		if(devpriv->serial_hw_mode) {
+			err = ni_serial_hw_readwrite8(dev,s,byteOut,&byteIn);
+		} else if(devpriv->serial_interval_ns > 0) {
+			err = ni_serial_sw_readwrite8(dev,s,byteOut,&byteIn);
+		} else {
+			printk("ni_serial_insn_bits: serial disabled!\n");
+			return -EINVAL;
+		}
+		if(err < 0) return err;
+		data_in |= byteIn;
+
+		/* Write from MSB to LSB */
+		num_bits -= 8;
+	}
+	data[1] = data_in;
+	return insn->n;
+}
+
 
 
 static int ni_8255_callback(int dir,int port,int data,unsigned long arg)
@@ -2608,7 +2829,7 @@
 	// Stop_Mode = 0
 	devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
 	devpriv->gpct_mode[chan] |= G_Stop_Mode(0);
-	
+
 	// Counting_Once = 2 
 	devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));
 	devpriv->gpct_mode[chan] |= G_Counting_Once(2);
@@ -2788,7 +3009,7 @@
 	win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
 	win_out( devpriv->gpct_input_select[chan],G_Input_Select_Register(chan));
 	win_out( 0,G_Autoincrement_Register(chan)); 
-		
+
 	//printk("exit GPCT_Reset\n");
 }
 
@@ -2878,7 +3099,7 @@
 		
 	//printk("in ni_gpct_insn_read, n=%d, data[0]=%d\n",insn->chanspec,data[0]);
 	if(insn->n!=1)return -EINVAL;
-		
+
 	data[0] = GPCT_G_Watch(dev,insn->chanspec);
 		
 	/* for certain modes (period and pulse width measurment), the value

diff -ur comedi-0.7.63/include/linux/comedi.h comscxi-0.7.63/include/linux/comedi.h
--- comedi-0.7.63/include/linux/comedi.h	Wed Oct 24 17:19:13 2001
+++ comscxi-0.7.63/include/linux/comedi.h	Fri Feb  8 15:08:50 2002
@@ -192,7 +192,7 @@
 #define COMEDI_SUBD_MEMORY              8	/* memory, EEPROM, DPRAM */
 #define COMEDI_SUBD_CALIB               9	/* calibration DACs */
 #define COMEDI_SUBD_PROC                10	/* processor, DSP */
-
+#define COMEDI_SUBD_SERIAL		11
 
 #define COMEDI_INPUT			0
 #define COMEDI_OUTPUT			1
diff -ur comedi-0.7.63/include/linux/comedidev.h comscxi-0.7.63/include/linux/comedidev.h
--- comedi-0.7.63/include/linux/comedidev.h	Tue Jan 15 06:59:52 2002
+++ comscxi-0.7.63/include/linux/comedidev.h	Fri Feb  8 15:10:46 2002
@@ -340,6 +340,19 @@
 	return 0;
 }
 
+static inline int nanodelay(unsigned long ns)
+{
+	/* We round up, so the result should always be longer than the
+	 * specified time. It's probably not much more precise than
+	 * using udelay(). Hopefully, one day Linux will have an
+	 * nanodelay() function. */
+	//unsigned long loops_per_us = (loops_per_sec + 999999) / 1000000;
+	//unsigned long loops = ((ns * loops_per_us) + 999) / 1000;
+	/* printk("nanodelay: ns=%ld loops=%ld\n", ns, loops); */
+	udelay((ns + 999) / 1000);
+	//__delay(loops);
+}
+
 
 //#ifdef CONFIG_COMEDI_RT
 #include <linux/comedi_rt.h>

_______________________________________________
comedi mailing list
comedi@stm.lbl.gov
http://stm.lbl.gov/cgi-bin/mailman/listinfo/comedi

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic