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