Updated with latest version changes to original source.
[reactos.git] / reactos / drivers / net / packet / 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 #ifndef __GNUC__
30 data->reference = 0;
31 data->start.tv_sec = 0;
32 data->start.tv_usec = 0;
33 #endif
34 }
35
36 #ifdef KQPC_TS
37
38 /* KeQueryPerformanceCounter TimeStamps */
39
40 VOID TIME_SYNCHRONIZE(struct time_conv *data)
41 {
42 #ifndef __GNUC__
43 struct timeval tmp;
44 LARGE_INTEGER SystemTime;
45 LARGE_INTEGER i;
46 ULONG tmp2;
47 LARGE_INTEGER TimeFreq,PTime;
48
49 if (data->reference!=0)
50 return;
51
52 // get the absolute value of the system boot time.
53 PTime=KeQueryPerformanceCounter(&TimeFreq);
54 KeQuerySystemTime(&SystemTime);
55 tmp.tv_sec=(LONG)(SystemTime.QuadPart/10000000-11644473600);
56 tmp.tv_usec=(LONG)((SystemTime.QuadPart%10000000)/10);
57 tmp.tv_sec-=(ULONG)(PTime.QuadPart/TimeFreq.QuadPart);
58 tmp.tv_usec-=(LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
59 if (tmp.tv_usec<0) {
60 tmp.tv_sec--;
61 tmp.tv_usec+=1000000;
62 }
63 data->start=tmp;
64 data->reference=1;
65 #endif
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 #ifndef __GNUC__
76 LARGE_INTEGER PTime, TimeFreq;
77 LONG tmp;
78
79 PTime=KeQueryPerformanceCounter(&TimeFreq);
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 if (dst->tv_usec>=1000000) {
84 dst->tv_sec++;
85 dst->tv_usec-=1000000;
86 }
87 #endif
88 }
89
90 #else
91
92 /*RDTSC timestamps*/
93
94 /* callers must be at IRQL=PASSIVE_LEVEL */
95 VOID TIME_SYNCHRONIZE(struct time_conv *data)
96 {
97 #ifndef __GNUC__
98 struct timeval tmp;
99 LARGE_INTEGER system_time;
100 ULONGLONG curr_ticks;
101 KIRQL old;
102 LARGE_INTEGER start_kqpc,stop_kqpc,start_freq,stop_freq;
103 ULONGLONG start_ticks,stop_ticks;
104 ULONGLONG delta,delta2;
105 KEVENT event;
106 LARGE_INTEGER i;
107 ULONGLONG reference;
108
109 if (data->reference!=0)
110 return;
111
112 KeInitializeEvent(&event,NotificationEvent,FALSE);
113 i.QuadPart=-3500000;
114 KeRaiseIrql(HIGH_LEVEL,&old);
115 start_kqpc=KeQueryPerformanceCounter(&start_freq);
116 #ifndef __GNUC__
117 __asm
118 {
119 push eax
120 push edx
121 push ecx
122 rdtsc
123 lea ecx, start_ticks
124 mov [ecx+4], edx
125 mov [ecx], eax
126 pop ecx
127 pop edx
128 pop eax
129 }
130 #else
131 #endif
132 KeLowerIrql(old);
133 KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i);
134 KeRaiseIrql(HIGH_LEVEL,&old);
135 stop_kqpc=KeQueryPerformanceCounter(&stop_freq);
136 #ifndef __GNUC__
137 __asm
138 {
139 push eax
140 push edx
141 push ecx
142 rdtsc
143 lea ecx, stop_ticks
144 mov [ecx+4], edx
145 mov [ecx], eax
146 pop ecx
147 pop edx
148 pop eax
149 }
150 #else
151 #endif
152 KeLowerIrql(old);
153 delta=stop_ticks-start_ticks;
154 delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart;
155 if (delta>10000000000) {
156 delta/=16;
157 delta2/=16;
158 }
159 reference=delta*(start_freq.QuadPart)/delta2;
160 data->reference=reference/1000;
161 if (reference%1000>500)
162 data->reference++;
163 data->reference*=1000;
164 reference=data->reference;
165 KeQuerySystemTime(&system_time);
166 #ifndef __GNUC__
167 __asm
168 {
169 push eax
170 push edx
171 push ecx
172 rdtsc
173 lea ecx, curr_ticks
174 mov [ecx+4], edx
175 mov [ecx], eax
176 pop ecx
177 pop edx
178 pop eax
179 }
180 #else
181 #endif
182 tmp.tv_sec=-(LONG)(curr_ticks/reference);
183 tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference);
184 system_time.QuadPart-=116444736000000000;
185 tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000);
186 tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10);
187 if (tmp.tv_usec<0) {
188 tmp.tv_sec--;
189 tmp.tv_usec+=1000000;
190 }
191 data->start=tmp;
192 IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);)
193 #else
194 #endif
195 }
196
197 void FORCE_TIME(struct timeval *src, struct time_conv *dest)
198 {
199 dest->start=*src;
200 }
201
202 void GET_TIME(struct timeval *dst, struct time_conv *data)
203 {
204 #ifndef __GNUC__
205 ULONGLONG tmp;
206 #ifndef __GNUC__
207 __asm
208 {
209 push eax
210 push edx
211 push ecx
212 rdtsc
213 lea ecx, tmp
214 mov [ecx+4], edx
215 mov [ecx], eax
216 pop ecx
217 pop edx
218 pop eax
219 }
220 #else
221 #endif
222 if (data->reference==0) {
223 return;
224 }
225 dst->tv_sec=(LONG)(tmp/data->reference);
226 dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference);
227 dst->tv_sec+=data->start.tv_sec;
228 dst->tv_usec+=data->start.tv_usec;
229 if (dst->tv_usec>=1000000) {
230 dst->tv_sec++;
231 dst->tv_usec-=1000000;
232 }
233 #endif
234 }
235
236 #endif /*KQPC_TS*/