mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-29 19:26:33 +00:00
[NTVDM]
- When we have few R/W IO port handlers, just register them directly instead of using a wrap-up function. - Start implementing the PS/2 keyboard command handler. - Report scancodes only if the keyboard is enabled. See r68415. CORE-9920 svn path=/trunk/; revision=68708
This commit is contained in:
@@ -46,6 +46,7 @@ static VOID RtcUpdatePeriodicTimer(VOID)
|
||||
if (RateSelect <= 2) RateSelect += 7;
|
||||
|
||||
SetHardwareTimerDelay(PeriodicTimer, HZ_TO_NS(1 << (16 - RateSelect)));
|
||||
// FIXME: This call keeps EnableCount increasing without compensating it!
|
||||
EnableHardwareTimer(PeriodicTimer);
|
||||
}
|
||||
|
||||
@@ -101,18 +102,20 @@ static VOID FASTCALL RtcTimeUpdate(ULONGLONG ElapsedTime)
|
||||
}
|
||||
}
|
||||
|
||||
static VOID CmosWriteAddress(BYTE Value)
|
||||
static VOID WINAPI CmosWriteAddress(USHORT Port, BYTE Data)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Port);
|
||||
|
||||
/* Update the NMI enabled flag */
|
||||
NmiEnabled = !(Value & CMOS_DISABLE_NMI);
|
||||
NmiEnabled = !(Data & CMOS_DISABLE_NMI);
|
||||
|
||||
/* Get the register number */
|
||||
Value &= ~CMOS_DISABLE_NMI;
|
||||
Data &= ~CMOS_DISABLE_NMI;
|
||||
|
||||
if (Value < CMOS_REG_MAX)
|
||||
if (Data < CMOS_REG_MAX)
|
||||
{
|
||||
/* Select the new register */
|
||||
SelectedRegister = Value;
|
||||
SelectedRegister = Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -121,11 +124,13 @@ static VOID CmosWriteAddress(BYTE Value)
|
||||
}
|
||||
}
|
||||
|
||||
static BYTE CmosReadData(VOID)
|
||||
static BYTE WINAPI CmosReadData(USHORT Port)
|
||||
{
|
||||
BYTE Value;
|
||||
SYSTEMTIME CurrentTime;
|
||||
|
||||
UNREFERENCED_PARAMETER(Port);
|
||||
|
||||
/* Get the current time */
|
||||
GetLocalTime(&CurrentTime);
|
||||
|
||||
@@ -257,11 +262,13 @@ static BYTE CmosReadData(VOID)
|
||||
return Value;
|
||||
}
|
||||
|
||||
static VOID CmosWriteData(BYTE Value)
|
||||
static VOID WINAPI CmosWriteData(USHORT Port, BYTE Data)
|
||||
{
|
||||
BOOLEAN ChangeTime = FALSE;
|
||||
SYSTEMTIME CurrentTime;
|
||||
|
||||
UNREFERENCED_PARAMETER(Port);
|
||||
|
||||
/* Get the current time */
|
||||
GetLocalTime(&CurrentTime);
|
||||
|
||||
@@ -270,26 +277,26 @@ static VOID CmosWriteData(BYTE Value)
|
||||
case CMOS_REG_SECONDS:
|
||||
{
|
||||
ChangeTime = TRUE;
|
||||
CurrentTime.wSecond = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
CurrentTime.wSecond = WRITE_CMOS_DATA(CmosMemory, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_ALARM_SEC:
|
||||
{
|
||||
CmosMemory.AlarmSecond = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
CmosMemory.AlarmSecond = WRITE_CMOS_DATA(CmosMemory, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_MINUTES:
|
||||
{
|
||||
ChangeTime = TRUE;
|
||||
CurrentTime.wMinute = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
CurrentTime.wMinute = WRITE_CMOS_DATA(CmosMemory, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_ALARM_MIN:
|
||||
{
|
||||
CmosMemory.AlarmMinute = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
CmosMemory.AlarmMinute = WRITE_CMOS_DATA(CmosMemory, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -299,13 +306,13 @@ static VOID CmosWriteData(BYTE Value)
|
||||
|
||||
ChangeTime = TRUE;
|
||||
|
||||
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value & 0x80))
|
||||
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Data & 0x80))
|
||||
{
|
||||
Value &= ~0x80;
|
||||
Data &= ~0x80;
|
||||
Afternoon = TRUE;
|
||||
}
|
||||
|
||||
CurrentTime.wHour = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
CurrentTime.wHour = WRITE_CMOS_DATA(CmosMemory, Data);
|
||||
|
||||
/* Convert to 24-hour format */
|
||||
if (Afternoon) CurrentTime.wHour += 12;
|
||||
@@ -317,13 +324,13 @@ static VOID CmosWriteData(BYTE Value)
|
||||
{
|
||||
BOOLEAN Afternoon = FALSE;
|
||||
|
||||
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Value & 0x80))
|
||||
if (!(CmosMemory.StatusRegB & CMOS_STB_24HOUR) && (Data & 0x80))
|
||||
{
|
||||
Value &= ~0x80;
|
||||
Data &= ~0x80;
|
||||
Afternoon = TRUE;
|
||||
}
|
||||
|
||||
CmosMemory.AlarmHour = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
CmosMemory.AlarmHour = WRITE_CMOS_DATA(CmosMemory, Data);
|
||||
|
||||
/* Convert to 24-hour format */
|
||||
if (Afternoon) CmosMemory.AlarmHour += 12;
|
||||
@@ -339,22 +346,22 @@ static VOID CmosWriteData(BYTE Value)
|
||||
* SetLocalTime API value is 0-based.
|
||||
* Correct it.
|
||||
*/
|
||||
Value -= 1;
|
||||
CurrentTime.wDayOfWeek = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
Data -= 1;
|
||||
CurrentTime.wDayOfWeek = WRITE_CMOS_DATA(CmosMemory, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_DAY:
|
||||
{
|
||||
ChangeTime = TRUE;
|
||||
CurrentTime.wDay = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
CurrentTime.wDay = WRITE_CMOS_DATA(CmosMemory, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_MONTH:
|
||||
{
|
||||
ChangeTime = TRUE;
|
||||
CurrentTime.wMonth = WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
CurrentTime.wMonth = WRITE_CMOS_DATA(CmosMemory, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -365,7 +372,7 @@ static VOID CmosWriteData(BYTE Value)
|
||||
/* Clear everything except the century */
|
||||
CurrentTime.wYear = (CurrentTime.wYear / 100) * 100;
|
||||
|
||||
CurrentTime.wYear += WRITE_CMOS_DATA(CmosMemory, Value);
|
||||
CurrentTime.wYear += WRITE_CMOS_DATA(CmosMemory, Data);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -377,14 +384,14 @@ static VOID CmosWriteData(BYTE Value)
|
||||
|
||||
case CMOS_REG_STATUS_A:
|
||||
{
|
||||
CmosMemory.StatusRegA = Value & 0x7F; // Bit 7 is read-only
|
||||
CmosMemory.StatusRegA = Data & 0x7F; // Bit 7 is read-only
|
||||
RtcUpdatePeriodicTimer();
|
||||
break;
|
||||
}
|
||||
|
||||
case CMOS_REG_STATUS_B:
|
||||
{
|
||||
CmosMemory.StatusRegB = Value;
|
||||
CmosMemory.StatusRegB = Data;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -399,7 +406,7 @@ static VOID CmosWriteData(BYTE Value)
|
||||
{
|
||||
/* Sync EMS and UMS */
|
||||
CmosMemory.Regs[CMOS_REG_EXT_MEMORY_LOW] =
|
||||
CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_LOW] = Value;
|
||||
CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_LOW] = Data;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -409,13 +416,13 @@ static VOID CmosWriteData(BYTE Value)
|
||||
{
|
||||
/* Sync EMS and UMS */
|
||||
CmosMemory.Regs[CMOS_REG_EXT_MEMORY_HIGH] =
|
||||
CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_HIGH] = Value;
|
||||
CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_HIGH] = Data;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
CmosMemory.Regs[SelectedRegister] = Value;
|
||||
CmosMemory.Regs[SelectedRegister] = Data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,20 +432,6 @@ static VOID CmosWriteData(BYTE Value)
|
||||
SelectedRegister = CMOS_REG_STATUS_D;
|
||||
}
|
||||
|
||||
static BYTE WINAPI CmosReadPort(USHORT Port)
|
||||
{
|
||||
ASSERT(Port == CMOS_DATA_PORT);
|
||||
return CmosReadData();
|
||||
}
|
||||
|
||||
static VOID WINAPI CmosWritePort(USHORT Port, BYTE Data)
|
||||
{
|
||||
if (Port == CMOS_ADDRESS_PORT)
|
||||
CmosWriteAddress(Data);
|
||||
else if (Port == CMOS_DATA_PORT)
|
||||
CmosWriteData(Data);
|
||||
}
|
||||
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
@@ -511,8 +504,8 @@ VOID CmosInitialize(VOID)
|
||||
CmosMemory.Regs[CMOS_REG_ACTUAL_EXT_MEMORY_HIGH] = HIBYTE((MAX_ADDRESS - 0x100000) / 1024);
|
||||
|
||||
/* Register the I/O Ports */
|
||||
RegisterIoPort(CMOS_ADDRESS_PORT, NULL , CmosWritePort);
|
||||
RegisterIoPort(CMOS_DATA_PORT , CmosReadPort, CmosWritePort);
|
||||
RegisterIoPort(CMOS_ADDRESS_PORT, NULL, CmosWriteAddress);
|
||||
RegisterIoPort(CMOS_DATA_PORT , CmosReadData, CmosWriteData );
|
||||
|
||||
ClockTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED,
|
||||
HZ_TO_NS(1),
|
||||
|
||||
@@ -559,12 +559,12 @@ VOID DmaInitialize(VOID)
|
||||
RegisterIoPort(0x07, DmaReadPort, DmaWritePort); /* Current(R) / Base (W) Count Register 3 */
|
||||
|
||||
RegisterIoPort(0x08, DmaReadPort, DmaWritePort); /* Status (Read) / Command (Write) Registers */
|
||||
RegisterIoPort(0x09, NULL, DmaWritePort); /* Request Register */
|
||||
RegisterIoPort(0x0A, NULL, DmaWritePort); /* Single Channel Mask Register */
|
||||
RegisterIoPort(0x0B, NULL, DmaWritePort); /* Mode Register */
|
||||
RegisterIoPort(0x0C, NULL, DmaWritePort); /* Flip-Flop Reset Register */
|
||||
RegisterIoPort(0x09, NULL, DmaWritePort); /* Request Register */
|
||||
RegisterIoPort(0x0A, NULL, DmaWritePort); /* Single Channel Mask Register */
|
||||
RegisterIoPort(0x0B, NULL, DmaWritePort); /* Mode Register */
|
||||
RegisterIoPort(0x0C, NULL, DmaWritePort); /* Flip-Flop Reset Register */
|
||||
RegisterIoPort(0x0D, DmaReadPort, DmaWritePort); /* Intermediate (Read) / Master Reset (Write) Registers */
|
||||
RegisterIoPort(0x0E, NULL, DmaWritePort); /* Mask Reset Register */
|
||||
RegisterIoPort(0x0E, NULL, DmaWritePort); /* Mask Reset Register */
|
||||
RegisterIoPort(0x0F, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Register */
|
||||
|
||||
|
||||
@@ -579,12 +579,12 @@ VOID DmaInitialize(VOID)
|
||||
RegisterIoPort(0xCE, DmaReadPort, DmaWritePort); /* Current(R) / Base (W) Count Register 7 */
|
||||
|
||||
RegisterIoPort(0xD0, DmaReadPort, DmaWritePort); /* Status (Read) / Command (Write) Registers */
|
||||
RegisterIoPort(0xD2, NULL, DmaWritePort); /* Request Register */
|
||||
RegisterIoPort(0xD4, NULL, DmaWritePort); /* Single Channel Mask Register */
|
||||
RegisterIoPort(0xD6, NULL, DmaWritePort); /* Mode Register */
|
||||
RegisterIoPort(0xD8, NULL, DmaWritePort); /* Flip-Flop Reset Register */
|
||||
RegisterIoPort(0xD2, NULL, DmaWritePort); /* Request Register */
|
||||
RegisterIoPort(0xD4, NULL, DmaWritePort); /* Single Channel Mask Register */
|
||||
RegisterIoPort(0xD6, NULL, DmaWritePort); /* Mode Register */
|
||||
RegisterIoPort(0xD8, NULL, DmaWritePort); /* Flip-Flop Reset Register */
|
||||
RegisterIoPort(0xDA, DmaReadPort, DmaWritePort); /* Intermediate (Read) / Master Reset (Write) Registers */
|
||||
RegisterIoPort(0xDC, NULL, DmaWritePort); /* Mask Reset Register */
|
||||
RegisterIoPort(0xDC, NULL, DmaWritePort); /* Mask Reset Register */
|
||||
RegisterIoPort(0xDE, DmaReadPort, DmaWritePort); /* Multi-Channel Mask Register */
|
||||
|
||||
|
||||
|
||||
@@ -16,19 +16,148 @@
|
||||
|
||||
/* PRIVATE VARIABLES **********************************************************/
|
||||
|
||||
static BOOLEAN Reporting = FALSE;
|
||||
static BYTE KeyboardId = 0; // We only support basic old-type keyboard
|
||||
static BYTE DataByteWait = 0;
|
||||
|
||||
static BYTE PS2Port = 0;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static VOID WINAPI KeyboardCommand(LPVOID Param, BYTE Command)
|
||||
{
|
||||
// FIXME: UNIMPLEMENTED; just return ACKnowledge.
|
||||
// This unblocks some programs that want to initialize
|
||||
// the keyboard by sending keyboard commands and then
|
||||
// performing polling on the port until "valid" data
|
||||
// comes out.
|
||||
DPRINT1("KeyboardCommand(0x%02X) NOT IMPLEMENTED\n", Command);
|
||||
PS2QueuePush(PS2Port, 0xFA);
|
||||
/* Check if we were waiting for a data byte */
|
||||
if (DataByteWait)
|
||||
{
|
||||
PS2QueuePush(PS2Port, KEYBOARD_ACK);
|
||||
|
||||
switch (DataByteWait)
|
||||
{
|
||||
/* Set/Reset Mode Indicators */
|
||||
case 0xED:
|
||||
{
|
||||
// Ignore setting the keyboard LEDs
|
||||
break;
|
||||
}
|
||||
|
||||
/* PS/2 Select/Read Alternate Scan Code Sets */
|
||||
case 0xF0:
|
||||
/* Set Typematic Rate/Delay */
|
||||
case 0xF3:
|
||||
{
|
||||
// FIXME: UNIMPLEMENTED; just return ACKnowledge.
|
||||
// This unblocks some programs that want to initialize
|
||||
// the keyboard by sending keyboard commands and then
|
||||
// performing polling on the port until "valid" data
|
||||
// comes out.
|
||||
DPRINT1("KeyboardCommand(0x%02X) NOT IMPLEMENTED\n", DataByteWait);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
DataByteWait = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
/* Set/Reset Mode Indicators */
|
||||
case 0xED:
|
||||
/* PS/2 Select/Read Alternate Scan Code Sets */
|
||||
case 0xF0:
|
||||
/* Set Typematic Rate/Delay */
|
||||
case 0xF3:
|
||||
{
|
||||
DataByteWait = Command;
|
||||
PS2QueuePush(PS2Port, KEYBOARD_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Echo test command */
|
||||
case 0xEE:
|
||||
{
|
||||
PS2QueuePush(PS2Port, 0xEE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get Keyboard ID */
|
||||
case 0xF2:
|
||||
{
|
||||
PS2QueuePush(PS2Port, KEYBOARD_ACK);
|
||||
PS2QueuePush(PS2Port, KeyboardId);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable Reporting */
|
||||
case 0xF4:
|
||||
{
|
||||
Reporting = TRUE;
|
||||
PS2QueuePush(PS2Port, KEYBOARD_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable Reporting */
|
||||
case 0xF5:
|
||||
{
|
||||
Reporting = FALSE;
|
||||
PS2QueuePush(PS2Port, KEYBOARD_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set Defaults */
|
||||
case 0xF6:
|
||||
{
|
||||
// So far, nothing to reset
|
||||
PS2QueuePush(PS2Port, KEYBOARD_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
/* PS/2 Typematic & Make/Break key modes */
|
||||
case 0xF7: case 0xF8: case 0xF9:
|
||||
case 0xFA: case 0xFB: case 0xFC: case 0xFD:
|
||||
{
|
||||
/*
|
||||
* Unsupported on PC-AT, they are just ignored
|
||||
* and acknowledged as discussed in:
|
||||
* http://stanislavs.org/helppc/keyboard_commands.html
|
||||
*/
|
||||
PS2QueuePush(PS2Port, KEYBOARD_ACK);
|
||||
}
|
||||
|
||||
/* Resend */
|
||||
case 0xFE:
|
||||
{
|
||||
PS2QueuePush(PS2Port, KEYBOARD_ACK);
|
||||
UNIMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Reset */
|
||||
case 0xFF:
|
||||
{
|
||||
/* Send ACKnowledge */
|
||||
PS2QueuePush(PS2Port, KEYBOARD_ACK);
|
||||
|
||||
// So far, nothing to reset
|
||||
|
||||
/* Send the Basic Assurance Test success code and the device ID */
|
||||
PS2QueuePush(PS2Port, KEYBOARD_BAT_SUCCESS);
|
||||
PS2QueuePush(PS2Port, KeyboardId);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unknown command */
|
||||
default:
|
||||
{
|
||||
PS2QueuePush(PS2Port, KEYBOARD_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
@@ -38,6 +167,9 @@ VOID KeyboardEventHandler(PKEY_EVENT_RECORD KeyEvent)
|
||||
WORD i;
|
||||
BYTE ScanCode = (BYTE)KeyEvent->wVirtualScanCode;
|
||||
|
||||
/* Check if we're not reporting */
|
||||
if (!Reporting) return;
|
||||
|
||||
/* If this is a key release, set the highest bit in the scan code */
|
||||
if (!KeyEvent->bKeyDown) ScanCode |= 0x80;
|
||||
|
||||
@@ -56,6 +188,5 @@ BOOLEAN KeyboardInit(BYTE PS2Connector)
|
||||
/* Finish to plug the keyboard to the specified PS/2 port */
|
||||
PS2Port = PS2Connector;
|
||||
PS2SetDeviceCmdProc(PS2Port, NULL, KeyboardCommand);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
/* Command responses */
|
||||
#define KEYBOARD_ACK 0xFA
|
||||
#define KEYBOARD_RESEND 0xFE
|
||||
#define KEYBOARD_BAT_SUCCESS 0xAA
|
||||
#define KEYBOARD_ACK 0xFA
|
||||
#define KEYBOARD_ERROR 0xFC
|
||||
#define KEYBOARD_RESEND 0xFE
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user