Rev 3 | Details | Compare with Previous | 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 | |||
645 | giacomo | 47 | extern int pci20to26_find_class(unsigned int class_code, int index, BYTE *bus, BYTE *dev); |
48 | extern int pci20to26_read_config_byte(unsigned int bus, unsigned int dev, int where, BYTE *val); |
||
49 | extern int pci20to26_read_config_word(unsigned int bus, unsigned int dev, int where, WORD *val); |
||
50 | extern int pci20to26_read_config_dword(unsigned int bus, unsigned int dev, int where, DWORD *val); |
||
51 | extern int pci20to26_write_config_byte(unsigned int bus, unsigned int dev, int where, BYTE val); |
||
52 | extern int pci20to26_write_config_word(unsigned int bus, unsigned int dev, int where, WORD val); |
||
53 | extern int pci20to26_write_config_dword(unsigned int bus, unsigned int dev, int where, DWORD val); |
||
54 | |||
2 | pj | 55 | //Software copy of importan register |
56 | static WORD interrupt_control; |
||
57 | |||
58 | // PJ: Global data |
||
59 | struct pci6025e_deviceinfo NIDevice_info[10]; |
||
60 | DWORD *IntLinestructptr; |
||
61 | DWORD *BAR0structptr; |
||
62 | DWORD *RevID; |
||
63 | DWORD STC_Base_Address, MITE_Base_Address; |
||
64 | |||
65 | //Software copy of STC general registers |
||
66 | WORD joint_reset, interrupt_a_enable, interrupt_a_ack, |
||
67 | interrupt_b_enable, interrupt_b_ack, clock_and_fout; |
||
68 | |||
69 | /***************************************************************************** |
||
70 | * Usefull(???) Functions * |
||
71 | *****************************************************************************/ |
||
72 | |||
73 | /***************************************************************************** |
||
74 | * Print value of each bit contained in value * |
||
75 | *****************************************************************************/ |
||
76 | void bitfield(BYTE dim, DWORD value) |
||
77 | { |
||
78 | int i; |
||
79 | |||
80 | for(i=(dim*8)-1; i>=0; i--) |
||
81 | cprintf("%ld",(value>>i)%2); |
||
82 | cprintf("\n"); |
||
83 | } |
||
84 | |||
85 | /***************************************************************************** |
||
86 | * Print custom string (str) before printing the bitfield * |
||
87 | *****************************************************************************/ |
||
88 | void TEST_bitfield(BYTE dim, DWORD value, char *str) |
||
89 | { |
||
90 | cprintf("%s", str); |
||
91 | bitfield(dim, value); |
||
92 | } |
||
93 | |||
94 | /***************************************************************************** |
||
95 | * Low Level Functions to write in windowed mode into DAQ STC * |
||
96 | *****************************************************************************/ |
||
97 | void DAQ_STC_Windowed_Mode_Write(WORD addr, WORD Value) |
||
98 | { |
||
645 | giacomo | 99 | SYS_FLAGS f; |
100 | |||
101 | f = kern_fsave(); |
||
2 | pj | 102 | *((WORD *)(STC_Base_Address + WIN_ADDR_REG)) = addr; |
103 | *((WORD *)(STC_Base_Address + WIN_DATA_WR_REG)) = Value; |
||
645 | giacomo | 104 | kern_frestore(f); |
2 | pj | 105 | } |
106 | |||
107 | WORD DAQ_STC_Windowed_Mode_Read(WORD addr) |
||
108 | { |
||
109 | WORD value = 0; |
||
645 | giacomo | 110 | SYS_FLAGS f; |
2 | pj | 111 | |
645 | giacomo | 112 | f = kern_fsave(); |
2 | pj | 113 | *((WORD *)(STC_Base_Address + WIN_ADDR_REG)) = addr; |
114 | value = *((WORD *)(STC_Base_Address + WIN_DATA_RD_REG)); |
||
645 | giacomo | 115 | kern_frestore(f); |
2 | pj | 116 | return (value); |
117 | } |
||
118 | |||
119 | /***************************************************************************** |
||
120 | * Detect all NI Devices on PCI bus * |
||
121 | *****************************************************************************/ |
||
122 | BYTE find_NI_Device(void) |
||
123 | { |
||
124 | WORD devNumFunNum = 0; |
||
125 | WORD busNum, i = 0; |
||
645 | giacomo | 126 | DWORD value, temp = 0, Device_ID; |
2 | pj | 127 | BYTE hdr, Device_Count; |
128 | int present; |
||
129 | |||
130 | Device_Count = 0; |
||
131 | BAR0structptr = &NIDevice_info[0].BAR0Value; |
||
132 | IntLinestructptr = &NIDevice_info[0].IntLineRegValue; |
||
133 | RevID = &NIDevice_info[0].RevisionID; |
||
134 | |||
135 | for(busNum = 0; busNum <= 0; busNum++){ |
||
136 | for(devNumFunNum = 0; devNumFunNum <= 0xFF; devNumFunNum += 0x08){ |
||
137 | present = 0; |
||
138 | if((devNumFunNum & 0x07) == 0){ |
||
645 | giacomo | 139 | present = pci20to26_read_config_byte((BYTE)busNum, |
2 | pj | 140 | (BYTE)devNumFunNum, 0x0E, &hdr); |
141 | if(hdr & 0x80) |
||
142 | present = 1; |
||
143 | if(present){ |
||
645 | giacomo | 144 | if(pci20to26_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, |
2 | pj | 145 | 0x00, &value) && (value != 0xffffffff)){ |
146 | if((value & 0xffffL) == NI_CODE){ |
||
147 | Device_ID = value; |
||
148 | Device_ID &= 0xFFFF0000; |
||
149 | Device_ID = Device_ID >> 16; |
||
150 | |||
151 | NIDevice_info[i].DEVID = (WORD)temp; |
||
152 | NIDevice_info[i].DevFunction = (BYTE)devNumFunNum; |
||
153 | NIDevice_info[i].BusNumber = (BYTE)busNum; |
||
645 | giacomo | 154 | pci20to26_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, 0x10, (DWORD *)BAR0structptr); |
155 | pci20to26_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, 0x3C, (DWORD *)IntLinestructptr); |
||
156 | pci20to26_read_config_dword((BYTE)busNum, (BYTE)devNumFunNum, 0x08, (DWORD *)RevID); |
||
2 | pj | 157 | NIDevice_info[i].InterruptLevel = (BYTE)NIDevice_info[i].IntLineRegValue; |
158 | i++; |
||
159 | BAR0structptr++; |
||
160 | IntLinestructptr++; |
||
161 | RevID++; |
||
162 | Device_Count++; |
||
163 | } |
||
164 | } |
||
165 | } |
||
166 | } |
||
167 | } |
||
168 | } |
||
169 | return Device_Count; |
||
170 | } |
||
171 | |||
172 | /***************************************************************************** |
||
173 | * Remap Base address of STC and MITE registers presents on NI boards * |
||
174 | * Note: If there's over than one NI Board on bus only the first device is * |
||
175 | * remapped * |
||
176 | *****************************************************************************/ |
||
177 | BYTE reMap(void) |
||
178 | { |
||
179 | //DWORD Mite_Data; |
||
180 | //DWORD Value; |
||
181 | |||
182 | if(!find_NI_Device()){ |
||
183 | return 0; |
||
184 | } |
||
185 | |||
186 | /* |
||
187 | // *************************************************************** |
||
188 | // This is usefull to remap board in another memory zone |
||
189 | // Enable this and choose memory zone setting BAR0 and BAR1 values |
||
190 | // on PCI6025E.H |
||
191 | // *************************************************************** |
||
192 | // Set Up MITE |
||
193 | Value = BAR0; |
||
194 | pcibios_write_config_dword((BYTE)NIDevice_info[0].BusNumber, |
||
195 | NIDevice_info[0].DevFunction, 0x10, Value); |
||
196 | Mite_Data = 0xAEAE; |
||
197 | lmempoked(BAR0 + 0x0340, Mite_Data); |
||
198 | |||
199 | // Set Up Board |
||
200 | Value = BAR1; |
||
201 | pcibios_write_config_dword((BYTE)NIDevice_info[0].BusNumber, |
||
202 | NIDevice_info[0].DevFunction, 0x14, Value); |
||
203 | Mite_Data = (BAR1 & 0xFFFFFF00) | 0x80; |
||
204 | lmempoked(BAR0 + 0xC0, Mite_Data); |
||
205 | */ |
||
206 | |||
207 | |||
208 | //Setting up Base Address |
||
645 | giacomo | 209 | pci20to26_read_config_dword((BYTE)NIDevice_info[0].BusNumber, |
2 | pj | 210 | (BYTE)NIDevice_info[0].DevFunction, 0x14, &STC_Base_Address); |
211 | STC_Base_Address = (STC_Base_Address & 0xFFFFFF00) | 0x80; |
||
645 | giacomo | 212 | pci20to26_read_config_dword((BYTE)NIDevice_info[0].BusNumber, |
2 | pj | 213 | (BYTE)NIDevice_info[0].DevFunction, 0x10, &MITE_Base_Address); |
214 | //MITE_Base_Address &= 0xFFFFFF00; |
||
215 | |||
216 | *((DWORD *)MITE_Base_Address) = 0xAEAE; |
||
217 | *((DWORD *)(MITE_Base_Address + 0xC0)) = STC_Base_Address; |
||
218 | |||
219 | return 1; |
||
220 | } |
||
221 | |||
222 | /***************************************************************************** |
||
223 | * Sets up the internal timebase clock and enable Frequency Out (FOUT). * |
||
224 | * Signal is available on pin 50 * |
||
225 | *----------------------------------------------------------------------------* |
||
226 | * tbs -> if 0 then 20 Mhz freq; if 1 then 200 Khz freq * |
||
227 | * divBy2 -> if 1 divides output frequency by two else if 0 doesn't * |
||
228 | * divide it * |
||
229 | * divider -> if 0 divides frequency by 16 * |
||
230 | * if between 1 and 15 divides frequency by specified value * |
||
231 | *****************************************************************************/ |
||
232 | BYTE setIntClock(BYTE tbs, BYTE divBy2, BYTE divider) |
||
233 | { |
||
234 | clr(clock_and_fout, 15); |
||
235 | DAQ_STC_Windowed_Mode_Write(CLOCK_AND_FOUT, clock_and_fout); |
||
236 | |||
237 | switch(tbs){ |
||
238 | case 0: |
||
239 | clr(clock_and_fout, 14); //IN_TIMEBASE |
||
240 | break; |
||
241 | case 1: |
||
242 | set(clock_and_fout, 11); //Enable IN_TIMEBASE2 |
||
243 | set(clock_and_fout, 14); //Select IN_TIMEBASE2 |
||
244 | break; |
||
245 | default: |
||
246 | return 0; |
||
247 | break; |
||
248 | } |
||
249 | |||
250 | switch(divBy2){ |
||
251 | case 0: clr(clock_and_fout, 12); break; //Not divided by two |
||
252 | case 1: set(clock_and_fout, 12); break; //Divided by two |
||
253 | default: return 0; break; |
||
254 | } |
||
255 | |||
256 | //if((divider < 0) || (divider > 15)) |
||
257 | if(divider > 15) // PJ: byte has only positive values!!! |
||
258 | return 0; //Addictional frequency division wrong |
||
259 | |||
260 | if(divider & 0x01) |
||
261 | set(clock_and_fout, 0); |
||
262 | else |
||
263 | clr(clock_and_fout, 0); |
||
264 | |||
265 | if(divider & 0x02) |
||
266 | set(clock_and_fout, 1); |
||
267 | else |
||
268 | clr(clock_and_fout, 1); |
||
269 | |||
270 | if(divider & 0x04) |
||
271 | set(clock_and_fout, 2); |
||
272 | else |
||
273 | clr(clock_and_fout, 2); |
||
274 | |||
275 | if(divider & 0x08) |
||
276 | set(clock_and_fout, 3); |
||
277 | else |
||
278 | clr(clock_and_fout, 3); |
||
279 | |||
280 | //Write in register |
||
281 | DAQ_STC_Windowed_Mode_Write(CLOCK_AND_FOUT, clock_and_fout); |
||
282 | |||
283 | //Enable internal clock |
||
284 | set(clock_and_fout, 15); |
||
285 | DAQ_STC_Windowed_Mode_Write(CLOCK_AND_FOUT, clock_and_fout); |
||
286 | |||
287 | return 1; |
||
288 | } |
||
289 | |||
290 | /***************************************************************************** |
||
291 | * void PFIprogramming(WORD pfi) * |
||
292 | *----------------------------------------------------------------------------* |
||
293 | * Use this function to program the direction of the ten available PFI lines * |
||
294 | * Parameter: pfi bit 0 through 9: 0 releted PFI line configured as input * |
||
295 | * 1 releted PFI line configured as output* |
||
296 | * 10..15 NOT USED * |
||
297 | *****************************************************************************/ |
||
298 | void PFIprogramming(WORD pfi) |
||
299 | { |
||
300 | DAQ_STC_Windowed_Mode_Write(IO_BIDIRECTION_PIN, (pfi & 0x03FF)); |
||
301 | } |
||
302 | |||
303 | /***************************************************************************** |
||
304 | * Interrupt manage module * |
||
305 | *****************************************************************************/ |
||
306 | /***************************************************************************** |
||
307 | * void INT_personalize(BYTE personal) * |
||
308 | *----------------------------------------------------------------------------* |
||
309 | * Use this function to select the logic level will indicate an interrupt * |
||
310 | * condition on IRQ_OUT pins and to enable or disable the possibility of * |
||
311 | * duplicate selected interrupt to IRQ_OUT<0..1> pins * |
||
312 | * Parameter: personal: bit 0: enable(1) or disable(0) signal duplication * |
||
313 | * bit 1: polarity: (0)active high (1)active low * |
||
314 | * bit 2..7 NOT USED * |
||
315 | *****************************************************************************/ |
||
316 | void INT_personalize(BYTE personal) |
||
317 | { |
||
318 | if( (personal & 0x02) ) set(interrupt_control, 0); |
||
319 | else clr(interrupt_control, 0); |
||
320 | |||
321 | if( (personal & 0x01) ) set(interrupt_control, 1); |
||
322 | else clr(interrupt_control, 1); |
||
323 | |||
324 | DAQ_STC_Windowed_Mode_Write(INTERRUPT_CONTROL, interrupt_control); |
||
325 | } |
||
326 | |||
327 | /***************************************************************************** |
||
328 | * void INT_setup(BYTE ga, BYTE gb) * |
||
329 | *----------------------------------------------------------------------------* |
||
330 | * Use this function to enable interrupt groups and to indicate which pin * |
||
331 | * indicate interrupt condition. * |
||
332 | * Parameter: ga: group A manages AITM, IRQ_IN0, Counter0 * |
||
333 | * gb: group B manages AOTM, IRQ_IN1, Counter1 * |
||
334 | * Both parameters have first 3 bits (0..2) to indicate IRQ_OUT pin that will * |
||
335 | * indicate interrupt condition and the fourth bit (3) to enable the * |
||
336 | * interrupts group. * |
||
337 | * Upper 4 bits of each BYTE are NOT USED * |
||
338 | *****************************************************************************/ |
||
339 | void INT_setup(BYTE ga, BYTE gb) |
||
340 | { |
||
341 | if( (ga & 0x08) ) |
||
342 | interrupt_control = (interrupt_control & 0xF0FF) | |
||
343 | ((ga & 0x0F) << 8); |
||
344 | else |
||
345 | clr(interrupt_control, 11); |
||
346 | |||
347 | if( (gb & 0x08) ) |
||
348 | interrupt_control = (interrupt_control & 0x0FFF) | |
||
349 | ((gb & 0x0F) << 12); |
||
350 | else |
||
351 | clr(interrupt_control, 15); |
||
352 | |||
353 | DAQ_STC_Windowed_Mode_Write(INTERRUPT_CONTROL, interrupt_control); |
||
354 | } |
||
355 | /*End of file: pci6025e.c*/ |