genode/base-pistachio/src/core/irq_session_component.cc

135 lines
3.0 KiB
C++

/*
* \brief Pistachio-specific implementation of IRQ sessions
* \author Julian Stecklina
* \date 2008-02-21
*
* FIXME ram quota missing
*/
/*
* Copyright (C) 2008-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <util/arg_string.h>
/* core includes */
#include <irq_root.h>
#include <util.h>
/* Pistachio includes */
namespace Pistachio {
#include <l4/ipc.h>
}
using namespace Genode;
using namespace Pistachio;
static inline L4_ThreadId_t irqno_to_threadid(unsigned int irqno)
{
/*
* Interrupt threads have their number as thread_no and a version of 1.
*/
return L4_GlobalId(irqno, 1);
}
bool Irq_session_component::Irq_control_component::associate_to_irq(unsigned)
{
/*
* We defer the association with the IRQ to the first call of the
* 'wait_for_irq' function.
*/
return true;
}
void Irq_session_component::wait_for_irq()
{
L4_ThreadId_t irq_thread = irqno_to_threadid(_irq_number);
/* attach to IRQ when called for the first time */
L4_MsgTag_t res;
if (!_irq_attached) {
if (L4_AssociateInterrupt(irq_thread, L4_Myself()) != true) {
PERR("L4_AssociateInterrupt failed");
return;
}
/*
* Right after associating with an interrupt, the interrupt is
* unmasked. Hence, we do not need to send an unmask message
* to the IRQ thread but just wait for the IRQ.
*/
L4_Set_MsgTag(L4_Niltag);
res = L4_Receive(irq_thread);
/*
* Now, the IRQ is masked. To receive the next IRQ we have to send
* an unmask message to the IRQ thread first.
*/
_irq_attached = true;
/* receive subsequent interrupt */
} else {
/* send unmask message and wait for new IRQ */
L4_Set_MsgTag(L4_Niltag);
res = L4_Call(irq_thread);
}
if (L4_IpcFailed(res)) {
PERR("ipc error while waiting for interrupt.");
return;
}
}
Irq_session_component::Irq_session_component(Cap_session *cap_session,
Range_allocator *irq_alloc,
const char *args)
:
_irq_alloc(irq_alloc),
_ep(cap_session, STACK_SIZE, "irqctrl"),
_irq_attached(false),
_control_client(Capability<Irq_session_component::Irq_control>())
{
bool shared = Arg_string::find_arg(args, "irq_shared").bool_value(false);
if (shared) {
PWRN("IRQ sharing not supported");
/* FIXME error condition -> exception */
return;
}
long irq_number = Arg_string::find_arg(args, "irq_number").long_value(-1);
if (irq_number == -1 || !irq_alloc ||
irq_alloc->alloc_addr(1, irq_number).is_error()) {
PERR("unavailable IRQ %lx requested", irq_number);
/* FIXME error condition -> exception */
return;
}
_irq_number = irq_number;
/* initialize capability */
_irq_cap = _ep.manage(this);
}
Irq_session_component::~Irq_session_component()
{
L4_Word_t res = L4_DeassociateInterrupt(irqno_to_threadid(_irq_number));
if (res != 1) {
PERR("L4_DeassociateInterrupt failed");
}
}