amplc_dio200: Enable enhanced features of PCIe boards.
[comedi.git] / patches / patch-scxi-0.7.63
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
4 @@ -180,6 +180,10 @@
5  };
6  
7  
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);
12  
13  static int ni_dio_insn_config(comedi_device *dev,comedi_subdevice *s,
14         comedi_insn *insn,lsampl_t *data);
15 @@ -257,6 +261,12 @@
16  #define AIMODE_SCAN            2
17  #define AIMODE_SAMPLE          3
18  
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
24 +
25  static void handle_a_interrupt(comedi_device *dev,unsigned short status);
26  static void handle_b_interrupt(comedi_device *dev,unsigned short status);
27  #ifdef PCIDMA
28 @@ -1978,9 +1988,9 @@
29  static int ni_E_init(comedi_device *dev,comedi_devconfig *it)
30  {
31         comedi_subdevice *s;
32 -       
33 -       dev->n_subdevices=7;
34 -       
35 +
36 +       dev->n_subdevices=8;
37 +
38         if(alloc_subdevices(dev)<0)
39                 return -ENOMEM;
40         
41 @@ -2026,7 +2036,7 @@
42         }else{
43                 s->type=COMEDI_SUBD_UNUSED;
44         }
45 -       
46 +
47         /* digital i/o subdevice */
48         
49         s=dev->subdevices+2;
50 @@ -2079,14 +2089,28 @@
51         s->n_chan=512;
52         s->maxdata=0xff;
53         s->insn_read=ni_eeprom_insn_read;
54 -       
55 +
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;
60 +       s->n_chan=1;
61 +       s->maxdata=0xff;
62 +       s->insn_bits=ni_serial_insn_bits;
63 +       s->insn_config=ni_serial_insn_config;
64 +
65 +       /* serial configuration */
66 +       devpriv->serial_interval_ns = 0;
67 +       devpriv->serial_hw_mode = 0;
68 +
69 +
70         /* ai configuration */
71         ni_ai_reset(dev,dev->subdevices+0);
72 -       win_out(0x1ba0,Clock_and_FOUT_Register);
73 -
74 +       devpriv->clock_and_fout = 0x1ba0;
75 +       win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
76  
77         /* analog output configuration */
78 -       
79 +
80         devpriv->ao0p=0x0000;
81         ni_writew(devpriv->ao0p,AO_Configuration);
82         devpriv->ao1p=AO_Channel(1);
83 @@ -2125,6 +2149,203 @@
84         return 0;
85  }
86  
87 +static int ni_serial_insn_config(comedi_device *dev,comedi_subdevice *s,
88 +                                comedi_insn *insn,lsampl_t *data)
89 +{
90 +#ifdef DEBUG_DIO
91 +       printk("SPI serial I/O Config %d\n", data[0]);
92 +#endif
93 +
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;
98 +       switch(data[0]) {
99 +       default:
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);
105 +               break;
106 +       case SERIAL_600NS:
107 +               /* Warning: this clock speed is too fast to reliably
108 +                  control SCXI. */
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;
112 +               break;
113 +       case SERIAL_1_2US:
114 +               devpriv->dio_control &= ~DIO_HW_Serial_Timebase;
115 +               devpriv->clock_and_fout |= Slow_Internal_Timebase |
116 +                       DIO_Serial_Out_Divide_By_2;
117 +               break;
118 +       case SERIAL_10US:
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. */
126 +               break;
127 +       }
128 +       win_out(devpriv->dio_control,DIO_Control_Register);
129 +       win_out(devpriv->clock_and_fout,Clock_and_FOUT_Register);
130 +       return 1;
131 +}
132 +
133 +static int ni_serial_hw_readwrite8(comedi_device *dev,comedi_subdevice *s,
134 +                                  unsigned char data_out,
135 +                                  unsigned char *data_in)
136 +{
137 +       unsigned int status1;
138 +       int err = 0, count = 20;
139 +
140 +#ifdef DEBUG_DIO
141 +       printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out);
142 +#endif
143 +
144 +       if(devpriv->serial_interval_ns == 0) {
145 +               err = -EINVAL;
146 +               goto Error;
147 +       }
148 +
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);
152 +
153 +       status1 = win_in(Joint_Status_1_Register);
154 +       if(status1 & DIO_Serial_IO_In_Progress_St) {
155 +               err = -EBUSY;
156 +               goto Error;
157 +       }
158 +
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;
162 +
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);
169 +               if(--count < 0) {
170 +                       printk("ni_serial_hw_readwrite8: SPI serial I/O didn't finish in time!\n");
171 +                       err = -ETIME;
172 +                       goto Error;
173 +               }
174 +       }
175 +
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);
179 +
180 +       if(data_in != NULL) {
181 +               *data_in = win_in(DIO_Serial_Input_Register);
182 +#ifdef DEBUG_DIO
183 +               printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in);
184 +#endif
185 +       }
186 +
187 + Error:
188 +       win_out(devpriv->dio_control,DIO_Control_Register);
189 +
190 +       return err;
191 +}
192 +
193 +static int ni_serial_sw_readwrite8(comedi_device *dev,comedi_subdevice *s,
194 +                                  unsigned char data_out,
195 +                                  unsigned char *data_in)
196 +{
197 +       unsigned char mask, input = 0;
198 +
199 +#ifdef DEBUG_DIO
200 +       printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out);
201 +#endif
202 +
203 +       /* Wait for one bit before transfer */
204 +       nanodelay(devpriv->serial_interval_ns);
205 +
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;
213 +               }
214 +               win_out(devpriv->dio_output,DIO_Output_Register);
215 +
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);
220 +
221 +               nanodelay(devpriv->serial_interval_ns / 2);
222 +
223 +               devpriv->dio_control &= ~DIO_Software_Serial_Control;
224 +               win_out(devpriv->dio_control,DIO_Control_Register);
225 +
226 +               nanodelay(devpriv->serial_interval_ns / 2);
227 +
228 +               /* Input current bit */
229 +               if(ni_readw(DIO_Parallel_Input) & DIO_SDIN) {
230 +                       input |= mask;
231 +               }
232 +       }
233 +#ifdef DEBUG_DIO
234 +       printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input);
235 +#endif
236 +       if(data_in) *data_in = input;
237 +
238 +       return 0;
239 +}
240 +
241 +static int ni_serial_insn_bits(comedi_device *dev,comedi_subdevice *s,
242 +                              comedi_insn *insn,lsampl_t *data)
243 +{
244 +       int err = insn->n;
245 +       lsampl_t data_out, data_in, num_bits;
246 +       unsigned char byteOut, byteIn;
247 +
248 +#ifdef DEBUG_DIO
249 +       printk("ni_serial_insn_bits: num_bits=0x%x data_out=0x%x\n", data[0],
250 +              data[1]);
251 +#endif
252 +
253 +       if(insn->n!=2) return -EINVAL;
254 +
255 +       num_bits = data[0];
256 +
257 +       if((num_bits % 8) != 0) return -EINVAL;
258 +
259 +       data_out = data[1];
260 +       data_in = 0;
261 +       while(num_bits > 0) {
262 +               /* Read from MSB to LSB */
263 +               data_in <<= 8;
264 +
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);
270 +               } else {
271 +                       printk("ni_serial_insn_bits: serial disabled!\n");
272 +                       return -EINVAL;
273 +               }
274 +               if(err < 0) return err;
275 +               data_in |= byteIn;
276 +
277 +               /* Write from MSB to LSB */
278 +               num_bits -= 8;
279 +       }
280 +       data[1] = data_in;
281 +       return insn->n;
282 +}
283 +
284  
285  
286  static int ni_8255_callback(int dir,int port,int data,unsigned long arg)
287 @@ -2608,7 +2829,7 @@
288         // Stop_Mode = 0
289         devpriv->gpct_mode[chan] &= ~(G_Stop_Mode(0x3));
290         devpriv->gpct_mode[chan] |= G_Stop_Mode(0);
291 -       
292 +
293         // Counting_Once = 2 
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)); 
300 -               
301 +
302         //printk("exit GPCT_Reset\n");
303  }
304  
305 @@ -2878,7 +3099,7 @@
306                 
307         //printk("in ni_gpct_insn_read, n=%d, data[0]=%d\n",insn->chanspec,data[0]);
308         if(insn->n!=1)return -EINVAL;
309 -               
310 +
311         data[0] = GPCT_G_Watch(dev,insn->chanspec);
312                 
313         /* for certain modes (period and pulse width measurment), the value
314
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
318 @@ -192,7 +192,7 @@
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 */
322 -
323 +#define COMEDI_SUBD_SERIAL             11
324  
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
330 @@ -340,6 +340,19 @@
331         return 0;
332  }
333  
334 +static inline int nanodelay(unsigned long ns)
335 +{
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);
344 +       //__delay(loops);
345 +}
346 +
347  
348  //#ifdef CONFIG_COMEDI_RT
349  #include <linux/comedi_rt.h>