Serenity Operating System
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/Assertions.h>
29#include <Kernel/Interrupts/IRQHandler.h>
30#include <Kernel/Interrupts/InterruptManagement.h>
31#include <Kernel/Interrupts/PIC.h>
32#include <Kernel/Interrupts/SharedIRQHandler.h>
33
34//#define INTERRUPT_DEBUG
35namespace Kernel {
36
37void SharedIRQHandler::initialize(u8 interrupt_number)
38{
39 new SharedIRQHandler(interrupt_number);
40}
41
42void SharedIRQHandler::register_handler(GenericInterruptHandler& handler)
43{
44#ifdef INTERRUPT_DEBUG
45 kprintf("Interrupt Handler registered @ Shared Interrupt Handler %d\n", m_interrupt_number);
46#endif
47 m_handlers.set(&handler);
48 enable_interrupt_vector();
49}
50void SharedIRQHandler::unregister_handler(GenericInterruptHandler& handler)
51{
52#ifdef INTERRUPT_DEBUG
53 kprintf("Interrupt Handler unregistered @ Shared Interrupt Handler %d\n", m_interrupt_number);
54#endif
55 m_handlers.remove(&handler);
56 if (m_handlers.is_empty())
57 disable_interrupt_vector();
58}
59
60bool SharedIRQHandler::eoi()
61{
62#ifdef INTERRUPT_DEBUG
63 dbg() << "EOI IRQ " << interrupt_number();
64#endif
65 InterruptManagement::the().eoi(interrupt_number());
66 return true;
67}
68
69SharedIRQHandler::SharedIRQHandler(u8 irq)
70 : GenericInterruptHandler(irq)
71{
72#ifdef INTERRUPT_DEBUG
73 kprintf("Shared Interrupt Handler registered @ %d\n", m_interrupt_number);
74#endif
75 register_generic_interrupt_handler(irq, *this);
76 disable_interrupt_vector();
77}
78
79SharedIRQHandler::~SharedIRQHandler()
80{
81#ifdef INTERRUPT_DEBUG
82 kprintf("Shared Interrupt Handler unregistered @ %d\n", interrupt_number());
83#endif
84 disable_interrupt_vector();
85 unregister_generic_interrupt_handler(interrupt_number(), *this);
86}
87
88void SharedIRQHandler::handle_interrupt(RegisterState& regs)
89{
90 ASSERT_INTERRUPTS_DISABLED();
91 increment_invoking_counter();
92#ifdef INTERRUPT_DEBUG
93 dbg() << "Interrupt @ " << interrupt_number();
94 dbg() << "Interrupt Handlers registered - " << m_handlers.size();
95#endif
96 int i = 0;
97 for (auto* handler : m_handlers) {
98#ifdef INTERRUPT_DEBUG
99 dbg() << "Going for Interrupt Handling @ " << i << ", Shared Interrupt " << interrupt_number();
100#endif
101 ASSERT(handler != nullptr);
102 if (handler->is_enabled()) {
103 handler->increment_invoking_counter();
104 handler->handle_interrupt(regs);
105 }
106
107#ifdef INTERRUPT_DEBUG
108 dbg() << "Going for Interrupt Handling @ " << i << ", Shared Interrupt " << interrupt_number() << " - End";
109#endif
110 i++;
111 }
112}
113
114void SharedIRQHandler::enable_interrupt_vector()
115{
116 if (m_enabled)
117 return;
118 m_enabled = true;
119 InterruptManagement::the().enable(interrupt_number());
120}
121
122void SharedIRQHandler::disable_interrupt_vector()
123{
124 if (!m_enabled)
125 return;
126 m_enabled = false;
127 InterruptManagement::the().disable(interrupt_number());
128}
129
130}