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