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

183 lines
5.1 KiB
C#
Raw Normal View History

2008-03-05 09:52:00 -05:00
///////////////////////////////////////////////////////////////////////////////
//
// 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;
2008-11-17 18:29:00 -05:00
private InterruptAwareAutoResetEvent! signal;
2008-03-05 09:52:00 -05:00
private IoIrq next;
2008-11-17 18:29:00 -05:00
private bool registered;
2008-03-05 09:52:00 -05:00
//////////////////////////////////////////////////////////////////////
//
//
private const int MaxInterrupts = 256;
2008-11-17 18:29:00 -05:00
private static IoIrq[]! irqTable;
2008-03-05 09:52:00 -05:00
private static SpinLock regLock;
static IoIrq()
{
2008-11-17 18:29:00 -05:00
irqTable = new IoIrq [MaxInterrupts];
regLock = new SpinLock(SpinLock.Types.IoIrq);
2008-03-05 09:52:00 -05:00
}
[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
2008-11-17 18:29:00 -05:00
for (IoIrq step = irqTable[irq]; step != null; step = step.next) {
step.signal.InterruptAwareSet();
2008-03-05 09:52:00 -05:00
}
}
public IoIrq(byte irq)
{
this.irq = irq;
this.next = null;
2008-11-17 18:29:00 -05:00
this.signal = new InterruptAwareAutoResetEvent(false);
this.registered = false;
2008-03-05 09:52:00 -05:00
}
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
2008-11-17 18:29:00 -05:00
this.next = irqTable[irq];
irqTable[irq] = this;
this.registered = true;
2008-03-05 09:52:00 -05:00
if (next == null) {
2008-11-17 18:29:00 -05:00
Platform.EnableIoInterrupt(irq);
2008-03-05 09:52:00 -05:00
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 {
2008-11-17 18:29:00 -05:00
2008-03-05 09:52:00 -05:00
Tracing.Log(Tracing.Debug, "Release Irq={0:x2}", irq);
#if DEBUG_DISPATCH_IO
DebugStub.WriteLine("++ Release Irq={0:x2}", __arglist(irq));
#endif
2008-11-17 18:29:00 -05:00
if (irqTable[irq] == this) {
irqTable[irq] = this.next;
2008-03-05 09:52:00 -05:00
}
else {
2008-11-17 18:29:00 -05:00
IoIrq! prev = (!)irqTable[irq];
2008-03-05 09:52:00 -05:00
while (prev.next != this) {
prev = prev.next;
}
prev.next = this.next;
}
2008-11-17 18:29:00 -05:00
this.next = null;
this.registered = false;
if (irqTable[irq] == null) {
Platform.DisableIoInterrupt(irq);
2008-03-05 09:52:00 -05:00
return true;
}
}
finally {
ReleaseLock(enabled);
}
return true;
}
public bool WaitForInterrupt()
{
2008-11-17 18:29:00 -05:00
DebugStub.Assert(this.registered);
2008-03-05 09:52:00 -05:00
if (signal != null) {
2008-11-17 18:29:00 -05:00
signal.InterruptAwareWaitOne();
return true;
2008-03-05 09:52:00 -05:00
}
return false;
}
public void Pulse()
{
2008-11-17 18:29:00 -05:00
signal.InterruptAwareSet();
2008-03-05 09:52:00 -05:00
}
public bool AckInterrupt()
{
#if DEBUG_DISPATCH_IO
DebugStub.WriteLine("++ AckInterrupt: Irq={0:x2}", __arglist(irq));
#endif
2008-11-17 18:29:00 -05:00
Platform.EnableIoInterrupt(irq);
2008-03-05 09:52:00 -05:00
return true;
}
public override string! ToString()
{
return String.Format("IRQ:{0,2:x2}", irq);
}
}
}