- 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:
Hermès Bélusca-Maïto
2015-08-13 17:11:17 +00:00
parent 3625edddc3
commit dbfe940f2d
4 changed files with 189 additions and 63 deletions
+36 -43
View File
@@ -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),
+10 -10
View File
@@ -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 ******************************************************************/