Revisted the packet capture driver and updated with fixes in latest 3.0a4 release.
[reactos.git] / reactos / drivers / net / packet / time_calls.h
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 #ifndef _time_calls
23 #define _time_calls
24
25 #ifdef WIN_NT_DRIVER
26
27 #include "debug.h"
28
29 /*!
30 \brief A microsecond precise timestamp.
31
32 included in the sf_pkthdr or the bpf_hdr that NPF associates with every packet.
33 */
34
35 struct timeval {
36 long tv_sec; ///< seconds
37 long tv_usec; ///< microseconds
38 };
39
40 #endif /*WIN_NT_DRIVER*/
41
42 struct time_conv {
43 ULONGLONG reference;
44 struct timeval start;
45 };
46
47 #ifdef __GNUC__
48
49 void TIME_DESYNCHRONIZE(struct time_conv *data);
50 VOID TIME_SYNCHRONIZE(struct time_conv *data);
51 void FORCE_TIME(struct timeval *src, struct time_conv *dest);
52 void GET_TIME(struct timeval *dst, struct time_conv *data);
53
54 #else /* __GNUC__ */
55
56 #ifdef WIN_NT_DRIVER
57
58 __inline void TIME_DESYNCHRONIZE(struct time_conv *data)
59 {
60 data->reference = 0;
61 data->start.tv_sec = 0;
62 data->start.tv_usec = 0;
63 }
64
65 #ifdef KQPC_TS
66
67 /* KeQueryPerformanceCounter TimeStamps */
68
69 __inline VOID TIME_SYNCHRONIZE(struct time_conv *data)
70 {
71 struct timeval tmp;
72 LARGE_INTEGER SystemTime;
73 LARGE_INTEGER i;
74 ULONG tmp2;
75 LARGE_INTEGER TimeFreq,PTime;
76
77 if (data->reference!=0)
78 return;
79
80 // get the absolute value of the system boot time.
81 PTime=KeQueryPerformanceCounter(&TimeFreq);
82 KeQuerySystemTime(&SystemTime);
83 tmp.tv_sec=(LONG)(SystemTime.QuadPart/10000000-11644473600);
84 tmp.tv_usec=(LONG)((SystemTime.QuadPart%10000000)/10);
85 tmp.tv_sec-=(ULONG)(PTime.QuadPart/TimeFreq.QuadPart);
86 tmp.tv_usec-=(LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
87 if (tmp.tv_usec<0) {
88 tmp.tv_sec--;
89 tmp.tv_usec+=1000000;
90 }
91 data->start=tmp;
92 data->reference=1;
93 }
94
95 __inline void GET_TIME(struct timeval *dst, struct time_conv *data)
96 {
97 LARGE_INTEGER PTime, TimeFreq;
98 LONG tmp;
99
100 PTime=KeQueryPerformanceCounter(&TimeFreq);
101 tmp=(LONG)(PTime.QuadPart/TimeFreq.QuadPart);
102 dst->tv_sec=data->start.tv_sec+tmp;
103 dst->tv_usec=data->start.tv_usec+(LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
104 if (dst->tv_usec>=1000000) {
105 dst->tv_sec++;
106 dst->tv_usec-=1000000;
107 }
108 }
109
110 __inline void FORCE_TIME(struct timeval *src, struct time_conv *dest)
111 {
112 dest->start=*src;
113 }
114
115 #else
116
117 /*RDTSC timestamps*/
118
119 /* callers must be at IRQL=PASSIVE_LEVEL */
120 __inline VOID TIME_SYNCHRONIZE(struct time_conv *data)
121 {
122 struct timeval tmp;
123 LARGE_INTEGER system_time;
124 ULONGLONG curr_ticks;
125 KIRQL old;
126 LARGE_INTEGER start_kqpc,stop_kqpc,start_freq,stop_freq;
127 ULONGLONG start_ticks,stop_ticks;
128 ULONGLONG delta,delta2;
129 KEVENT event;
130 LARGE_INTEGER i;
131 ULONGLONG reference;
132
133 if (data->reference!=0)
134 return;
135
136 KeInitializeEvent(&event,NotificationEvent,FALSE);
137 i.QuadPart=-3500000;
138 KeRaiseIrql(HIGH_LEVEL,&old);
139 start_kqpc=KeQueryPerformanceCounter(&start_freq);
140 #ifndef __GNUC__
141 __asm
142 {
143 push eax
144 push edx
145 push ecx
146 rdtsc
147 lea ecx, start_ticks
148 mov [ecx+4], edx
149 mov [ecx], eax
150 pop ecx
151 pop edx
152 pop eax
153 }
154 #else
155 #endif
156 KeLowerIrql(old);
157 KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i);
158 KeRaiseIrql(HIGH_LEVEL,&old);
159 stop_kqpc=KeQueryPerformanceCounter(&stop_freq);
160 #ifndef __GNUC__
161 __asm
162 {
163 push eax
164 push edx
165 push ecx
166 rdtsc
167 lea ecx, stop_ticks
168 mov [ecx+4], edx
169 mov [ecx], eax
170 pop ecx
171 pop edx
172 pop eax
173 }
174 #else
175 #endif
176 KeLowerIrql(old);
177 delta=stop_ticks-start_ticks;
178 delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart;
179 if (delta>10000000000) {
180 delta/=16;
181 delta2/=16;
182 }
183 reference=delta*(start_freq.QuadPart)/delta2;
184 data->reference=reference/1000;
185 if (reference%1000>500)
186 data->reference++;
187 data->reference*=1000;
188 reference=data->reference;
189 KeQuerySystemTime(&system_time);
190 #ifndef __GNUC__
191 __asm
192 {
193 push eax
194 push edx
195 push ecx
196 rdtsc
197 lea ecx, curr_ticks
198 mov [ecx+4], edx
199 mov [ecx], eax
200 pop ecx
201 pop edx
202 pop eax
203 }
204 #else
205 #endif
206 tmp.tv_sec=-(LONG)(curr_ticks/reference);
207 tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference);
208 system_time.QuadPart-=116444736000000000;
209 tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000);
210 tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10);
211 if (tmp.tv_usec<0) {
212 tmp.tv_sec--;
213 tmp.tv_usec+=1000000;
214 }
215 data->start=tmp;
216 IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);)
217 }
218
219 __inline void FORCE_TIME(struct timeval *src, struct time_conv *dest)
220 {
221 dest->start=*src;
222 }
223
224 __inline void GET_TIME(struct timeval *dst, struct time_conv *data)
225 {
226 ULONGLONG tmp;
227 #ifndef __GNUC__
228 __asm
229 {
230 push eax
231 push edx
232 push ecx
233 rdtsc
234 lea ecx, tmp
235 mov [ecx+4], edx
236 mov [ecx], eax
237 pop ecx
238 pop edx
239 pop eax
240 }
241 #else
242 #endif
243 if (data->reference==0) {
244 return;
245 }
246 dst->tv_sec=(LONG)(tmp/data->reference);
247 dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference);
248 dst->tv_sec+=data->start.tv_sec;
249 dst->tv_usec+=data->start.tv_usec;
250 if (dst->tv_usec>=1000000) {
251 dst->tv_sec++;
252 dst->tv_usec-=1000000;
253 }
254 }
255
256 #endif /*KQPC_TS*/
257
258 #endif /*WIN_NT_DRIVER*/
259
260 #endif /* __GNUC__ */
261
262 #endif /*_time_calls*/