HPETComparator.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  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. #include <Kernel/Assertions.h>
  27. #include <Kernel/Debug.h>
  28. #include <Kernel/Time/HPETComparator.h>
  29. #include <Kernel/Time/TimeManagement.h>
  30. namespace Kernel {
  31. NonnullRefPtr<HPETComparator> HPETComparator::create(u8 number, u8 irq, bool periodic_capable)
  32. {
  33. return adopt(*new HPETComparator(number, irq, periodic_capable));
  34. }
  35. HPETComparator::HPETComparator(u8 number, u8 irq, bool periodic_capable)
  36. : HardwareTimer(irq)
  37. , m_periodic(false)
  38. , m_periodic_capable(periodic_capable)
  39. , m_enabled(false)
  40. , m_comparator_number(number)
  41. {
  42. }
  43. void HPETComparator::disable()
  44. {
  45. if (!m_enabled)
  46. return;
  47. m_enabled = false;
  48. HPET::the().disable(*this);
  49. }
  50. void HPETComparator::set_periodic()
  51. {
  52. ASSERT(m_periodic_capable);
  53. m_periodic = true;
  54. m_enabled = true;
  55. HPET::the().enable_periodic_interrupt(*this);
  56. }
  57. void HPETComparator::set_non_periodic()
  58. {
  59. ASSERT(m_periodic_capable);
  60. m_periodic = false;
  61. m_enabled = true;
  62. HPET::the().disable_periodic_interrupt(*this);
  63. }
  64. void HPETComparator::handle_irq(const RegisterState& regs)
  65. {
  66. HardwareTimer::handle_irq(regs);
  67. if (!is_periodic())
  68. set_new_countdown();
  69. }
  70. void HPETComparator::set_new_countdown()
  71. {
  72. ASSERT_INTERRUPTS_DISABLED();
  73. ASSERT(m_frequency <= HPET::the().frequency());
  74. HPET::the().update_non_periodic_comparator_value(*this);
  75. }
  76. size_t HPETComparator::ticks_per_second() const
  77. {
  78. return m_frequency;
  79. }
  80. void HPETComparator::reset_to_default_ticks_per_second()
  81. {
  82. dbgln("reset_to_default_ticks_per_second");
  83. m_frequency = OPTIMAL_TICKS_PER_SECOND_RATE;
  84. if (!is_periodic())
  85. set_new_countdown();
  86. else
  87. try_to_set_frequency(m_frequency);
  88. }
  89. bool HPETComparator::try_to_set_frequency(size_t frequency)
  90. {
  91. InterruptDisabler disabler;
  92. if (!is_capable_of_frequency(frequency)) {
  93. dbgln("HPETComparator: not cable of frequency: {}", frequency);
  94. return false;
  95. }
  96. auto hpet_frequency = HPET::the().frequency();
  97. ASSERT(frequency <= hpet_frequency);
  98. m_frequency = frequency;
  99. m_enabled = true;
  100. dbgln<HPET_COMPARATOR_DEBUG>("HPET Comparator: Max frequency {} Hz, want to set {} Hz, periodic: {}", hpet_frequency, frequency, is_periodic());
  101. if (is_periodic()) {
  102. HPET::the().update_periodic_comparator_value();
  103. } else {
  104. HPET::the().update_non_periodic_comparator_value(*this);
  105. }
  106. enable_irq(); // Enable if we haven't already
  107. return true;
  108. }
  109. bool HPETComparator::is_capable_of_frequency(size_t frequency) const
  110. {
  111. if (frequency > HPET::the().frequency())
  112. return false;
  113. // HPET::update_periodic_comparator_value and HPET::update_non_periodic_comparator_value
  114. // calculate the best counter based on the desired frequency.
  115. return true;
  116. }
  117. size_t HPETComparator::calculate_nearest_possible_frequency(size_t frequency) const
  118. {
  119. if (frequency > HPET::the().frequency())
  120. return HPET::the().frequency();
  121. // HPET::update_periodic_comparator_value and HPET::update_non_periodic_comparator_value
  122. // calculate the best counter based on the desired frequency.
  123. return frequency;
  124. }
  125. }