branch update for HEAD-2003021201
[reactos.git] / 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*/