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)
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 KSPIN_LOCK HalpSystemHardwareLock
;
19 UCHAR HalpCmosCenturyOffset
;
20 ULONG HalpSystemHardwareFlags
;
22 /* PRIVATE FUNCTIONS **********************************************************/
26 HalpAcquireSystemHardwareSpinLock(VOID
)
30 /* Get flags and disable interrupts */
31 Flags
= __readeflags();
34 /* Acquire the lock */
35 KxAcquireSpinLock(&HalpSystemHardwareLock
);
37 /* We have the lock, save the flags now */
38 HalpSystemHardwareFlags
= Flags
;
43 HalpReleaseCmosSpinLock(VOID
)
48 Flags
= HalpSystemHardwareFlags
;
50 /* Release the lock */
51 KxReleaseSpinLock(&HalpSystemHardwareLock
);
53 /* Restore the flags */
59 HalpReadCmos(IN UCHAR Reg
)
61 /* Select the register */
62 WRITE_PORT_UCHAR(CMOS_CONTROL_PORT
, Reg
);
65 return READ_PORT_UCHAR(CMOS_DATA_PORT
);
70 HalpWriteCmos(IN UCHAR Reg
,
73 /* Select the register */
74 WRITE_PORT_UCHAR(CMOS_CONTROL_PORT
, Reg
);
77 WRITE_PORT_UCHAR(CMOS_DATA_PORT
, Value
);
82 HalpGetCmosData(IN ULONG BusNumber
,
87 PUCHAR Ptr
= (PUCHAR
)Buffer
;
88 ULONG Address
= SlotNumber
;
91 /* Do nothing if we don't have a length */
92 if (!Length
) return 0;
94 /* Acquire CMOS Lock */
95 HalpAcquireSystemHardwareSpinLock();
97 /* Check if this is simple CMOS */
100 /* Loop the buffer up to 0xFF */
101 while ((Len
> 0) && (Address
< 0x100))
104 *Ptr
= HalpReadCmos((UCHAR
)Address
);
106 /* Update position and length */
112 else if (BusNumber
== 1)
114 /* Loop the buffer up to 0xFFFF */
115 while ((Len
> 0) && (Address
< 0x10000))
118 *Ptr
= HalpReadCmos((UCHAR
)Address
);
120 /* Update position and length */
127 /* Release CMOS Lock */
128 HalpReleaseCmosSpinLock();
130 /* Return length read */
136 HalpSetCmosData(IN ULONG BusNumber
,
141 PUCHAR Ptr
= (PUCHAR
)Buffer
;
142 ULONG Address
= SlotNumber
;
145 /* Do nothing if we don't have a length */
146 if (!Length
) return 0;
148 /* Acquire CMOS Lock */
149 HalpAcquireSystemHardwareSpinLock();
151 /* Check if this is simple CMOS */
154 /* Loop the buffer up to 0xFF */
155 while ((Len
> 0) && (Address
< 0x100))
158 HalpWriteCmos((UCHAR
)Address
, *Ptr
);
160 /* Update position and length */
166 else if (BusNumber
== 1)
168 /* Loop the buffer up to 0xFFFF */
169 while ((Len
> 0) && (Address
< 0x10000))
172 HalpWriteCmos((UCHAR
)Address
, *Ptr
);
174 /* Update position and length */
181 /* Release CMOS Lock */
182 HalpReleaseCmosSpinLock();
184 /* Return length read */
190 HalpInitializeCmos(VOID
)
192 /* Set default century offset byte */
193 HalpCmosCenturyOffset
= 50;
195 /* No support for EISA or MCA */
196 ASSERT(HalpBusType
== MACHINE_TYPE_ISA
);
199 /* PUBLIC FUNCTIONS **********************************************************/
206 HalGetEnvironmentVariable(IN PCH Name
,
207 IN USHORT ValueLength
,
212 /* Only variable supported on x86 */
213 if (_stricmp(Name
, "LastKnownGood")) return ENOENT
;
215 /* Acquire CMOS Lock */
216 HalpAcquireSystemHardwareSpinLock();
218 /* Query the current value */
219 Val
= HalpReadCmos(RTC_REGISTER_B
) & 0x01;
221 /* Release CMOS lock */
222 HalpReleaseCmosSpinLock();
228 strncpy(Value
, "FALSE", ValueLength
);
233 strncpy(Value
, "TRUE", ValueLength
);
245 HalSetEnvironmentVariable(IN PCH Name
,
250 /* Only variable supported on x86 */
251 if (_stricmp(Name
, "LastKnownGood")) return ENOMEM
;
253 /* Check if this is true or false */
254 if (!_stricmp(Value
, "TRUE"))
256 /* It's true, acquire CMOS lock */
257 HalpAcquireSystemHardwareSpinLock();
259 /* Read the current value and add the flag */
260 Val
= HalpReadCmos(RTC_REGISTER_B
) | 1;
262 else if (!_stricmp(Value
, "FALSE"))
264 /* It's false, acquire CMOS lock */
265 HalpAcquireSystemHardwareSpinLock();
267 /* Read the current value and mask out the flag */
268 Val
= HalpReadCmos(RTC_REGISTER_B
) & ~1;
276 /* Write new value */
277 HalpWriteCmos(RTC_REGISTER_B
, Val
);
279 /* Release the lock and return success */
280 HalpReleaseCmosSpinLock();
289 HalQueryRealTimeClock(OUT PTIME_FIELDS Time
)
291 /* Acquire CMOS Lock */
292 HalpAcquireSystemHardwareSpinLock();
294 /* Loop while update is in progress */
295 while ((HalpReadCmos(RTC_REGISTER_A
)) & RTC_REG_A_UIP
);
297 /* Set the time data */
298 Time
->Second
= BCD_INT(HalpReadCmos(0));
299 Time
->Minute
= BCD_INT(HalpReadCmos(2));
300 Time
->Hour
= BCD_INT(HalpReadCmos(4));
301 Time
->Weekday
= BCD_INT(HalpReadCmos(6));
302 Time
->Day
= BCD_INT(HalpReadCmos(7));
303 Time
->Month
= BCD_INT(HalpReadCmos(8));
304 Time
->Year
= BCD_INT(HalpReadCmos(9));
305 Time
->Milliseconds
= 0;
307 /* FIXME: Check century byte */
309 /* Compensate for the century field */
310 Time
->Year
+= (Time
->Year
> 80) ? 1900: 2000;
312 /* Release CMOS lock */
313 HalpReleaseCmosSpinLock();
315 /* Always return TRUE */
324 HalSetRealTimeClock(IN PTIME_FIELDS Time
)
326 /* Acquire CMOS Lock */
327 HalpAcquireSystemHardwareSpinLock();
329 /* Loop while update is in progress */
330 while ((HalpReadCmos(RTC_REGISTER_A
)) & RTC_REG_A_UIP
);
332 /* Write time fields to CMOS RTC */
333 HalpWriteCmos(0, INT_BCD(Time
->Second
));
334 HalpWriteCmos(2, INT_BCD(Time
->Minute
));
335 HalpWriteCmos(4, INT_BCD(Time
->Hour
));
336 HalpWriteCmos(6, INT_BCD(Time
->Weekday
));
337 HalpWriteCmos(7, INT_BCD(Time
->Day
));
338 HalpWriteCmos(8, INT_BCD(Time
->Month
));
339 HalpWriteCmos(9, INT_BCD(Time
->Year
% 100));
341 /* FIXME: Set the century byte */
343 /* Release CMOS lock */
344 HalpReleaseCmosSpinLock();
346 /* Always return TRUE */