Serenity Operating System
at hosted 109 lines 3.6 kB view raw
1/* 2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <Kernel/Arch/i386/CPU.h> 28#include <Kernel/CMOS.h> 29#include <Kernel/Time/RTC.h> 30#include <Kernel/Time/TimeManagement.h> 31#include <LibBareMetal/IO.h> 32 33namespace Kernel { 34#define IRQ_TIMER 8 35#define MAX_FREQUENCY 8000 36 37NonnullRefPtr<RealTimeClock> RealTimeClock::create(Function<void(const RegisterState&)> callback) 38{ 39 return adopt(*new RealTimeClock(move(callback))); 40} 41RealTimeClock::RealTimeClock(Function<void(const RegisterState&)> callback) 42 : HardwareTimer(IRQ_TIMER, move(callback)) 43{ 44 InterruptDisabler disabler; 45 NonMaskableInterruptDisabler nmi_disabler; 46 enable_irq(); 47 CMOS::write(0x8B, CMOS::read(0xB) | 0x40); 48 reset_to_default_ticks_per_second(); 49} 50void RealTimeClock::handle_irq(const RegisterState& regs) 51{ 52 HardwareTimer::handle_irq(regs); 53 CMOS::read(0x8C); 54} 55 56size_t RealTimeClock::ticks_per_second() const 57{ 58 return m_frequency; 59} 60 61void RealTimeClock::reset_to_default_ticks_per_second() 62{ 63 InterruptDisabler disabler; 64 bool success = try_to_set_frequency(1024); 65 ASSERT(success); 66} 67 68// FIXME: This is a quick & dirty log base 2 with a paramater. Please provide something better in the future. 69static int quick_log2(size_t number) 70{ 71 int count = 0; 72 while (number >>= 1) 73 count++; 74 return count; 75} 76 77bool RealTimeClock::try_to_set_frequency(size_t frequency) 78{ 79 InterruptDisabler disabler; 80 if (!is_capable_of_frequency(frequency)) 81 return false; 82 disable_irq(); 83 u8 previous_rate = CMOS::read(0x8A); 84 u8 rate = quick_log2(32768 / frequency) + 1; 85 dbg() << "RTC: Set rate to " << rate; 86 CMOS::write(0x8A, (previous_rate & 0xF0) | rate); 87 m_frequency = frequency; 88 dbg() << "RTC: Set frequency to " << frequency << " Hz"; 89 enable_irq(); 90 return true; 91} 92bool RealTimeClock::is_capable_of_frequency(size_t frequency) const 93{ 94 ASSERT(frequency != 0); 95 if (frequency > MAX_FREQUENCY) 96 return false; 97 if (32768 % frequency) 98 return false; 99 100 u16 divider = 32768 / frequency; 101 return (divider <= 16384 && divider >= 4); // Frequency can be in range of 2 Hz to 8 KHz 102} 103size_t RealTimeClock::calculate_nearest_possible_frequency(size_t frequency) const 104{ 105 ASSERT(frequency != 0); 106 return frequency; 107} 108 109}