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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|