1 Index: comedi/drivers/ni_mio_common.c
2 ===================================================================
3 RCS file: /var/cvs/comedi/comedi/drivers/ni_mio_common.c,v
4 retrieving revision 1.43
5 diff -u -r1.43 ni_mio_common.c
6 --- comedi/drivers/ni_mio_common.c 2001/02/05 02:58:40 1.43
7 +++ comedi/drivers/ni_mio_common.c 2001/02/05 02:59:48
9 static int ni_dio(comedi_device *dev,comedi_subdevice *s,comedi_trig *it);
12 +static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
13 + comedi_insn *insn,lsampl_t *data);
14 +static int ni_serial_insn_bits(comedi_device *dev,comedi_subdevice *s,
15 + comedi_insn *insn,lsampl_t *data);
18 static int ni_eeprom(comedi_device *dev,comedi_subdevice *s,comedi_trig *it);
22 #define AIMODE_SAMPLE 3
24 +/* supported serial clock intervals */
25 +#define SERIAL_DISABLED 0
26 +#define SERIAL_600NS 600
27 +#define SERIAL_1_2US 1200
28 +#define SERIAL_10US 10000
30 static void ni_E_interrupt(int irq,void *d,struct pt_regs * regs)
32 @@ -1991,6 +2001,203 @@
36 +static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
37 + comedi_insn *insn,lsampl_t *data)
40 + printk("SPI serial I/O Config %d\n", data[0]);
43 + if(insn->n!=1)return -EINVAL;
44 + devpriv->serial_interval_ns = data[0];
45 + devpriv->serial_hw_mode = 1;
46 + devpriv->dio_control |= DIO_HW_Serial_Enable;
49 + case SERIAL_DISABLED:
50 + /* Disable (or use software serial) */
51 + devpriv->serial_hw_mode = 0;
52 + devpriv->dio_control &= ~(DIO_HW_Serial_Enable |
53 + DIO_Software_Serial_Control);
56 + /* Warning: this clock speed is too fast to reliably
58 + devpriv->dio_control &= ~DIO_HW_Serial_Timebase;
59 + devpriv->clock_and_fout |= Slow_Internal_Timebase;
60 + devpriv->clock_and_fout &= ~DIO_Serial_Out_Divide_By_2;
63 + devpriv->dio_control &= ~DIO_HW_Serial_Timebase;
64 + devpriv->clock_and_fout |= Slow_Internal_Timebase |
65 + DIO_Serial_Out_Divide_By_2;
68 + devpriv->dio_control |= DIO_HW_Serial_Timebase;
69 + devpriv->clock_and_fout |= Slow_Internal_Timebase |
70 + DIO_Serial_Out_Divide_By_2;
71 + /* Note: DIO_Serial_Out_Divide_By_2 only affects
72 + 600ns/1.2us. If you turn divide_by_2 off with the
73 + slow clock, you will still get 10us, except then
74 + all your delays are wrong. */
77 + win_out(devpriv->dio_control,DIO_Control_Register);
78 + win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
82 +static int ni_serial_hw_readwrite8(comedi_device *dev,comedi_subdevice *s,
83 + unsigned char data_out,
84 + unsigned char *data_in)
86 + unsigned int status1;
87 + int err = 0, count = 20;
90 + printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out);
93 + if(devpriv->serial_interval_ns == 0) {
98 + devpriv->dio_output &= ~DIO_Serial_Data_Mask;
99 + devpriv->dio_output |= DIO_Serial_Data_Out(data_out);
100 + win_out(devpriv->dio_output,DIO_Output_Register);
102 + status1 = win_in(Joint_Status_1_Register);
103 + if(status1 & DIO_Serial_IO_In_Progress_St) {
108 + devpriv->dio_control |= DIO_HW_Serial_Start;
109 + win_out(devpriv->dio_control,DIO_Control_Register);
110 + devpriv->dio_control &= ~DIO_HW_Serial_Start;
112 + /* Wait until STC says we're done, but don't loop infinitely. Also,
113 + we don't have to keep updating the window address for this. */
114 + ni_writew(Joint_Status_1_Register,Window_Address);
115 + while((status1 = ni_readw(Window_Data)) & DIO_Serial_IO_In_Progress_St) {
116 + /* Delay one bit per loop */
117 + nanodelay(devpriv->serial_interval_ns);
119 + printk("ni_serial_hw_readwrite8: SPI serial I/O didn't finish in time!\n");
125 + /* Delay for last bit. This delay is absolutely necessary, because
126 + DIO_Serial_IO_In_Progress_St goes high one bit too early. */
127 + nanodelay(devpriv->serial_interval_ns);
129 + if(data_in != NULL) {
130 + *data_in = win_in(DIO_Serial_Input_Register);
132 + printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in);
137 + win_out(devpriv->dio_control,DIO_Control_Register);
142 +static int ni_serial_sw_readwrite8(comedi_device *dev,comedi_subdevice *s,
143 + unsigned char data_out,
144 + unsigned char *data_in)
146 + unsigned char mask, input = 0;
149 + printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out);
152 + /* Wait for one bit before transfer */
153 + nanodelay(devpriv->serial_interval_ns);
155 + for(mask = 0x80; mask; mask >>= 1) {
156 + /* Output current bit; note that we cannot touch s->state
157 + because it is a per-subdevice field, and serial is
158 + a separate subdevice from DIO. */
159 + devpriv->dio_output &= ~DIO_SDOUT;
160 + if(data_out & mask) {
161 + devpriv->dio_output |= DIO_SDOUT;
163 + win_out(devpriv->dio_output,DIO_Output_Register);
165 + /* Assert SDCLK (active low, inverted), wait for half of
166 + the delay, deassert SDCLK, and wait for the other half. */
167 + devpriv->dio_control |= DIO_Software_Serial_Control;
168 + win_out(devpriv->dio_control,DIO_Control_Register);
170 + nanodelay(devpriv->serial_interval_ns / 2);
172 + devpriv->dio_control &= ~DIO_Software_Serial_Control;
173 + win_out(devpriv->dio_control,DIO_Control_Register);
175 + nanodelay(devpriv->serial_interval_ns / 2);
177 + /* Input current bit */
178 + if(ni_readw(DIO_Parallel_Input) & DIO_SDIN) {
183 + printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input);
185 + if(data_in) *data_in = input;
190 +static int ni_serial_insn_bits(comedi_device *dev,comedi_subdevice *s,
191 + comedi_insn *insn,lsampl_t *data)
194 + lsampl_t data_out, data_in, num_bits;
195 + unsigned char byteOut, byteIn;
198 + printk("ni_serial_insn_bits: num_bits=0x%x data_out=0x%x\n", data[0],
202 + if(insn->n!=2) return -EINVAL;
204 + num_bits = data[0];
206 + if((num_bits % 8) != 0) return -EINVAL;
208 + data_out = data[1];
210 + while(num_bits > 0) {
211 + /* Read from MSB to LSB */
214 + byteOut = (data_out >> (num_bits - 8)) & 0xff;
215 + if(devpriv->serial_hw_mode) {
216 + err = ni_serial_hw_readwrite8(dev,s,byteOut,&byteIn);
217 + } else if(devpriv->serial_interval_ns > 0) {
218 + err = ni_serial_sw_readwrite8(dev,s,byteOut,&byteIn);
220 + printk("ni_serial_insn_bits: serial disabled!\n");
223 + if(err < 0) return err;
226 + /* Write from MSB to LSB */
236 @@ -2031,7 +2238,7 @@
240 - dev->n_subdevices=7;
241 + dev->n_subdevices=8;
243 if(alloc_subdevices(dev)<0)
245 @@ -2144,11 +2351,24 @@
247 s->trig[0]=ni_eeprom;
251 + /* SPI serial I/O */
252 + s=dev->subdevices+7;
253 + s->type=COMEDI_SUBD_SERIAL;
254 + s->subdev_flags=SDF_READABLE|SDF_WRITEABLE|SDF_INTERNAL;
257 + s->insn_bits=ni_serial_insn_bits;
258 + s->insn_config=ni_serial_insn_config;
260 + /* serial configuration */
261 + devpriv->serial_interval_ns = 0;
262 + devpriv->serial_hw_mode = 0;
264 /* ai configuration */
265 ni_ai_reset(dev,dev->subdevices+0);
266 - win_out(0x1ba0,Clock_and_FOUT_Register);
268 + devpriv->clock_and_fout = 0x1ba0;
269 + win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
271 /* analog output configuration */
273 Index: include/linux/comedi.h
274 ===================================================================
275 RCS file: /var/cvs/comedi/include/linux/comedi.h,v
276 retrieving revision 1.5
277 diff -u -r1.5 comedi.h
278 --- include/linux/comedi.h 2001/01/30 20:19:39 1.5
279 +++ include/linux/comedi.h 2001/02/05 02:59:50
281 #define COMEDI_SUBD_MEMORY 8 /* memory, EEPROM, DPRAM */
282 #define COMEDI_SUBD_CALIB 9 /* calibration DACs */
283 #define COMEDI_SUBD_PROC 10 /* processor, DSP */
285 +#define COMEDI_SUBD_SERIAL 11 /* SPI serial I/O */
287 #define COMEDI_INPUT 0
288 #define COMEDI_OUTPUT 1
289 Index: include/linux/comedidev.h
290 ===================================================================
291 RCS file: /var/cvs/comedi/include/linux/comedidev.h,v
292 retrieving revision 1.8
293 diff -u -r1.8 comedidev.h
294 --- include/linux/comedidev.h 2001/02/05 02:09:19 1.8
295 +++ include/linux/comedidev.h 2001/02/05 02:59:51
300 +static inline int nanodelay(unsigned long ns)
302 + /* We round up, so the result should always be longer than the
303 + * specified time. It's probably not much more precise than
304 + * using udelay(). Hopefully, one day Linux will have an
305 + * nanodelay() function. */
306 + unsigned long loops_per_us = (loops_per_sec + 999999) / 1000000;
307 + unsigned long loops = ((ns * loops_per_us) + 999) / 1000;
308 + /* printk("nanodelay: ns=%ld loops=%ld\n", ns, loops); */
314 extern struct symbol_table comedi_syms;