1 diff -ur comedi-0.7.63/comedi/drivers/ni_mio_common.c comscxi-0.7.63/comedi/drivers/ni_mio_common.c
2 --- comedi-0.7.63/comedi/drivers/ni_mio_common.c Sat Jan 26 21:28:10 2002
3 +++ comscxi-0.7.63/comedi/drivers/ni_mio_common.c Fri Feb 8 15:08:05 2002
8 +static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
9 + comedi_insn *insn,lsampl_t *data);
10 +static int ni_serial_insn_bits(comedi_device *dev,comedi_subdevice *s,
11 + comedi_insn *insn,lsampl_t *data);
13 static int ni_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
14 comedi_insn *insn,lsampl_t *data);
17 #define AIMODE_SAMPLE 3
19 +/* supported serial clock intervals */
20 +#define SERIAL_DISABLED 0
21 +#define SERIAL_600NS 600
22 +#define SERIAL_1_2US 1200
23 +#define SERIAL_10US 10000
25 static void handle_a_interrupt(comedi_device *dev,unsigned short status);
26 static void handle_b_interrupt(comedi_device *dev,unsigned short status);
29 static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
33 - dev->n_subdevices=7;
36 + dev->n_subdevices=8;
38 if(alloc_subdevices(dev)<0)
43 s->type=COMEDI_SUBD_UNUSED;
47 /* digital i/o subdevice */
50 @@ -2079,14 +2089,28 @@
53 s->insn_read=ni_eeprom_insn_read;
56 + /* SPI serial I/O */
57 + s=dev->subdevices+7;
58 + s->type=COMEDI_SUBD_SERIAL;
59 + s->subdev_flags=SDF_READABLE|SDF_WRITEABLE|SDF_INTERNAL;
62 + s->insn_bits=ni_serial_insn_bits;
63 + s->insn_config=ni_serial_insn_config;
65 + /* serial configuration */
66 + devpriv->serial_interval_ns = 0;
67 + devpriv->serial_hw_mode = 0;
70 /* ai configuration */
71 ni_ai_reset(dev,dev->subdevices+0);
72 - win_out(0x1ba0,Clock_and_FOUT_Register);
74 + devpriv->clock_and_fout = 0x1ba0;
75 + win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
77 /* analog output configuration */
81 ni_writew(devpriv->ao0p,AO_Configuration);
82 devpriv->ao1p=AO_Channel(1);
83 @@ -2125,6 +2149,203 @@
87 +static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
88 + comedi_insn *insn,lsampl_t *data)
91 + printk("SPI serial I/O Config %d\n", data[0]);
94 + if(insn->n!=1)return -EINVAL;
95 + devpriv->serial_interval_ns = data[0];
96 + devpriv->serial_hw_mode = 1;
97 + devpriv->dio_control |= DIO_HW_Serial_Enable;
100 + case SERIAL_DISABLED:
101 + /* Disable (or use software serial) */
102 + devpriv->serial_hw_mode = 0;
103 + devpriv->dio_control &= ~(DIO_HW_Serial_Enable |
104 + DIO_Software_Serial_Control);
107 + /* Warning: this clock speed is too fast to reliably
109 + devpriv->dio_control &= ~DIO_HW_Serial_Timebase;
110 + devpriv->clock_and_fout |= Slow_Internal_Timebase;
111 + devpriv->clock_and_fout &= ~DIO_Serial_Out_Divide_By_2;
114 + devpriv->dio_control &= ~DIO_HW_Serial_Timebase;
115 + devpriv->clock_and_fout |= Slow_Internal_Timebase |
116 + DIO_Serial_Out_Divide_By_2;
119 + devpriv->dio_control |= DIO_HW_Serial_Timebase;
120 + devpriv->clock_and_fout |= Slow_Internal_Timebase |
121 + DIO_Serial_Out_Divide_By_2;
122 + /* Note: DIO_Serial_Out_Divide_By_2 only affects
123 + 600ns/1.2us. If you turn divide_by_2 off with the
124 + slow clock, you will still get 10us, except then
125 + all your delays are wrong. */
128 + win_out(devpriv->dio_control,DIO_Control_Register);
129 + win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
133 +static int ni_serial_hw_readwrite8(comedi_device *dev,comedi_subdevice *s,
134 + unsigned char data_out,
135 + unsigned char *data_in)
137 + unsigned int status1;
138 + int err = 0, count = 20;
141 + printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out);
144 + if(devpriv->serial_interval_ns == 0) {
149 + devpriv->dio_output &= ~DIO_Serial_Data_Mask;
150 + devpriv->dio_output |= DIO_Serial_Data_Out(data_out);
151 + win_out(devpriv->dio_output,DIO_Output_Register);
153 + status1 = win_in(Joint_Status_1_Register);
154 + if(status1 & DIO_Serial_IO_In_Progress_St) {
159 + devpriv->dio_control |= DIO_HW_Serial_Start;
160 + win_out(devpriv->dio_control,DIO_Control_Register);
161 + devpriv->dio_control &= ~DIO_HW_Serial_Start;
163 + /* Wait until STC says we're done, but don't loop infinitely. Also,
164 + we don't have to keep updating the window address for this. */
165 + ni_writew(Joint_Status_1_Register,Window_Address);
166 + while((status1 = ni_readw(Window_Data)) & DIO_Serial_IO_In_Progress_St) {
167 + /* Delay one bit per loop */
168 + nanodelay(devpriv->serial_interval_ns);
170 + printk("ni_serial_hw_readwrite8: SPI serial I/O didn't finish in time!\n");
176 + /* Delay for last bit. This delay is absolutely necessary, because
177 + DIO_Serial_IO_In_Progress_St goes high one bit too early. */
178 + nanodelay(devpriv->serial_interval_ns);
180 + if(data_in != NULL) {
181 + *data_in = win_in(DIO_Serial_Input_Register);
183 + printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in);
188 + win_out(devpriv->dio_control,DIO_Control_Register);
193 +static int ni_serial_sw_readwrite8(comedi_device *dev,comedi_subdevice *s,
194 + unsigned char data_out,
195 + unsigned char *data_in)
197 + unsigned char mask, input = 0;
200 + printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out);
203 + /* Wait for one bit before transfer */
204 + nanodelay(devpriv->serial_interval_ns);
206 + for(mask = 0x80; mask; mask >>= 1) {
207 + /* Output current bit; note that we cannot touch s->state
208 + because it is a per-subdevice field, and serial is
209 + a separate subdevice from DIO. */
210 + devpriv->dio_output &= ~DIO_SDOUT;
211 + if(data_out & mask) {
212 + devpriv->dio_output |= DIO_SDOUT;
214 + win_out(devpriv->dio_output,DIO_Output_Register);
216 + /* Assert SDCLK (active low, inverted), wait for half of
217 + the delay, deassert SDCLK, and wait for the other half. */
218 + devpriv->dio_control |= DIO_Software_Serial_Control;
219 + win_out(devpriv->dio_control,DIO_Control_Register);
221 + nanodelay(devpriv->serial_interval_ns / 2);
223 + devpriv->dio_control &= ~DIO_Software_Serial_Control;
224 + win_out(devpriv->dio_control,DIO_Control_Register);
226 + nanodelay(devpriv->serial_interval_ns / 2);
228 + /* Input current bit */
229 + if(ni_readw(DIO_Parallel_Input) & DIO_SDIN) {
234 + printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input);
236 + if(data_in) *data_in = input;
241 +static int ni_serial_insn_bits(comedi_device *dev,comedi_subdevice *s,
242 + comedi_insn *insn,lsampl_t *data)
245 + lsampl_t data_out, data_in, num_bits;
246 + unsigned char byteOut, byteIn;
249 + printk("ni_serial_insn_bits: num_bits=0x%x data_out=0x%x\n", data[0],
253 + if(insn->n!=2) return -EINVAL;
255 + num_bits = data[0];
257 + if((num_bits % 8) != 0) return -EINVAL;
259 + data_out = data[1];
261 + while(num_bits > 0) {
262 + /* Read from MSB to LSB */
265 + byteOut = (data_out >> (num_bits - 8)) & 0xff;
266 + if(devpriv->serial_hw_mode) {
267 + err = ni_serial_hw_readwrite8(dev,s,byteOut,&byteIn);
268 + } else if(devpriv->serial_interval_ns > 0) {
269 + err = ni_serial_sw_readwrite8(dev,s,byteOut,&byteIn);
271 + printk("ni_serial_insn_bits: serial disabled!\n");
274 + if(err < 0) return err;
277 + /* Write from MSB to LSB */
286 static int ni_8255_callback(int dir,int port,int data,unsigned long arg)
287 @@ -2608,7 +2829,7 @@
289 devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
290 devpriv->gpct_mode[chan] |= G_Stop_Mode(0);
294 devpriv->gpct_mode[chan] &= ~(G_Counting_Once(0x3));
295 devpriv->gpct_mode[chan] |= G_Counting_Once(2);
296 @@ -2788,7 +3009,7 @@
297 win_out( devpriv->gpct_mode[chan],G_Mode_Register(chan));
298 win_out( devpriv->gpct_input_select[chan],G_Input_Select_Register(chan));
299 win_out( 0,G_Autoincrement_Register(chan));
302 //printk("exit GPCT_Reset\n");
305 @@ -2878,7 +3099,7 @@
307 //printk("in ni_gpct_insn_read, n=%d, data[0]=%d\n",insn->chanspec,data[0]);
308 if(insn->n!=1)return -EINVAL;
311 data[0] = GPCT_G_Watch(dev,insn->chanspec);
313 /* for certain modes (period and pulse width measurment), the value
315 diff -ur comedi-0.7.63/include/linux/comedi.h comscxi-0.7.63/include/linux/comedi.h
316 --- comedi-0.7.63/include/linux/comedi.h Wed Oct 24 17:19:13 2001
317 +++ comscxi-0.7.63/include/linux/comedi.h Fri Feb 8 15:08:50 2002
319 #define COMEDI_SUBD_MEMORY 8 /* memory, EEPROM, DPRAM */
320 #define COMEDI_SUBD_CALIB 9 /* calibration DACs */
321 #define COMEDI_SUBD_PROC 10 /* processor, DSP */
323 +#define COMEDI_SUBD_SERIAL 11
325 #define COMEDI_INPUT 0
326 #define COMEDI_OUTPUT 1
327 diff -ur comedi-0.7.63/include/linux/comedidev.h comscxi-0.7.63/include/linux/comedidev.h
328 --- comedi-0.7.63/include/linux/comedidev.h Tue Jan 15 06:59:52 2002
329 +++ comscxi-0.7.63/include/linux/comedidev.h Fri Feb 8 15:10:46 2002
334 +static inline int nanodelay(unsigned long ns)
336 + /* We round up, so the result should always be longer than the
337 + * specified time. It's probably not much more precise than
338 + * using udelay(). Hopefully, one day Linux will have an
339 + * nanodelay() function. */
340 + //unsigned long loops_per_us = (loops_per_sec + 999999) / 1000000;
341 + //unsigned long loops = ((ns * loops_per_us) + 999) / 1000;
342 + /* printk("nanodelay: ns=%ld loops=%ld\n", ns, loops); */
343 + udelay((ns + 999) / 1000);
348 //#ifdef CONFIG_COMEDI_RT
349 #include <linux/comedi_rt.h>