update for HEAD-2003021201
[reactos.git] / drivers / net / npf / time_calls.c
1 /*
2  * Copyright (c) 2001
3  *      Politecnico di Torino.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the Politecnico
13  * di Torino, and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21
22 #include "tme.h"
23 #include "win_bpf.h"
24 #include "time_calls.h"
25
26
27 void TIME_DESYNCHRONIZE(struct time_conv *data)
28 {
29         data->reference = 0;
30         data->start.tv_sec = 0;
31         data->start.tv_usec = 0;
32 }
33
34 #ifdef KQPC_TS
35
36 /* KeQueryPerformanceCounter TimeStamps */
37
38 VOID TIME_SYNCHRONIZE(struct time_conv *data)
39 {
40         struct timeval tmp;
41         LARGE_INTEGER SystemTime;
42         LARGE_INTEGER i;
43         ULONG tmp2;
44         LARGE_INTEGER TimeFreq,PTime;
45
46         if (data->reference!=0)
47                 return;
48         
49         // get the absolute value of the system boot time.   
50         PTime=KeQueryPerformanceCounter(&TimeFreq);
51         KeQuerySystemTime(&SystemTime);
52 #ifndef __GNUC__
53         tmp.tv_sec=(LONG)(SystemTime.QuadPart/10000000-11644473600);
54         tmp.tv_usec=(LONG)((SystemTime.QuadPart%10000000)/10);
55         tmp.tv_sec-=(ULONG)(PTime.QuadPart/TimeFreq.QuadPart);
56         tmp.tv_usec-=(LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
57 #else
58     // TODO FIXME:
59 #endif
60         if (tmp.tv_usec<0) {
61                 tmp.tv_sec--;
62                 tmp.tv_usec+=1000000;
63         }
64         data->start=tmp;
65         data->reference=1;
66 }
67
68 void FORCE_TIME(struct timeval *src, struct time_conv *dest)
69 {
70         dest->start=*src;
71 }
72
73 void GET_TIME(struct timeval *dst, struct time_conv *data)
74 {
75         LARGE_INTEGER PTime, TimeFreq;
76         LONG tmp;
77
78         PTime=KeQueryPerformanceCounter(&TimeFreq);
79 #ifndef __GNUC__
80         tmp=(LONG)(PTime.QuadPart/TimeFreq.QuadPart);
81         dst->tv_sec=data->start.tv_sec+tmp;
82         dst->tv_usec=data->start.tv_usec+(LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
83 #else
84     // TODO FIXME:
85 #endif
86         if (dst->tv_usec>=1000000) {
87                 dst->tv_sec++;
88                 dst->tv_usec-=1000000;
89         }
90 }
91
92 #else /*KQPC_TS*/
93
94 /*RDTSC timestamps*/
95
96 /* callers must be at IRQL=PASSIVE_LEVEL */
97 VOID TIME_SYNCHRONIZE(struct time_conv *data)
98 {
99         struct timeval tmp;
100         LARGE_INTEGER system_time;
101         ULONGLONG curr_ticks;
102         KIRQL old;
103         LARGE_INTEGER start_kqpc,stop_kqpc,start_freq,stop_freq;
104         ULONGLONG start_ticks,stop_ticks;
105         ULONGLONG delta,delta2;
106         KEVENT event;
107         LARGE_INTEGER i;
108         ULONGLONG reference;
109
110         if (data->reference!=0)
111                 return;
112         
113         KeInitializeEvent(&event,NotificationEvent,FALSE);
114         i.QuadPart=-3500000;
115         KeRaiseIrql(HIGH_LEVEL,&old);
116         start_kqpc=KeQueryPerformanceCounter(&start_freq);
117 #ifndef __GNUC__
118         __asm
119         {
120                 push eax
121                 push edx
122                 push ecx
123                 rdtsc
124                 lea ecx, start_ticks
125                 mov [ecx+4], edx
126                 mov [ecx], eax
127                 pop ecx
128                 pop edx
129                 pop eax
130         }
131 #else
132         asm("push %%eax;"
133                 "push %%edx;"
134                 "push %%ecx;"
135                 "rdtsc;"
136                 "lea %0,%%ecx;"
137                 "mov %%edx,(%%ecx+4);"
138                 "mov %%eax,(%%ecx);"
139                 "pop %%ecx;"
140                 "pop %%edx;"
141                 "pop %%eax;"
142         :"=c"(start_ticks): );
143 #endif
144         KeLowerIrql(old);
145     KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i);
146         KeRaiseIrql(HIGH_LEVEL,&old);
147         stop_kqpc=KeQueryPerformanceCounter(&stop_freq);
148 #ifndef __GNUC__
149         __asm
150         {
151                 push eax
152                 push edx
153                 push ecx
154                 rdtsc
155                 lea ecx, stop_ticks
156                 mov [ecx+4], edx
157                 mov [ecx], eax
158                 pop ecx
159                 pop edx
160                 pop eax
161         }
162 #else
163         asm("push %%eax;"
164                 "push %%edx;"
165                 "push %%ecx;"
166                 "rdtsc;"
167                 "lea %0,%%ecx;"
168                 "mov %%edx,(%%ecx+4);"
169                 "mov %%eax,(%%ecx);"
170                 "pop %%ecx;"
171                 "pop %%edx;"
172                 "pop %%eax;"
173         :"=c"(stop_ticks): );
174 #endif
175         KeLowerIrql(old);
176         delta=stop_ticks-start_ticks;
177         delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart;
178         if (delta>10000000000) {
179                 delta/=16;
180                 delta2/=16;
181         }
182         reference=delta*(start_freq.QuadPart)/delta2;
183         data->reference=reference/1000;
184         if (reference%1000>500) 
185                 data->reference++;
186         data->reference*=1000;
187         reference=data->reference;
188         KeQuerySystemTime(&system_time);
189 #ifndef __GNUC__
190         __asm
191         {
192                 push eax
193                 push edx
194                 push ecx
195                 rdtsc
196                 lea ecx, curr_ticks
197                 mov [ecx+4], edx
198                 mov [ecx], eax
199                 pop ecx
200                 pop edx
201                 pop eax
202         }
203 #else
204         asm("push %%eax;"
205                 "push %%edx;"
206                 "push %%ecx;"
207                 "rdtsc;"
208                 "lea %0,%%ecx;"
209                 "mov %%edx,(%%ecx+4);"
210                 "mov %%eax,(%%ecx);"
211                 "pop %%ecx;"
212                 "pop %%edx;"
213                 "pop %%eax;"
214         :"=c"(curr_ticks): );
215 #endif
216         tmp.tv_sec=-(LONG)(curr_ticks/reference);
217         tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference);
218         system_time.QuadPart-=116444736000000000;
219         tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000);
220         tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10);
221         if (tmp.tv_usec<0) {
222                 tmp.tv_sec--;
223                 tmp.tv_usec+=1000000;
224         }
225         data->start=tmp;
226         IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);)
227 }
228
229 void FORCE_TIME(struct timeval *src, struct time_conv *dest)
230 {
231         dest->start=*src;
232 }
233
234 void GET_TIME(struct timeval *dst, struct time_conv *data)
235 {
236         ULONGLONG tmp;
237 #ifndef __GNUC__
238         __asm
239         {
240                 push eax
241                 push edx
242                 push ecx
243                 rdtsc
244                 lea ecx, tmp
245                 mov [ecx+4], edx
246                 mov [ecx], eax
247                 pop ecx
248                 pop edx
249                 pop eax
250         }
251 #else
252         asm("push %%eax;"
253                 "push %%edx;"
254                 "push %%ecx;"
255                 "rdtsc;"
256                 "lea %0,%%ecx;"
257                 "mov %%edx,(%%ecx+4);"
258                 "mov %%eax,(%%ecx);"
259                 "pop %%ecx;"
260                 "pop %%edx;"
261                 "pop %%eax;"
262         :"=c"(tmp): );
263 #endif
264         if (data->reference==0) {
265                 return;
266         }
267         dst->tv_sec=(LONG)(tmp/data->reference);
268         dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference);
269         dst->tv_sec+=data->start.tv_sec;
270         dst->tv_usec+=data->start.tv_usec;
271         if (dst->tv_usec>=1000000) {
272                 dst->tv_sec++;
273                 dst->tv_usec-=1000000;
274         }
275 }
276
277 #endif /*KQPC_TS*/