:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / 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*/