/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.scheduler;
import org.jnode.annotation.Internal;
import org.jnode.annotation.KernelSpace;
import org.jnode.annotation.PrivilegedActionPragma;
import org.jnode.annotation.Uninterruptible;
import org.jnode.system.resource.IRQHandler;
import org.jnode.system.resource.IRQResource;
import org.jnode.system.resource.Resource;
import org.jnode.system.resource.ResourceNotFreeException;
import org.jnode.system.resource.ResourceOwner;
/**
* IRQ manager implementation.
*
* @author epr
*/
public abstract class IRQManager {
private final Object LOCK = new Object();
private final IRQThread[] handlers;
private final int count;
private final int[] irqCount;
private final VmProcessor defaultIrqProcessor;
/**
* Initialize a new instance
*
* @param irqCount
*/
@PrivilegedActionPragma
protected IRQManager(int[] irqCount, VmProcessor defaultIrqProcessor) {
this.irqCount = irqCount;
this.count = irqCount.length;
this.defaultIrqProcessor = defaultIrqProcessor;
this.handlers = new IRQThread[count];
}
/**
* Gets the IRQ counter value for the given IRQ
*
* @param irq
* @return The irq count
*/
public final int getIrqCount(int irq) {
return irqCount[irq];
}
/**
* Gets the number of IRQ's this processor supports.
*
* @return int
*/
public final int getNumIRQs() {
return count;
}
public Object getHandlerInfo(int irq) {
return handlers[irq];
}
/**
* Register an interrupt handler for a given irq number.
*
* @param owner
* @param irq
* @param handler
* @param shared
* @return True is the handler was set, false if there was already a handler for the given irq
* number set.
* @throws ResourceNotFreeException
*/
@Internal
public final IRQResource claimIRQ(ResourceOwner owner, int irq, IRQHandler handler, boolean shared)
throws ResourceNotFreeException {
IRQThread newThread = null;
synchronized (LOCK) {
final IRQThread thread = handlers[irq];
if (thread == null) {
newThread = new IRQThread(this, irq, owner, handler, shared, defaultIrqProcessor);
handlers[irq] = newThread;
} else {
if (thread.isShared()) {
if (shared) {
thread.addHandler(owner, handler);
} else {
throw new ResourceNotFreeException(
"IRQ " + irq + " is already claimed, but you don't want to share");
}
} else {
if (shared) {
throw new ResourceNotFreeException("IRQ " + irq + " is already claimed, but not shared");
} else {
//Unsafe.debug("IRQ was already claim");
throw new ResourceNotFreeException("IRQ " + irq + " is not free");
}
}
}
}
if (newThread != null) {
newThread.start();
}
return new IRQResourceImpl(owner, irq, handler, shared);
}
/**
* Unregister a given interrupt handler for a given irq number. If the current handler for the
* given irq number is not equal to the given handler, nothing is done.
*
* @param res The IRQ resource
*/
final void releaseIRQ(IRQResourceImpl res) {
final int irq = res.getIRQ();
synchronized (LOCK) {
final IRQThread thread = handlers[irq];
if (thread != null) {
thread.remove(res.getHandler());
if (thread.isEmpty()) {
handlers[irq] = null;
thread.stopThread();
}
}
}
}
/**
* Dispatch IRQ events to their corresponding threads. This method should only be called by the
* Thread scheduler.
*
* @param current
* @throws org.vmmagic.pragma.UninterruptiblePragma
*/
@KernelSpace
@Uninterruptible
final void dispatchInterrupts(VmThread current) {
final IRQThread[] hlist = handlers;
final int[] irqCount = this.irqCount;
final int max = this.count;
for (int irq = 0; irq < max; irq++) {
final IRQThread thread = hlist[irq];
if (thread != null) {
thread.signalIRQ(irqCount[irq], current);
} else {
// No handler, signal and End of Interrupt
eoi(irq);
}
}
}
/**
* Set an End Of Interrupt message to the 8259 interrupt controller(s).
*
* @param irq
*/
@Uninterruptible
@KernelSpace
protected abstract void eoi(int irq);
final class IRQResourceImpl implements IRQResource {
/**
* The owner of this resource
*/
private final ResourceOwner owner;
/**
* The IRQ number
*/
private final int irq;
/**
* The handler
*/
private final IRQHandler handler;
private final boolean shared;
/**
* Create a new instance
*
* @param owner
* @param irq
* @param handler
* @param shared
*/
public IRQResourceImpl(ResourceOwner owner, int irq, IRQHandler handler, boolean shared) {
this.owner = owner;
this.irq = irq;
this.handler = handler;
this.shared = shared;
}
/**
* @return int
* @see org.jnode.system.resource.IRQResource#getIRQ()
*/
public int getIRQ() {
return irq;
}
/**
* Is this a shared interrupt?
*
* @return boolean
*/
public boolean isShared() {
return shared;
}
/**
* @return The owner
* @see org.jnode.system.resource.Resource#getOwner()
*/
public ResourceOwner getOwner() {
return owner;
}
public IRQHandler getHandler() {
return handler;
}
/**
* @see org.jnode.system.resource.Resource#release()
*/
public void release() {
releaseIRQ(this);
}
/**
* Gets the parent resource if any.
*
* @return The parent resource, or null if this resource has no parent.
*/
public Resource getParent() {
return null;
}
}
}