📄 patch-scxi
字号:
Index: comedi/drivers/ni_mio_common.c===================================================================RCS file: /var/cvs/comedi/comedi/drivers/ni_mio_common.c,vretrieving revision 1.43diff -u -r1.43 ni_mio_common.c--- comedi/drivers/ni_mio_common.c 2001/02/05 02:58:40 1.43+++ comedi/drivers/ni_mio_common.c 2001/02/05 02:59:48@@ -161,6 +161,11 @@ static int ni_dio(comedi_device *dev,comedi_subdevice *s,comedi_trig *it); #endif +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);+ #ifdef USE_TRIG static int ni_eeprom(comedi_device *dev,comedi_subdevice *s,comedi_trig *it); #endif@@ -203,6 +208,11 @@ #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 ni_E_interrupt(int irq,void *d,struct pt_regs * regs) {@@ -1991,6 +2001,203 @@ return 2; } +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;+}+ /* HACK! @@ -2031,7 +2238,7 @@ { comedi_subdevice *s; - dev->n_subdevices=7;+ dev->n_subdevices=8; if(alloc_subdevices(dev)<0) return -ENOMEM;@@ -2144,11 +2351,24 @@ #ifdef USE_TRIG s->trig[0]=ni_eeprom; #endif- ++ /* 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 */ Index: include/linux/comedi.h===================================================================RCS file: /var/cvs/comedi/include/linux/comedi.h,vretrieving revision 1.5diff -u -r1.5 comedi.h--- include/linux/comedi.h 2001/01/30 20:19:39 1.5+++ include/linux/comedi.h 2001/02/05 02:59:50@@ -148,7 +148,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 /* SPI serial I/O */ #define COMEDI_INPUT 0 #define COMEDI_OUTPUT 1Index: include/linux/comedidev.h===================================================================RCS file: /var/cvs/comedi/include/linux/comedidev.h,vretrieving revision 1.8diff -u -r1.8 comedidev.h--- include/linux/comedidev.h 2001/02/05 02:09:19 1.8+++ include/linux/comedidev.h 2001/02/05 02:59:51@@ -276,6 +276,18 @@ 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); */+ __delay(loops);+}+ #ifdef LINUX_V20 extern struct symbol_table comedi_syms;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -