207 lines
6.1 KiB
C#
207 lines
6.1 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: Register.cs
|
||
|
//
|
||
|
// Note: PnP Device Type Registration and Base Initialization.
|
||
|
//
|
||
|
|
||
|
using Microsoft.Singularity;
|
||
|
using Microsoft.Singularity.Io;
|
||
|
using System;
|
||
|
using System.Threading;
|
||
|
using System.Diagnostics;
|
||
|
|
||
|
namespace Microsoft.Singularity.Intel8255x
|
||
|
{
|
||
|
public class Factory {
|
||
|
public static IDevice! DeviceCreate(IoConfig! config, String! instanceName)
|
||
|
{
|
||
|
return new Driver((PciDeviceConfig)config);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal enum SCBStatAck : byte {
|
||
|
CX = 1 << 7,
|
||
|
FR = 1 << 6,
|
||
|
CNA = 1 << 5,
|
||
|
RNR = 1 << 4,
|
||
|
MDI = 1 << 3,
|
||
|
SWI = 1 << 2,
|
||
|
ER = 1 << 1,
|
||
|
FCP = 1 << 0
|
||
|
}
|
||
|
|
||
|
internal enum SCBStatus : byte {
|
||
|
RUS = 0x3 << 6,
|
||
|
CUS = 0xf << 2
|
||
|
}
|
||
|
|
||
|
internal enum SCBCommand : ushort {
|
||
|
CX = 1 << 15,
|
||
|
FR = 1 << 14,
|
||
|
CNA = 1 << 13,
|
||
|
RNR = 1 << 12,
|
||
|
ER = 1 << 11,
|
||
|
FCP = 1 << 10,
|
||
|
SI = 1 << 9,
|
||
|
M = 1 << 8,
|
||
|
CUC = 0xf << 4,
|
||
|
RUC = 0x7
|
||
|
}
|
||
|
|
||
|
public class Driver : IDevice {
|
||
|
public static IDevice! DeviceCreate(IoConfig! config)
|
||
|
{
|
||
|
return new Driver((PciDeviceConfig)config);
|
||
|
}
|
||
|
|
||
|
private PciDeviceConfig config;
|
||
|
|
||
|
private IoMemoryRange eepromBase;
|
||
|
private IoMemory eepromMemory;
|
||
|
|
||
|
private IReadWriteRegister16 scbCommand;
|
||
|
private IReadOnlyRegister8 scbStatus;
|
||
|
private IReadWriteRegister8 scbStatAck;
|
||
|
|
||
|
private IoIrq irq;
|
||
|
private Thread irqWorker;
|
||
|
private bool irqWorkerStop = false;
|
||
|
private Thread irqMaker;
|
||
|
private bool irqMakerStop = false;
|
||
|
|
||
|
internal Driver(PciDeviceConfig config)
|
||
|
{
|
||
|
this.config = config;
|
||
|
}
|
||
|
|
||
|
private void DebugPrint(string format, __arglist)
|
||
|
{
|
||
|
DebugStub.Print(format, __arglist);
|
||
|
}
|
||
|
|
||
|
private void InitializeMemoryRegisters()
|
||
|
{
|
||
|
IoMemoryRange range = (IoMemoryRange)config.Ranges[0];
|
||
|
scbStatus = ReadOnlyMemoryRegister8.Create(range, 0);
|
||
|
scbStatAck = ReadWriteMemoryRegister8.Create(range, 1);
|
||
|
scbCommand = ReadWriteMemoryRegister16.Create(range, 2);
|
||
|
}
|
||
|
|
||
|
private void InitializeIoPortRegisters()
|
||
|
{
|
||
|
IoPortRange range = (IoPortRange)config.Ranges[1];
|
||
|
scbStatus = ReadOnlyPortRegister8.Create(range, 0);
|
||
|
scbStatAck = ReadWritePortRegister8.Create(range, 1);
|
||
|
scbCommand = ReadWritePortRegister16.Create(range, 2);
|
||
|
}
|
||
|
|
||
|
public void Initialize()
|
||
|
{
|
||
|
if (config.MemorySpaceEnabled) {
|
||
|
InitializeMemoryRegisters();
|
||
|
} else {
|
||
|
Debug.Assert(config.IoSpaceEnabled == true);
|
||
|
InitializeIoPortRegisters();
|
||
|
}
|
||
|
|
||
|
eepromBase = (IoMemoryRange)config.Ranges[2];
|
||
|
eepromMemory = eepromBase.MemoryAtOffset(0, 65536, Access.Read);
|
||
|
|
||
|
DebugPrint("RevisionId {0} SCB Status 0x{1:x2} " +
|
||
|
"Command 0x{2:x4}\n",
|
||
|
__arglist(config.RevisionId,
|
||
|
(byte)GetScbStatus(), (ushort)GetScbCommand()));
|
||
|
|
||
|
irq = config.GetIrq().IrqAtOffset(0);
|
||
|
irq.RegisterInterrupt();
|
||
|
irqWorker = new Thread(new ThreadStart(this.IrqWorkerMain),
|
||
|
new Scheduler.Activity()
|
||
|
);
|
||
|
irqWorker.Start();
|
||
|
irqWorker.Name = String.Format("i8255x I/O {0} ({0})",
|
||
|
config.ToString());
|
||
|
|
||
|
irqMaker = new Thread(new ThreadStart(this.IrqMakerMain),
|
||
|
new Scheduler.Activity()
|
||
|
);
|
||
|
irqMaker.Start();
|
||
|
}
|
||
|
|
||
|
public void Finalize()
|
||
|
{
|
||
|
irqWorkerStop = true;
|
||
|
irqMakerStop = true;
|
||
|
irq.ReleaseInterrupt();
|
||
|
|
||
|
#if CAN_JOIN
|
||
|
if (irqMaker != null) {
|
||
|
irqMaker.Join();
|
||
|
irqMaker = null;
|
||
|
}
|
||
|
if (irqWorker != null) {
|
||
|
irqWorker.Join();
|
||
|
irqWorker = null;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
private SCBStatus GetScbStatus()
|
||
|
{
|
||
|
return (SCBStatus)scbStatus.Read();
|
||
|
}
|
||
|
|
||
|
private SCBStatAck GetScbStatAck()
|
||
|
{
|
||
|
return (SCBStatAck)scbStatAck.Read();
|
||
|
}
|
||
|
|
||
|
private void SetScbStatAck(SCBStatAck value)
|
||
|
{
|
||
|
scbStatAck.Write((byte)value);
|
||
|
}
|
||
|
|
||
|
private SCBCommand GetScbCommand()
|
||
|
{
|
||
|
return (SCBCommand)scbCommand.Read();
|
||
|
}
|
||
|
|
||
|
private void SetScbCommand(SCBCommand value)
|
||
|
{
|
||
|
scbCommand.Write((ushort)value);
|
||
|
}
|
||
|
|
||
|
private void IrqMakerMain()
|
||
|
{
|
||
|
for (;;) {
|
||
|
Thread.Sleep(1000);
|
||
|
// Trigger Software Interrupt
|
||
|
scbCommand.Write((ushort)SCBCommand.SI);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void IrqWorkerMain()
|
||
|
{
|
||
|
Tracing.Log(Tracing.Audit, "Start of worker thread.");
|
||
|
uint iters = 0;
|
||
|
for (;;) {
|
||
|
irq.WaitForInterrupt();
|
||
|
DebugPrint("+ IrqWorkerMain iteration {0}\n", __arglist(iters));
|
||
|
|
||
|
SCBStatAck s = GetScbStatAck();
|
||
|
DebugPrint("Clearing Interupt : StatAck 0x{0:x4}\n",
|
||
|
__arglist((ushort)s));
|
||
|
SetScbStatAck(s); // Write bits back to clear
|
||
|
scbCommand.Write(0);
|
||
|
irq.AckInterrupt();
|
||
|
|
||
|
DebugPrint("- IrqWorkerMain iteration {0}\n", __arglist(iters));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|