singrdk/base/Kernel/Singularity.Io/IoIrq.cs

183 lines
5.1 KiB
C#

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: IoIrq.cs
//
//#define DEBUG_DISPATCH_IO
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.Singularity.Hal;
namespace Microsoft.Singularity.Io
{
[CLSCompliant(false)]
public sealed class IoIrq
{
private readonly byte irq;
private InterruptAwareAutoResetEvent! signal;
private IoIrq next;
private bool registered;
//////////////////////////////////////////////////////////////////////
//
//
private const int MaxInterrupts = 256;
private static IoIrq[]! irqTable;
private static SpinLock regLock;
static IoIrq()
{
irqTable = new IoIrq [MaxInterrupts];
regLock = new SpinLock(SpinLock.Types.IoIrq);
}
[NoHeapAllocation]
private static bool AcquireLock()
{
bool enabled = Processor.DisableInterrupts();
#if SINGULARITY_MP
regLock.Acquire();
#endif // SINGULARITY_MP
return enabled;
}
[NoHeapAllocation]
private static void ReleaseLock(bool enabled)
{
#if SINGULARITY_MP
regLock.Release();
#endif // SINGULARITY_MP
Processor.RestoreInterrupts(enabled);
}
// This doesn't need a lock because Register and Release
// insure that the list is *always* valid (even when being updated).
[NoHeapAllocation]
public static void SignalInterrupt(byte irq)
{
#if DEBUG_DISPATCH_IO
DebugStub.WriteLine("++ SetInterruptEvent: Irq={0:x2}", __arglist(irq));
#endif
for (IoIrq step = irqTable[irq]; step != null; step = step.next) {
step.signal.InterruptAwareSet();
}
}
public IoIrq(byte irq)
{
this.irq = irq;
this.next = null;
this.signal = new InterruptAwareAutoResetEvent(false);
this.registered = false;
}
public byte Irq
{
[NoHeapAllocation]
get { return irq; }
}
// Insert the IoIrq into the linked list for this irq.
// If it is the first entry, then notify HAL to enable its irq.
// Returns true if this IoIrq caused the irq to be enabled.
public bool RegisterInterrupt()
{
bool enabled = AcquireLock();
try {
Tracing.Log(Tracing.Debug, "Register Irq={0:x2}", irq);
#if DEBUG_DISPATCH_IO
DebugStub.WriteLine("++ Register Irq={0:x2}", __arglist(irq));
#endif
this.next = irqTable[irq];
irqTable[irq] = this;
this.registered = true;
if (next == null) {
Platform.EnableIoInterrupt(irq);
return true;
}
}
finally {
ReleaseLock(enabled);
}
return false;
}
// Remove the IoIrq into the linked list for this irq.
// If it is the last entry, then notify HAL to disable its irq.
// Returns true if this IoIrq caused the irq to be disabled.
public bool ReleaseInterrupt()
{
bool enabled = AcquireLock();
try {
Tracing.Log(Tracing.Debug, "Release Irq={0:x2}", irq);
#if DEBUG_DISPATCH_IO
DebugStub.WriteLine("++ Release Irq={0:x2}", __arglist(irq));
#endif
if (irqTable[irq] == this) {
irqTable[irq] = this.next;
}
else {
IoIrq! prev = (!)irqTable[irq];
while (prev.next != this) {
prev = prev.next;
}
prev.next = this.next;
}
this.next = null;
this.registered = false;
if (irqTable[irq] == null) {
Platform.DisableIoInterrupt(irq);
return true;
}
}
finally {
ReleaseLock(enabled);
}
return true;
}
public bool WaitForInterrupt()
{
DebugStub.Assert(this.registered);
if (signal != null) {
signal.InterruptAwareWaitOne();
return true;
}
return false;
}
public void Pulse()
{
signal.InterruptAwareSet();
}
public bool AckInterrupt()
{
#if DEBUG_DISPATCH_IO
DebugStub.WriteLine("++ AckInterrupt: Irq={0:x2}", __arglist(irq));
#endif
Platform.EnableIoInterrupt(irq);
return true;
}
public override string! ToString()
{
return String.Format("IRQ:{0,2:x2}", irq);
}
}
}