//----------------------------------------------------------------------------// // OS on Kaleid // // // // Desc: RTC Time related functions // // // // // // Copyright © 2018-2021 The OS/K Team // // // // This file is part of OS/K. // // // // OS/K is free software: you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation, either version 3 of the License, or // // any later version. // // // // OS/K is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY//without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License for more details. // // // // You should have received a copy of the GNU General Public License // // along with OS/K. If not, see . // //----------------------------------------------------------------------------// #include #include #include static ulong Ticks = 0; static Time_t OriginTime; // TODO asnprintf() static uchar RTC_RATE = 0x05; //2048Hz static char time24or12Mode; static void GetTimeFromRTC(void) { Time_t lastTime; char updateInProgress = 1; // Wait while the RTC updates its value while (updateInProgress) { IoWriteByteOnPort(0x70, 0x0A); updateInProgress = (IoReadByteFromPort(0x71) & 0x80); } IoWriteByteOnPort(0x70, 0x0); OriginTime.sec = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x02); OriginTime.min = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x04); OriginTime.hour = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x06); OriginTime.weekday = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x07); OriginTime.day = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x08); OriginTime.month = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x09); OriginTime.year = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x32); OriginTime.century = IoReadByteFromPort(0x71); // Now while we don't get the same value, // read the registers (ensure data are valid) do { lastTime.sec = OriginTime.sec; lastTime.min = OriginTime.min; lastTime.hour = OriginTime.hour; lastTime.weekday = OriginTime.weekday; lastTime.day = OriginTime.day; lastTime.month = OriginTime.month; lastTime.year = OriginTime.year; lastTime.century = OriginTime.century; while (updateInProgress) { IoWriteByteOnPort(0x70, 0x0A); updateInProgress = (IoReadByteFromPort(0x71) & 0x80); } IoWriteByteOnPort(0x70, 0x0); OriginTime.sec = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x02); OriginTime.min = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x04); OriginTime.hour = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x06); OriginTime.weekday = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x07); OriginTime.day = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x08); OriginTime.month = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x09); OriginTime.year = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x32); OriginTime.century = IoReadByteFromPort(0x71); } while ((lastTime.sec != OriginTime.sec) || (lastTime.min != OriginTime.min) || (lastTime.hour != OriginTime.hour) || (lastTime.weekday != OriginTime.weekday) || (lastTime.day != OriginTime.day) || (lastTime.month != OriginTime.month) || (lastTime.year != OriginTime.year) || (lastTime.century != OriginTime.century) ); IoWriteByteOnPort(0x70, 0x0B); time24or12Mode = IoReadByteFromPort(0x71); // Convert to binary if it is necessary if (!(time24or12Mode & 0x04)) { OriginTime.sec = (OriginTime.sec & 0x0F) + ((OriginTime.sec / 16) * 10); OriginTime.min = (OriginTime.min & 0x0F) + ((OriginTime.min / 16) * 10); OriginTime.hour = ( (OriginTime.hour & 0x0F) + (((OriginTime.hour & 0x70) / 16) * 10) ) | (OriginTime.hour & 0x80); OriginTime.day = (OriginTime.day & 0x0F) + ((OriginTime.day / 16) * 10); OriginTime.month = (OriginTime.month & 0x0F) + ((OriginTime.month / 16) * 10); OriginTime.year = (OriginTime.year & 0x0F) + ((OriginTime.year / 16) * 10); OriginTime.century = (OriginTime.century & 0x0F) + ((OriginTime.century / 16) * 10); OriginTime.weekday = (OriginTime.weekday & 0x0F) + ((OriginTime.weekday / 16) * 10); } // Convert 12 to 24 hour if necessary if (!(time24or12Mode & 0x02) && (OriginTime.hour & 0x80)) { OriginTime.hour = ((OriginTime.hour & 0x7)+ 10) % 24; } KeSetCurTime(OriginTime); } // // ISR handler for the real time clock // static void HandleRTC(ISRFrame_t *regs) { IoWriteByteOnPort(0x70, 0x0C); // Selects status reg C IoReadByteFromPort(0x71); // Flush Ticks++; KeSendEOItoPIC(0x28); } ulong KeGetClockTicks(void) { return Ticks; } Time_t* KeGetOriginTime(void) { return &OriginTime; } void KeEnableRTC(void) { ulong flags = KePauseIRQs(); char readInterruptConfig; char readRegister; KeRegisterISR(HandleRTC, 0x28); // Setting up the register control and interrupt rates IoWriteByteOnPort(0x70, 0x8B); readRegister = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x8B); // Because reading flushes IoWriteByteOnPort(0x71, readRegister | 0x40); IoWriteByteOnPort(0x70, 0x8A); readInterruptConfig = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x8A); // Because reading flushes IoWriteByteOnPort(0x71, (readInterruptConfig & 0xF0) | RTC_RATE); IoWriteByteOnPort(0x70, 0x0C); IoReadByteFromPort(0x71); // Flush // Setting up the IRQ line KeUnmaskIRQ(8); // Clean-up IoWriteByteOnPort(0x70, 0x0C); // Select status reg C IoReadByteFromPort(0x71); // Flush GetTimeFromRTC(); KeRestoreIRQs(flags); KeEnableNMI(); srand(KeGetTimeStamp()); // init number generator DebugLog("RTC interrupt frequency set to %d Hz\n", 32768 >> (RTC_RATE - 1)); } void KeDelayExecution(uint time) { ulong frequency = 32768 >> (RTC_RATE - 1); ulong beginTick = KeGetClockTicks(); while (KeGetClockTicks() < beginTick + (frequency/1000) * time) { KeRelaxCPU(); } }