180 lines
5.0 KiB
C#
180 lines
5.0 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 AutoResetEvent! signal;
|
||
|
private IoIrq next;
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
//
|
||
|
private const int MaxInterrupts = 256;
|
||
|
private static IoIrq[]! registered;
|
||
|
private static SpinLock regLock;
|
||
|
|
||
|
static IoIrq()
|
||
|
{
|
||
|
registered = new IoIrq [MaxInterrupts];
|
||
|
regLock = new SpinLock();
|
||
|
}
|
||
|
|
||
|
[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 = registered[irq]; step != null; step = step.next) {
|
||
|
step.signal.Set();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public IoIrq(byte irq)
|
||
|
{
|
||
|
this.irq = irq;
|
||
|
this.next = null;
|
||
|
this.signal = new AutoResetEvent(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
|
||
|
|
||
|
next = registered[irq];
|
||
|
registered[irq] = this;
|
||
|
|
||
|
if (next == null) {
|
||
|
HalDevices.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 (registered[irq] == this) {
|
||
|
registered[irq] = this.next;
|
||
|
}
|
||
|
else {
|
||
|
IoIrq! prev = (!)registered[irq];
|
||
|
while (prev.next != this) {
|
||
|
prev = prev.next;
|
||
|
}
|
||
|
prev.next = this.next;
|
||
|
}
|
||
|
|
||
|
if (registered[irq] == null) {
|
||
|
HalDevices.DisableIoInterrupt(irq);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
finally {
|
||
|
ReleaseLock(enabled);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public bool WaitForInterrupt()
|
||
|
{
|
||
|
if (signal != null) {
|
||
|
return signal.WaitOne();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public bool WaitForInterrupt(TimeSpan timeout)
|
||
|
{
|
||
|
if (signal != null) {
|
||
|
return signal.WaitOne(timeout);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public void Pulse()
|
||
|
{
|
||
|
signal.Set();
|
||
|
}
|
||
|
|
||
|
public bool AckInterrupt()
|
||
|
{
|
||
|
#if DEBUG_DISPATCH_IO
|
||
|
DebugStub.WriteLine("++ AckInterrupt: Irq={0:x2}", __arglist(irq));
|
||
|
#endif
|
||
|
HalDevices.EnableIoInterrupt(irq);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override string! ToString()
|
||
|
{
|
||
|
return String.Format("IRQ:{0,2:x2}", irq);
|
||
|
}
|
||
|
}
|
||
|
}
|