Sync tools to 45592
[reactos.git] / reactos / hal / halx86 / generic / cmos.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/cmos.c
5 * PURPOSE: CMOS Access Routines (Real Time Clock and LastKnownGood)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl
8 * Timo Kreuzer (timo.kreuzer@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <hal.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 UCHAR HalpCmosCenturyOffset;
20
21 /* PRIVATE FUNCTIONS *********************************************************/
22
23 FORCEINLINE
24 UCHAR
25 HalpReadCmos(IN UCHAR Reg)
26 {
27 /* Select the register */
28 WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg);
29
30 /* Query the value */
31 return READ_PORT_UCHAR(CMOS_DATA_PORT);
32 }
33
34 FORCEINLINE
35 VOID
36 HalpWriteCmos(IN UCHAR Reg,
37 IN UCHAR Value)
38 {
39 /* Select the register */
40 WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg);
41
42 /* Write the value */
43 WRITE_PORT_UCHAR(CMOS_DATA_PORT, Value);
44 }
45
46 ULONG
47 NTAPI
48 HalpGetCmosData(IN ULONG BusNumber,
49 IN ULONG SlotNumber,
50 IN PVOID Buffer,
51 IN ULONG Length)
52 {
53 PUCHAR Ptr = (PUCHAR)Buffer;
54 ULONG Address = SlotNumber;
55 ULONG Len = Length;
56
57 /* Do nothing if we don't have a length */
58 if (!Length) return 0;
59
60 /* Acquire CMOS Lock */
61 HalpAcquireSystemHardwareSpinLock();
62
63 /* Check if this is simple CMOS */
64 if (BusNumber == 0)
65 {
66 /* Loop the buffer up to 0xFF */
67 while ((Len > 0) && (Address < 0x100))
68 {
69 /* Read the data */
70 *Ptr = HalpReadCmos((UCHAR)Address);
71
72 /* Update position and length */
73 Ptr++;
74 Address++;
75 Len--;
76 }
77 }
78 else if (BusNumber == 1)
79 {
80 /* Loop the buffer up to 0xFFFF */
81 while ((Len > 0) && (Address < 0x10000))
82 {
83 /* Write the data */
84 *Ptr = HalpReadCmos((UCHAR)Address);
85
86 /* Update position and length */
87 Ptr++;
88 Address++;
89 Len--;
90 }
91 }
92
93 /* Release CMOS Lock */
94 HalpReleaseCmosSpinLock();
95
96 /* Return length read */
97 return Length - Len;
98 }
99
100 ULONG
101 NTAPI
102 HalpSetCmosData(IN ULONG BusNumber,
103 IN ULONG SlotNumber,
104 IN PVOID Buffer,
105 IN ULONG Length)
106 {
107 PUCHAR Ptr = (PUCHAR)Buffer;
108 ULONG Address = SlotNumber;
109 ULONG Len = Length;
110
111 /* Do nothing if we don't have a length */
112 if (!Length) return 0;
113
114 /* Acquire CMOS Lock */
115 HalpAcquireSystemHardwareSpinLock();
116
117 /* Check if this is simple CMOS */
118 if (BusNumber == 0)
119 {
120 /* Loop the buffer up to 0xFF */
121 while ((Len > 0) && (Address < 0x100))
122 {
123 /* Write the data */
124 HalpWriteCmos((UCHAR)Address, *Ptr);
125
126 /* Update position and length */
127 Ptr++;
128 Address++;
129 Len--;
130 }
131 }
132 else if (BusNumber == 1)
133 {
134 /* Loop the buffer up to 0xFFFF */
135 while ((Len > 0) && (Address < 0x10000))
136 {
137 /* Write the data */
138 HalpWriteCmos((UCHAR)Address, *Ptr);
139
140 /* Update position and length */
141 Ptr++;
142 Address++;
143 Len--;
144 }
145 }
146
147 /* Release CMOS Lock */
148 HalpReleaseCmosSpinLock();
149
150 /* Return length read */
151 return Length - Len;
152 }
153
154 VOID
155 NTAPI
156 HalpInitializeCmos(VOID)
157 {
158 /* Set default century offset byte */
159 HalpCmosCenturyOffset = 50;
160
161 /* No support for EISA or MCA */
162 ASSERT(HalpBusType == MACHINE_TYPE_ISA);
163 }
164
165 /* PUBLIC FUNCTIONS **********************************************************/
166
167 /*
168 * @implemented
169 */
170 ARC_STATUS
171 NTAPI
172 HalGetEnvironmentVariable(IN PCH Name,
173 IN USHORT ValueLength,
174 IN PCH Value)
175 {
176 UCHAR Val;
177
178 /* Only variable supported on x86 */
179 if (_stricmp(Name, "LastKnownGood")) return ENOENT;
180
181 /* Acquire CMOS Lock */
182 HalpAcquireSystemHardwareSpinLock();
183
184 /* Query the current value */
185 Val = HalpReadCmos(RTC_REGISTER_B) & 0x01;
186
187 /* Release CMOS lock */
188 HalpReleaseCmosSpinLock();
189
190 /* Check the flag */
191 if (Val)
192 {
193 /* Return false */
194 strncpy(Value, "FALSE", ValueLength);
195 }
196 else
197 {
198 /* Return true */
199 strncpy(Value, "TRUE", ValueLength);
200 }
201
202 /* Return success */
203 return ESUCCESS;
204 }
205
206 /*
207 * @implemented
208 */
209 ARC_STATUS
210 NTAPI
211 HalSetEnvironmentVariable(IN PCH Name,
212 IN PCH Value)
213 {
214 UCHAR Val;
215
216 /* Only variable supported on x86 */
217 if (_stricmp(Name, "LastKnownGood")) return ENOMEM;
218
219 /* Check if this is true or false */
220 if (!_stricmp(Value, "TRUE"))
221 {
222 /* It's true, acquire CMOS lock */
223 HalpAcquireSystemHardwareSpinLock();
224
225 /* Read the current value and add the flag */
226 Val = HalpReadCmos(RTC_REGISTER_B) | 1;
227 }
228 else if (!_stricmp(Value, "FALSE"))
229 {
230 /* It's false, acquire CMOS lock */
231 HalpAcquireSystemHardwareSpinLock();
232
233 /* Read the current value and mask out the flag */
234 Val = HalpReadCmos(RTC_REGISTER_B) & ~1;
235 }
236 else
237 {
238 /* Fail */
239 return ENOMEM;
240 }
241
242 /* Write new value */
243 HalpWriteCmos(RTC_REGISTER_B, Val);
244
245 /* Release the lock and return success */
246 HalpReleaseCmosSpinLock();
247 return ESUCCESS;
248 }
249
250 /*
251 * @implemented
252 */
253 BOOLEAN
254 NTAPI
255 HalQueryRealTimeClock(OUT PTIME_FIELDS Time)
256 {
257 /* Acquire CMOS Lock */
258 HalpAcquireSystemHardwareSpinLock();
259
260 /* Loop while update is in progress */
261 while ((HalpReadCmos(RTC_REGISTER_A)) & RTC_REG_A_UIP);
262
263 /* Set the time data */
264 Time->Second = BCD_INT(HalpReadCmos(0));
265 Time->Minute = BCD_INT(HalpReadCmos(2));
266 Time->Hour = BCD_INT(HalpReadCmos(4));
267 Time->Weekday = BCD_INT(HalpReadCmos(6));
268 Time->Day = BCD_INT(HalpReadCmos(7));
269 Time->Month = BCD_INT(HalpReadCmos(8));
270 Time->Year = BCD_INT(HalpReadCmos(9));
271 Time->Milliseconds = 0;
272
273 /* FIXME: Check century byte */
274
275 /* Compensate for the century field */
276 Time->Year += (Time->Year > 80) ? 1900: 2000;
277
278 /* Release CMOS lock */
279 HalpReleaseCmosSpinLock();
280
281 /* Always return TRUE */
282 return TRUE;
283 }
284
285 /*
286 * @implemented
287 */
288 BOOLEAN
289 NTAPI
290 HalSetRealTimeClock(IN PTIME_FIELDS Time)
291 {
292 /* Acquire CMOS Lock */
293 HalpAcquireSystemHardwareSpinLock();
294
295 /* Loop while update is in progress */
296 while ((HalpReadCmos(RTC_REGISTER_A)) & RTC_REG_A_UIP);
297
298 /* Write time fields to CMOS RTC */
299 HalpWriteCmos(0, INT_BCD(Time->Second));
300 HalpWriteCmos(2, INT_BCD(Time->Minute));
301 HalpWriteCmos(4, INT_BCD(Time->Hour));
302 HalpWriteCmos(6, INT_BCD(Time->Weekday));
303 HalpWriteCmos(7, INT_BCD(Time->Day));
304 HalpWriteCmos(8, INT_BCD(Time->Month));
305 HalpWriteCmos(9, INT_BCD(Time->Year % 100));
306
307 /* FIXME: Set the century byte */
308
309 /* Release CMOS lock */
310 HalpReleaseCmosSpinLock();
311
312 /* Always return TRUE */
313 return TRUE;
314 }