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 #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 UCHAR 27 NTAPI 28 HalpReadCmos(IN UCHAR Reg) 29 { 30 /* Select the register */ 31 WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg); 32 33 /* Query the value */ 34 return READ_PORT_UCHAR(CMOS_DATA_PORT); 35 } 36 37 VOID 38 NTAPI 39 HalpWriteCmos(IN UCHAR Reg, 40 IN UCHAR Value) 41 { 42 /* Select the register */ 43 WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg); 44 45 /* Write the value */ 46 WRITE_PORT_UCHAR(CMOS_DATA_PORT, Value); 47 } 48 49 ULONG 50 NTAPI 51 HalpGetCmosData(IN ULONG BusNumber, 52 IN ULONG SlotNumber, 53 IN PVOID Buffer, 54 IN ULONG Length) 55 { 56 PUCHAR Ptr = (PUCHAR)Buffer; 57 ULONG Address = SlotNumber; 58 ULONG Len = Length; 59 60 /* Do nothing if we don't have a length */ 61 if (!Length) return 0; 62 63 /* Acquire CMOS Lock */ 64 HalpAcquireCmosSpinLock(); 65 66 /* Check if this is simple CMOS */ 67 if (BusNumber == 0) 68 { 69 /* Loop the buffer up to 0xFF */ 70 while ((Len > 0) && (Address < 0x100)) 71 { 72 /* Read the data */ 73 *Ptr = HalpReadCmos((UCHAR)Address); 74 75 /* Update position and length */ 76 Ptr++; 77 Address++; 78 Len--; 79 } 80 } 81 else if (BusNumber == 1) 82 { 83 /* Loop the buffer up to 0xFFFF */ 84 while ((Len > 0) && (Address < 0x10000)) 85 { 86 /* Write the data */ 87 *Ptr = HalpReadCmos((UCHAR)Address); 88 89 /* Update position and length */ 90 Ptr++; 91 Address++; 92 Len--; 93 } 94 } 95 96 /* Release CMOS Lock */ 97 HalpReleaseCmosSpinLock(); 98 99 /* Return length read */ 100 return Length - Len; 101 } 102 103 ULONG 104 NTAPI 105 HalpSetCmosData(IN ULONG BusNumber, 106 IN ULONG SlotNumber, 107 IN 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 INIT_FUNCTION 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(IN PCH Name, 177 IN USHORT ValueLength, 178 IN 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