[CMAKE]
[reactos.git] / 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 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <hal.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 UCHAR HalpCmosCenturyOffset;
19
20 /* PRIVATE FUNCTIONS *********************************************************/
21
22 UCHAR
23 NTAPI
24 HalpReadCmos(IN UCHAR Reg)
25 {
26 /* Select the register */
27 WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg);
28
29 /* Query the value */
30 return READ_PORT_UCHAR(CMOS_DATA_PORT);
31 }
32
33 VOID
34 NTAPI
35 HalpWriteCmos(IN UCHAR Reg,
36 IN UCHAR Value)
37 {
38 /* Select the register */
39 WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg);
40
41 /* Write the value */
42 WRITE_PORT_UCHAR(CMOS_DATA_PORT, Value);
43 }
44
45 ULONG
46 NTAPI
47 HalpGetCmosData(IN ULONG BusNumber,
48 IN ULONG SlotNumber,
49 IN PVOID Buffer,
50 IN ULONG Length)
51 {
52 PUCHAR Ptr = (PUCHAR)Buffer;
53 ULONG Address = SlotNumber;
54 ULONG Len = Length;
55
56 /* Do nothing if we don't have a length */
57 if (!Length) return 0;
58
59 /* Acquire CMOS Lock */
60 HalpAcquireSystemHardwareSpinLock();
61
62 /* Check if this is simple CMOS */
63 if (BusNumber == 0)
64 {
65 /* Loop the buffer up to 0xFF */
66 while ((Len > 0) && (Address < 0x100))
67 {
68 /* Read the data */
69 *Ptr = HalpReadCmos((UCHAR)Address);
70
71 /* Update position and length */
72 Ptr++;
73 Address++;
74 Len--;
75 }
76 }
77 else if (BusNumber == 1)
78 {
79 /* Loop the buffer up to 0xFFFF */
80 while ((Len > 0) && (Address < 0x10000))
81 {
82 /* Write the data */
83 *Ptr = HalpReadCmos((UCHAR)Address);
84
85 /* Update position and length */
86 Ptr++;
87 Address++;
88 Len--;
89 }
90 }
91
92 /* Release CMOS Lock */
93 HalpReleaseCmosSpinLock();
94
95 /* Return length read */
96 return Length - Len;
97 }
98
99 ULONG
100 NTAPI
101 HalpSetCmosData(IN ULONG BusNumber,
102 IN ULONG SlotNumber,
103 IN PVOID Buffer,
104 IN ULONG Length)
105 {
106 PUCHAR Ptr = (PUCHAR)Buffer;
107 ULONG Address = SlotNumber;
108 ULONG Len = Length;
109
110 /* Do nothing if we don't have a length */
111 if (!Length) return 0;
112
113 /* Acquire CMOS Lock */
114 HalpAcquireSystemHardwareSpinLock();
115
116 /* Check if this is simple CMOS */
117 if (BusNumber == 0)
118 {
119 /* Loop the buffer up to 0xFF */
120 while ((Len > 0) && (Address < 0x100))
121 {
122 /* Write the data */
123 HalpWriteCmos((UCHAR)Address, *Ptr);
124
125 /* Update position and length */
126 Ptr++;
127 Address++;
128 Len--;
129 }
130 }
131 else if (BusNumber == 1)
132 {
133 /* Loop the buffer up to 0xFFFF */
134 while ((Len > 0) && (Address < 0x10000))
135 {
136 /* Write the data */
137 HalpWriteCmos((UCHAR)Address, *Ptr);
138
139 /* Update position and length */
140 Ptr++;
141 Address++;
142 Len--;
143 }
144 }
145
146 /* Release CMOS Lock */
147 HalpReleaseCmosSpinLock();
148
149 /* Return length read */
150 return Length - Len;
151 }
152
153 VOID
154 NTAPI
155 INIT_FUNCTION
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 }