The Pedigree Project  0.1
malta/Pic.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "Pic.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/compiler.h"
23 #include "pedigree/kernel/debugger/Debugger.h"
24 
25 // TODO: Needs locking
26 
27 #define BASE_INTERRUPT_VECTOR 0x20
28 
30 
31 irq_id_t Pic::registerIsaIrqHandler(uint8_t irq, IrqHandler *handler)
32 {
33  if (UNLIKELY(irq >= 16))
34  return 0;
35 
36  // Save the IrqHandler
37  m_Handler[irq] = handler;
38 
39  // Enable/Unmask the IRQ
40  enable(irq, true);
41 
42  return irq + BASE_INTERRUPT_VECTOR;
43 }
44 irq_id_t Pic::registerPciIrqHandler(IrqHandler *handler)
45 {
46  // TODO
47  return 0;
48 }
49 void Pic::acknowledgeIrq(irq_id_t Id)
50 {
51  uint8_t irq = Id - BASE_INTERRUPT_VECTOR;
52 
53  // Enable the irq again (the interrupt reason got removed)
54  enable(irq, true);
55  eoi(irq);
56 }
57 void Pic::unregisterHandler(irq_id_t Id, IrqHandler *handler)
58 {
59  uint8_t irq = Id - BASE_INTERRUPT_VECTOR;
60 
61  // Disable the IRQ
62  enable(irq, false);
63 
64  // Remove the handler
65  m_Handler[irq] = 0;
66 }
67 
68 bool Pic::initialise()
69 {
70  // Allocate the I/O ports
71  // if (m_SlavePort.allocate(0xA0, 4) == false)
72  // return false;
73  // if (m_MasterPort.allocate(0x20, 4) == false)
74  // return false;
75 
76  // Initialise the slave and master PIC
77  /* m_MasterPort.write8(0x11, 0);
78  m_SlavePort.write8(0x11, 0);
79  m_MasterPort.write8(BASE_INTERRUPT_VECTOR, 1);
80  m_SlavePort.write8(BASE_INTERRUPT_VECTOR + 0x08, 1);
81  m_MasterPort.write8(0x04, 1);
82  m_SlavePort.write8(0x02, 1);
83  m_MasterPort.write8(0x01, 1);
84  m_SlavePort.write8(0x01, 1);
85  */
86  // Register the interrupts
88  if (IntManager.registerInterruptHandler(0, this) == false)
89 
90  // Disable all IRQ's (exept IRQ2)
91  enableAll(false);
92 
93  return true;
94 }
95 
96 Pic::Pic()
97 //: m_SlavePort("PIC #2"), m_MasterPort("PIC #1")
98 {
99  for (size_t i = 0; i < 16; i++)
100  m_Handler[i] = 0;
101 }
102 
103 void Pic::interrupt(size_t interruptNumber, InterruptState &state)
104 {
105  size_t irq = (interruptNumber - BASE_INTERRUPT_VECTOR);
106 
107  // Is Spurious IRQ7?
108  if (irq == 7)
109  {
110  m_MasterPort.write8(0x03, 3);
111  if (UNLIKELY((m_MasterPort.read8(0) & 0x80) == 0))
112  {
113  NOTICE("PIC: spurious IRQ7");
114  return;
115  }
116  }
117  // Is spurious IRQ15?
118  else if (irq == 15)
119  {
120  m_SlavePort.write8(0x03, 3);
121  if (UNLIKELY((m_SlavePort.read8(0) & 0x80) == 0))
122  {
123  NOTICE("PIC: spurious IRQ15");
124  return;
125  }
126  }
127 
128  // Call the irq handler, if any
129  if (LIKELY(m_Handler[irq] != 0))
130  {
131  if (m_Handler[irq]->irq(irq, state) == false)
132  {
133  // Disable/Mask the IRQ line (the handler did not remove
134  // the interrupt reason, yet)
135  enable(irq, false);
136  }
137  }
138  else
139  {
140  NOTICE("PIC: unhandled irq #" << irq << " occurred");
141 
142 #ifdef DEBUGGER
143  LargeStaticString str;
144  str += "Unhandled IRQ: #";
145  str += irq;
146  str += " occurred.";
147  Debugger::instance().start(state, str);
148 #endif
149  }
150 
151  eoi(irq);
152 }
153 
154 void Pic::eoi(uint8_t irq)
155 {
156  /* m_MasterPort.write8(0x20, 0);
157  if (irq > 7)
158  m_SlavePort.write8(0x20, 0);*/
159 }
160 void Pic::enable(uint8_t irq, bool enable)
161 {
162  if (irq <= 7)
163  {
164  uint8_t mask = m_MasterPort.read8(1);
165  if (enable == true)
166  mask = mask & ~(1 << irq);
167  else
168  mask = mask | (1 << irq);
169 
170  // m_MasterPort.write8(mask, 1);
171  }
172  else
173  {
174  uint8_t mask = m_SlavePort.read8(1);
175  if (enable == true)
176  mask = mask & ~(1 << (irq - 8));
177  else
178  mask = mask | (1 << (irq - 8));
179 
180  // m_SlavePort.write8(mask, 1);
181  }
182 }
183 void Pic::enableAll(bool enable)
184 {
185  if (enable == false)
186  {
187  // m_MasterPort.write8(0xFB, 1);
188  // m_SlavePort.write8(0xFB, 1);
189  }
190  else
191  {
192  // m_MasterPort.write8(0x00, 1);
193  // m_SlavePort.write8(0x00, 1);
194  }
195 }
IoPort m_MasterPort
Definition: mach_pc/Pic.h:101
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
virtual irq_id_t registerPciIrqHandler(IrqHandler *handler, Device *pDevice)
Definition: mach_pc/Pic.cc:86
virtual void acknowledgeIrq(irq_id_t Id)
Definition: mach_pc/Pic.cc:103
static Debugger & instance()
Definition: Debugger.h:48
Handles interrupts and interrupt registrations from kernel components.
virtual uint8_t read8(size_t offset=0)
IoPort m_SlavePort
Definition: mach_pc/Pic.h:99
virtual void unregisterHandler(irq_id_t Id, IrqHandler *handler)
Definition: mach_pc/Pic.cc:111
List< IrqHandler * > m_Handler[16]
Definition: mach_pc/Pic.h:104
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
static Pic m_Instance
Definition: mach_pc/Pic.h:120
#define NOTICE(text)
Definition: Log.h:74
Pic() INITIALISATION_ONLY
Definition: mach_pc/Pic.cc:171
virtual void interrupt(size_t interruptNumber, InterruptState &state)
Definition: mach_pc/Pic.cc:204
static InterruptManager & instance()
virtual irq_id_t registerIsaIrqHandler(uint8_t irq, IrqHandler *handler, bool bEdge=false)
Definition: mach_pc/Pic.cc:72
bool initialise() INITIALISATION_ONLY
Definition: mach_pc/Pic.cc:131
virtual void write8(uint8_t value, size_t offset=0)