5405de669dc565c1aeec9a4cfcdf43a640197119
[reactos.git] / reactos / drivers / bus / acpi / hardware / hwtimer.c
1
2 /******************************************************************************
3 *
4 * Name: hwtimer.c - ACPI Power Management Timer Interface
5 * $Revision: 1.1 $
6 *
7 *****************************************************************************/
8
9 /*
10 * Copyright (C) 2000, 2001 R. Byron Moore
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27 #include "acpi.h"
28 #include "achware.h"
29
30 #define _COMPONENT ACPI_HARDWARE
31 MODULE_NAME ("hwtimer")
32
33
34 /******************************************************************************
35 *
36 * FUNCTION: Acpi_get_timer_resolution
37 *
38 * PARAMETERS: none
39 *
40 * RETURN: Number of bits of resolution in the PM Timer (24 or 32).
41 *
42 * DESCRIPTION: Obtains resolution of the ACPI PM Timer.
43 *
44 ******************************************************************************/
45
46 ACPI_STATUS
47 acpi_get_timer_resolution (
48 u32 *resolution)
49 {
50 if (!resolution) {
51 return (AE_BAD_PARAMETER);
52 }
53
54 if (0 == acpi_gbl_FADT->tmr_val_ext) {
55 *resolution = 24;
56 }
57 else {
58 *resolution = 32;
59 }
60
61 return (AE_OK);
62 }
63
64
65 /******************************************************************************
66 *
67 * FUNCTION: Acpi_get_timer
68 *
69 * PARAMETERS: none
70 *
71 * RETURN: Current value of the ACPI PM Timer (in ticks).
72 *
73 * DESCRIPTION: Obtains current value of ACPI PM Timer.
74 *
75 ******************************************************************************/
76
77 ACPI_STATUS
78 acpi_get_timer (
79 u32 *ticks)
80 {
81 if (!ticks) {
82 return (AE_BAD_PARAMETER);
83 }
84
85 *ticks = acpi_os_in32 ((ACPI_IO_ADDRESS) ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address));
86
87 return (AE_OK);
88 }
89
90
91 /******************************************************************************
92 *
93 * FUNCTION: Acpi_get_timer_duration
94 *
95 * PARAMETERS: Start_ticks
96 * End_ticks
97 * Time_elapsed
98 *
99 * RETURN: Time_elapsed
100 *
101 * DESCRIPTION: Computes the time elapsed (in microseconds) between two
102 * PM Timer time stamps, taking into account the possibility of
103 * rollovers, the timer resolution, and timer frequency.
104 *
105 * The PM Timer's clock ticks at roughly 3.6 times per
106 * _microsecond_, and its clock continues through Cx state
107 * transitions (unlike many CPU timestamp counters) -- making it
108 * a versatile and accurate timer.
109 *
110 * Note that this function accomodates only a single timer
111 * rollover. Thus for 24-bit timers, this function should only
112 * be used for calculating durations less than ~4.6 seconds
113 * (~20 hours for 32-bit timers).
114 *
115 ******************************************************************************/
116
117 ACPI_STATUS
118 acpi_get_timer_duration (
119 u32 start_ticks,
120 u32 end_ticks,
121 u32 *time_elapsed)
122 {
123 u32 delta_ticks = 0;
124 u32 seconds = 0;
125 u32 milliseconds = 0;
126 u32 microseconds = 0;
127 u32 remainder = 0;
128
129 if (!time_elapsed) {
130 return (AE_BAD_PARAMETER);
131 }
132
133 /*
134 * Compute Tick Delta:
135 * -------------------
136 * Handle (max one) timer rollovers on 24- versus 32-bit timers.
137 */
138 if (start_ticks < end_ticks) {
139 delta_ticks = end_ticks - start_ticks;
140 }
141 else if (start_ticks > end_ticks) {
142 /* 24-bit Timer */
143 if (0 == acpi_gbl_FADT->tmr_val_ext) {
144 delta_ticks = (((0x00FFFFFF - start_ticks) + end_ticks) & 0x00FFFFFF);
145 }
146 /* 32-bit Timer */
147 else {
148 delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks;
149 }
150 }
151 else {
152 *time_elapsed = 0;
153 return (AE_OK);
154 }
155
156 /*
157 * Compute Duration:
158 * -----------------
159 * Since certain compilers (gcc/Linux, argh!) don't support 64-bit
160 * divides in kernel-space we have to do some trickery to preserve
161 * accuracy while using 32-bit math.
162 *
163 * TODO: Change to use 64-bit math when supported.
164 *
165 * The process is as follows:
166 * 1. Compute the number of seconds by dividing Delta Ticks by
167 * the timer frequency.
168 * 2. Compute the number of milliseconds in the remainder from step #1
169 * by multiplying by 1000 and then dividing by the timer frequency.
170 * 3. Compute the number of microseconds in the remainder from step #2
171 * by multiplying by 1000 and then dividing by the timer frequency.
172 * 4. Add the results from steps 1, 2, and 3 to get the total duration.
173 *
174 * Example: The time elapsed for Delta_ticks = 0xFFFFFFFF should be
175 * 1199864031 microseconds. This is computed as follows:
176 * Step #1: Seconds = 1199; Remainder = 3092840
177 * Step #2: Milliseconds = 864; Remainder = 113120
178 * Step #3: Microseconds = 31; Remainder = <don't care!>
179 */
180
181 /* Step #1 */
182 seconds = delta_ticks / PM_TIMER_FREQUENCY;
183 remainder = delta_ticks % PM_TIMER_FREQUENCY;
184
185 /* Step #2 */
186 milliseconds = (remainder * 1000) / PM_TIMER_FREQUENCY;
187 remainder = (remainder * 1000) % PM_TIMER_FREQUENCY;
188
189 /* Step #3 */
190 microseconds = (remainder * 1000) / PM_TIMER_FREQUENCY;
191
192 /* Step #4 */
193 *time_elapsed = seconds * 1000000;
194 *time_elapsed += milliseconds * 1000;
195 *time_elapsed += microseconds;
196
197 return (AE_OK);
198 }
199
200