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