Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | pj | 1 | /***************************************************************************** |
2 | * Filename: pci6025e.c * |
||
3 | * Author: Ziglioli Marco * |
||
4 | * Date: 15/03/2001 * |
||
5 | * Description: Collection of routines to find on PCI bus and configure Natio-* |
||
6 | * nal Instruments PCI6025E multifunction board. This board has * |
||
7 | * - One ADC 12 bit flash with 16 input lines (multiplexed) * |
||
8 | * - Two DACs 12 bit * |
||
9 | * - Eight Digital lines drived through NI DAQ-STC IC * |
||
10 | * - Twentyfour Digital lines drived through OKI MSM82C55A * |
||
11 | * - Two General purpose 24-bit counters/timers * |
||
12 | * - Timing module for analog input (AITM) * |
||
13 | * - Timing module for analog output (AOTM) * |
||
14 | * - 10 Programmable Function pins (PFI) * |
||
15 | * - RTSI bus for connection with other National Board * |
||
16 | * - Timing module which can provide frequency from 20MHz to * |
||
17 | * 6,25 KHz * |
||
18 | * - Two shared interrupt groups to manage up than 20 different * |
||
19 | * interrupt events * |
||
20 | * For more information please refer to National Web site: www.ni.com * |
||
21 | *----------------------------------------------------------------------------* |
||
22 | * Notes: Based on National C Routines * |
||
23 | *****************************************************************************/ |
||
24 | |||
25 | /* This file is part of the S.Ha.R.K. Project - http://shark.sssup.it |
||
26 | * |
||
27 | * Copyright (C) 2001 Marco Ziglioli |
||
28 | * |
||
29 | * This program is free software; you can redistribute it and/or modify |
||
30 | * it under the terms of the GNU General Public License as published by |
||
31 | * the Free Software Foundation; either version 2 of the License, or |
||
32 | * (at your option) any later version. |
||
33 | * |
||
34 | * This program is distributed in the hope that it will be useful, |
||
35 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
36 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
37 | * GNU General Public License for more details. |
||
38 | * |
||
39 | * You should have received a copy of the GNU General Public License |
||
40 | * along with this program; if not, write to the Free Software |
||
41 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
42 | * |
||
43 | */ |
||
44 | |||
45 | #include <drivers/pci6025e/pci6025e.h> |
||
46 | |||
47 | //Software copy of importan register |
||
48 | static WORD interrupt_control; |
||
49 | |||
50 | // PJ: Global data |
||
51 | struct pci6025e_deviceinfo NIDevice_info[10]; |
||
52 | DWORD *IntLinestructptr; |
||
53 | DWORD *BAR0structptr; |
||
54 | DWORD *RevID; |
||
55 | DWORD STC_Base_Address, MITE_Base_Address; |
||
56 | |||
57 | //Software copy of STC general registers |
||
58 | WORD joint_reset, interrupt_a_enable, interrupt_a_ack, |
||
59 | interrupt_b_enable, interrupt_b_ack, clock_and_fout; |
||
60 | |||
61 | /***************************************************************************** |
||
62 | * Usefull(???) Functions * |
||
63 | *****************************************************************************/ |
||
64 | |||
65 | /***************************************************************************** |
||
66 | * Print value of each bit contained in value * |
||
67 | *****************************************************************************/ |
||
68 | void bitfield(BYTE dim, DWORD value) |
||
69 | { |
||
70 | int i; |
||
71 | |||
72 | for(i=(dim*8)-1; i>=0; i--) |
||
73 | cprintf("%ld",(value>>i)%2); |
||
74 | cprintf("\n"); |
||
75 | } |
||
76 | |||
77 | /***************************************************************************** |
||
78 | * Print custom string (str) before printing the bitfield * |
||
79 | *****************************************************************************/ |
||
80 | void TEST_bitfield(BYTE dim, DWORD value, char *str) |
||
81 | { |
||
82 | cprintf("%s", str); |
||
83 | bitfield(dim, value); |
||
84 | } |
||
85 | |||
86 | /***************************************************************************** |
||
87 | * Low Level Functions to write in windowed mode into DAQ STC * |
||
88 | *****************************************************************************/ |
||
89 | void DAQ_STC_Windowed_Mode_Write(WORD addr, WORD Value) |
||
90 | { |
||
91 | kern_cli(); |
||
92 | *((WORD *)(STC_Base_Address + WIN_ADDR_REG)) = addr; |
||
93 | *((WORD *)(STC_Base_Address + WIN_DATA_WR_REG)) = Value; |
||
94 | kern_sti(); |
||
95 | } |
||
96 | |||
97 | WORD DAQ_STC_Windowed_Mode_Read(WORD addr) |
||
98 | { |
||
99 | WORD value = 0; |
||
100 | |||
101 | kern_cli(); |
||
102 | *((WORD *)(STC_Base_Address + WIN_ADDR_REG)) = addr; |
||
103 | value = *((WORD *)(STC_Base_Address + WIN_DATA_RD_REG)); |
||
104 | kern_sti(); |
||
105 | return (value); |
||
106 | } |
||
107 | |||
108 | /***************************************************************************** |
||
109 | * Detect all NI Devices on PCI bus * |
||
110 | *****************************************************************************/ |
||
111 | BYTE find_NI_Device(void) |
||
112 | { |
||
113 | WORD devNumFunNum = 0; |
||
114 | WORD busNum, i = 0; |
||
115 | DWORD value, temp, Device_ID; |
||
116 | BYTE hdr, Device_Count; |
||
117 | int present; |
||
118 | |||
119 | Device_Count = 0; |
||
120 | BAR0structptr = &NIDevice_info[0].BAR0Value; |
||
121 | IntLinestructptr = &NIDevice_info[0].IntLineRegValue; |
||
122 | RevID = &NIDevice_info[0].RevisionID; |
||
123 | |||
124 | for(busNum = 0; busNum <= 0; busNum++){ |
||
125 | for(devNumFunNum = 0; devNumFunNum <= 0xFF; devNumFunNum += 0x08){ |
||
126 | present = 0; |
||
127 | if((devNumFunNum & 0x07) == 0){ |
||
128 | present = pcibios_read_config_byte((BYTE)busNum, |
||
129 | (BYTE)devNumFunNum, 0x0E, &hdr); |
||
130 | if(hdr & 0x80) |
||
131 | present = 1; |
||
132 | if(present){ |
||
133 | if(pcibios_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, |
||
134 | 0x00, &value) && (value != 0xffffffff)){ |
||
135 | if((value & 0xffffL) == NI_CODE){ |
||
136 | Device_ID = value; |
||
137 | Device_ID &= 0xFFFF0000; |
||
138 | Device_ID = Device_ID >> 16; |
||
139 | |||
140 | NIDevice_info[i].DEVID = (WORD)temp; |
||
141 | NIDevice_info[i].DevFunction = (BYTE)devNumFunNum; |
||
142 | NIDevice_info[i].BusNumber = (BYTE)busNum; |
||
143 | pcibios_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, 0x10, (DWORD *)BAR0structptr); |
||
144 | pcibios_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, 0x3C, (DWORD *)IntLinestructptr); |
||
145 | pcibios_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, 0x08, (DWORD *)RevID); |
||
146 | NIDevice_info[i].InterruptLevel = (BYTE)NIDevice_info[i].IntLineRegValue; |
||
147 | i++; |
||
148 | BAR0structptr++; |
||
149 | IntLinestructptr++; |
||
150 | RevID++; |
||
151 | Device_Count++; |
||
152 | } |
||
153 | } |
||
154 | } |
||
155 | } |
||
156 | } |
||
157 | } |
||
158 | return Device_Count; |
||
159 | } |
||
160 | |||
161 | /***************************************************************************** |
||
162 | * Remap Base address of STC and MITE registers presents on NI boards * |
||
163 | * Note: If there's over than one NI Board on bus only the first device is * |
||
164 | * remapped * |
||
165 | *****************************************************************************/ |
||
166 | BYTE reMap(void) |
||
167 | { |
||
168 | //DWORD Mite_Data; |
||
169 | //DWORD Value; |
||
170 | |||
171 | if(!find_NI_Device()){ |
||
172 | return 0; |
||
173 | } |
||
174 | |||
175 | /* |
||
176 | // *************************************************************** |
||
177 | // This is usefull to remap board in another memory zone |
||
178 | // Enable this and choose memory zone setting BAR0 and BAR1 values |
||
179 | // on PCI6025E.H |
||
180 | // *************************************************************** |
||
181 | // Set Up MITE |
||
182 | Value = BAR0; |
||
183 | pcibios_write_config_dword((BYTE)NIDevice_info[0].BusNumber, |
||
184 | NIDevice_info[0].DevFunction, 0x10, Value); |
||
185 | Mite_Data = 0xAEAE; |
||
186 | lmempoked(BAR0 + 0x0340, Mite_Data); |
||
187 | |||
188 | // Set Up Board |
||
189 | Value = BAR1; |
||
190 | pcibios_write_config_dword((BYTE)NIDevice_info[0].BusNumber, |
||
191 | NIDevice_info[0].DevFunction, 0x14, Value); |
||
192 | Mite_Data = (BAR1 & 0xFFFFFF00) | 0x80; |
||
193 | lmempoked(BAR0 + 0xC0, Mite_Data); |
||
194 | */ |
||
195 | |||
196 | |||
197 | //Setting up Base Address |
||
198 | pcibios_read_config_dword((BYTE)NIDevice_info[0].BusNumber, |
||
199 | (BYTE)NIDevice_info[0].DevFunction, 0x14, &STC_Base_Address); |
||
200 | STC_Base_Address = (STC_Base_Address & 0xFFFFFF00) | 0x80; |
||
201 | pcibios_read_config_dword((BYTE)NIDevice_info[0].BusNumber, |
||
202 | (BYTE)NIDevice_info[0].DevFunction, 0x10, &MITE_Base_Address); |
||
203 | //MITE_Base_Address &= 0xFFFFFF00; |
||
204 | |||
205 | *((DWORD *)MITE_Base_Address) = 0xAEAE; |
||
206 | *((DWORD *)(MITE_Base_Address + 0xC0)) = STC_Base_Address; |
||
207 | |||
208 | return 1; |
||
209 | } |
||
210 | |||
211 | /***************************************************************************** |
||
212 | * Sets up the internal timebase clock and enable Frequency Out (FOUT). * |
||
213 | * Signal is available on pin 50 * |
||
214 | *----------------------------------------------------------------------------* |
||
215 | * tbs -> if 0 then 20 Mhz freq; if 1 then 200 Khz freq * |
||
216 | * divBy2 -> if 1 divides output frequency by two else if 0 doesn't * |
||
217 | * divide it * |
||
218 | * divider -> if 0 divides frequency by 16 * |
||
219 | * if between 1 and 15 divides frequency by specified value * |
||
220 | *****************************************************************************/ |
||
221 | BYTE setIntClock(BYTE tbs, BYTE divBy2, BYTE divider) |
||
222 | { |
||
223 | clr(clock_and_fout, 15); |
||
224 | DAQ_STC_Windowed_Mode_Write(CLOCK_AND_FOUT, clock_and_fout); |
||
225 | |||
226 | switch(tbs){ |
||
227 | case 0: |
||
228 | clr(clock_and_fout, 14); //IN_TIMEBASE |
||
229 | break; |
||
230 | case 1: |
||
231 | set(clock_and_fout, 11); //Enable IN_TIMEBASE2 |
||
232 | set(clock_and_fout, 14); //Select IN_TIMEBASE2 |
||
233 | break; |
||
234 | default: |
||
235 | return 0; |
||
236 | break; |
||
237 | } |
||
238 | |||
239 | switch(divBy2){ |
||
240 | case 0: clr(clock_and_fout, 12); break; //Not divided by two |
||
241 | case 1: set(clock_and_fout, 12); break; //Divided by two |
||
242 | default: return 0; break; |
||
243 | } |
||
244 | |||
245 | //if((divider < 0) || (divider > 15)) |
||
246 | if(divider > 15) // PJ: byte has only positive values!!! |
||
247 | return 0; //Addictional frequency division wrong |
||
248 | |||
249 | if(divider & 0x01) |
||
250 | set(clock_and_fout, 0); |
||
251 | else |
||
252 | clr(clock_and_fout, 0); |
||
253 | |||
254 | if(divider & 0x02) |
||
255 | set(clock_and_fout, 1); |
||
256 | else |
||
257 | clr(clock_and_fout, 1); |
||
258 | |||
259 | if(divider & 0x04) |
||
260 | set(clock_and_fout, 2); |
||
261 | else |
||
262 | clr(clock_and_fout, 2); |
||
263 | |||
264 | if(divider & 0x08) |
||
265 | set(clock_and_fout, 3); |
||
266 | else |
||
267 | clr(clock_and_fout, 3); |
||
268 | |||
269 | //Write in register |
||
270 | DAQ_STC_Windowed_Mode_Write(CLOCK_AND_FOUT, clock_and_fout); |
||
271 | |||
272 | //Enable internal clock |
||
273 | set(clock_and_fout, 15); |
||
274 | DAQ_STC_Windowed_Mode_Write(CLOCK_AND_FOUT, clock_and_fout); |
||
275 | |||
276 | return 1; |
||
277 | } |
||
278 | |||
279 | /***************************************************************************** |
||
280 | * void PFIprogramming(WORD pfi) * |
||
281 | *----------------------------------------------------------------------------* |
||
282 | * Use this function to program the direction of the ten available PFI lines * |
||
283 | * Parameter: pfi bit 0 through 9: 0 releted PFI line configured as input * |
||
284 | * 1 releted PFI line configured as output* |
||
285 | * 10..15 NOT USED * |
||
286 | *****************************************************************************/ |
||
287 | void PFIprogramming(WORD pfi) |
||
288 | { |
||
289 | DAQ_STC_Windowed_Mode_Write(IO_BIDIRECTION_PIN, (pfi & 0x03FF)); |
||
290 | } |
||
291 | |||
292 | /***************************************************************************** |
||
293 | * Interrupt manage module * |
||
294 | *****************************************************************************/ |
||
295 | /***************************************************************************** |
||
296 | * void INT_personalize(BYTE personal) * |
||
297 | *----------------------------------------------------------------------------* |
||
298 | * Use this function to select the logic level will indicate an interrupt * |
||
299 | * condition on IRQ_OUT pins and to enable or disable the possibility of * |
||
300 | * duplicate selected interrupt to IRQ_OUT<0..1> pins * |
||
301 | * Parameter: personal: bit 0: enable(1) or disable(0) signal duplication * |
||
302 | * bit 1: polarity: (0)active high (1)active low * |
||
303 | * bit 2..7 NOT USED * |
||
304 | *****************************************************************************/ |
||
305 | void INT_personalize(BYTE personal) |
||
306 | { |
||
307 | if( (personal & 0x02) ) set(interrupt_control, 0); |
||
308 | else clr(interrupt_control, 0); |
||
309 | |||
310 | if( (personal & 0x01) ) set(interrupt_control, 1); |
||
311 | else clr(interrupt_control, 1); |
||
312 | |||
313 | DAQ_STC_Windowed_Mode_Write(INTERRUPT_CONTROL, interrupt_control); |
||
314 | } |
||
315 | |||
316 | /***************************************************************************** |
||
317 | * void INT_setup(BYTE ga, BYTE gb) * |
||
318 | *----------------------------------------------------------------------------* |
||
319 | * Use this function to enable interrupt groups and to indicate which pin * |
||
320 | * indicate interrupt condition. * |
||
321 | * Parameter: ga: group A manages AITM, IRQ_IN0, Counter0 * |
||
322 | * gb: group B manages AOTM, IRQ_IN1, Counter1 * |
||
323 | * Both parameters have first 3 bits (0..2) to indicate IRQ_OUT pin that will * |
||
324 | * indicate interrupt condition and the fourth bit (3) to enable the * |
||
325 | * interrupts group. * |
||
326 | * Upper 4 bits of each BYTE are NOT USED * |
||
327 | *****************************************************************************/ |
||
328 | void INT_setup(BYTE ga, BYTE gb) |
||
329 | { |
||
330 | if( (ga & 0x08) ) |
||
331 | interrupt_control = (interrupt_control & 0xF0FF) | |
||
332 | ((ga & 0x0F) << 8); |
||
333 | else |
||
334 | clr(interrupt_control, 11); |
||
335 | |||
336 | if( (gb & 0x08) ) |
||
337 | interrupt_control = (interrupt_control & 0x0FFF) | |
||
338 | ((gb & 0x0F) << 12); |
||
339 | else |
||
340 | clr(interrupt_control, 15); |
||
341 | |||
342 | DAQ_STC_Windowed_Mode_Write(INTERRUPT_CONTROL, interrupt_control); |
||
343 | } |
||
344 | /*End of file: pci6025e.c*/ |