//#define COSMOSDEBUG
using System;
using Cosmos.Core;
using Cosmos.Debug.Kernel;
namespace Cosmos.HAL
{
///
/// This class describes the PS/2 keyboard.
///
public class PS2Keyboard : KeyboardBase
{
enum Command : byte
{
SetLEDs = 0xED,
GetOrSetScanCodeSet = 0xF0,
EnableScanning = 0xF4,
DisableScanning = 0xF5,
Reset = 0xFF
}
public byte PS2Port { get; }
private Core.IOGroup.PS2Controller IO = Core.Global.BaseIOGroups.PS2Controller;
private PS2Controller mPS2Controller = Global.PS2Controller;
private Debugger mDebugger = new Debugger("HAL", "PS2Keyboard");
internal PS2Keyboard(byte aPort)
{
PS2Port = aPort;
}
public override void Initialize()
{
SendCommand(Command.Reset);
mPS2Controller.WaitForDeviceReset();
//VMWare doesn't support the Get/SetScanCode command
//mDebugger.SendInternal("(PS/2 Keyboard) Current scan code set: " + GetScanCodeSet());
//SetScanCodeSet(1);
//mDebugger.SendInternal("(PS/2 Keyboard) Current scan code set: " + GetScanCodeSet());
INTs.SetIrqHandler(1, HandleIRQ);
SendCommand(Command.EnableScanning);
Global.mDebugger.SendInternal("(PS/2 Keyboard) Initialized");
UpdateLeds();
Global.mDebugger.SendInternal("(PS/2 Keyboard) Leds updated");
}
private void HandleIRQ(ref INTs.IRQContext aContext)
{
byte xScanCode = IO.Data.Byte;
bool xReleased = (xScanCode & 0x80) == 0x80;
if (xReleased)
{
xScanCode = (byte)(xScanCode ^ 0x80);
}
OnKeyPressed?.Invoke(xScanCode, xReleased);
}
public override void UpdateLeds()
{
// for now, lets not do this..
//IO.Port60.Byte = 0xED;
//while ((new IOPort(0x64).Byte & 2) != 0)
//{
//}
//var led_status = (Global.ScrollLock ? 1 : 0) | ((Global.NumLock ? 1 : 0) << 1) | ((Global.CapsLock ? 1 : 0) << 2);
//IO.Port60.Byte = (byte)led_status;
//while ((new IOPort(0x64).Byte & 2) != 0)
//{
//}
// Updated Code (not tested):
//var xLEDs = (byte)(Global.ScrollLock ? 1 : 0) | ((Global.NumLock ? 1 : 0) << 1) | ((Global.CapsLock ? 1 : 0) << 2);
//SendCommand(Command.SetLEDs, xLEDs);
}
///
/// Gets the current keyboard scan code set.
///
/// Returns the current scan code set.
private byte GetScanCodeSet()
{
SendCommand(Command.GetOrSetScanCodeSet, 0);
return mPS2Controller.ReadByteAfterAck();
}
///
/// Sets the scan code set.
///
/// The scan code set to set. Can be 1, 2 or 3.
private void SetScanCodeSet(byte aScanCodeSet)
{
if (aScanCodeSet == 1 || aScanCodeSet == 2 || aScanCodeSet == 3)
{
SendCommand(Command.GetOrSetScanCodeSet, aScanCodeSet);
}
else
{
throw new Exception("(PS/2 Keyboard) Scan code set '" + aScanCodeSet + "' doesn't exist");
}
}
private void SendCommand(Command aCommand, byte? aByte = null)
{
mDebugger.SendInternal("(PS/2 Keyboard) Sending command:");
mDebugger.SendInternal("Command:");
mDebugger.SendInternal((byte)aCommand);
if (PS2Port == 2)
{
mPS2Controller.PrepareSecondPortWrite();
}
mPS2Controller.WaitToWrite();
IO.Data.Byte = (byte)aCommand;
mPS2Controller.WaitForAck();
mDebugger.SendInternal("Command sent.");
if (aByte.HasValue)
{
mDebugger.SendInternal("(PS/2 Keyboard) Sending byte after command:");
mDebugger.SendInternal("Byte value:");
mDebugger.SendInternal(aByte.Value);
if (PS2Port == 2)
{
mPS2Controller.PrepareSecondPortWrite();
}
mPS2Controller.WaitToWrite();
IO.Data.Byte = aByte.Value;
mPS2Controller.WaitForAck();
}
}
}
}