415 lines
7.0 KiB
C
415 lines
7.0 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
Copyright (c) 1993 Digital Equipment Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Kbdtest.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the Keyboard and mouse test for the self-test.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Lluis Abello (lluis) 10-Feb-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Rom self-test.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
10-July-1992 John DeRosa [DEC]
|
|||
|
|
|||
|
Added Alpha/Jensen modifications.
|
|||
|
|
|||
|
--*/
|
|||
|
#include <ntos.h>
|
|||
|
#include "iodevice.h"
|
|||
|
#include "kbdmouse.h"
|
|||
|
|
|||
|
#ifdef JENSEN
|
|||
|
#include "jnsnprom.h"
|
|||
|
#include "jnsnrtc.h"
|
|||
|
#else
|
|||
|
#include "mrgnrtc.h" // morgan
|
|||
|
#endif
|
|||
|
|
|||
|
volatile ULONG TimerTicks;
|
|||
|
|
|||
|
//
|
|||
|
// If the user accidentally types on the keyboard or moves the mouse
|
|||
|
// during the power-up tests, there will be a failure. So, this code
|
|||
|
// retries an initialization of the keyboard controller and keyboard
|
|||
|
// this many times before giving up.
|
|||
|
//
|
|||
|
|
|||
|
#define MAXIMUM_KEYBOARD_MOUSE_RETRY_COUNT 20
|
|||
|
|
|||
|
//
|
|||
|
// function prototypes
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
FwpWriteIOChip(
|
|||
|
ULONG ComboInternalAddress,
|
|||
|
UCHAR ComboRegisterAddress
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
ClearKbdFifo(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine empties the Keyboard controller Fifo.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR Trash, Stat;
|
|||
|
volatile Timeout;
|
|||
|
|
|||
|
//
|
|||
|
// wait until the previous command is processed.
|
|||
|
//
|
|||
|
|
|||
|
while ((READ_PORT_UCHAR((PUCHAR)&KEYBOARD_READ->Status) & KBD_IBF_MASK) != 0) {
|
|||
|
}
|
|||
|
while ((READ_PORT_UCHAR((PUCHAR)&KEYBOARD_READ->Status) & KBD_OBF_MASK) != 0) {
|
|||
|
Trash= READ_PORT_UCHAR((PUCHAR)&KEYBOARD_READ->Data);
|
|||
|
for (Timeout=0;Timeout<10000;Timeout++) {
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
GetKbdData(
|
|||
|
PUCHAR C,
|
|||
|
ULONG msec
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine polls the Status Register until Data is available or timeout,
|
|||
|
then it reads and returns the Data.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
C - pointer to a byte where to write the read value
|
|||
|
msec - time-out time in milliseconds
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if timeout, FALSE if OK;
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
//
|
|||
|
// HACKHACK: This should be made smarter. For now it assumes
|
|||
|
// 90,000,000 instruction per second and 12 instructions per iteration.
|
|||
|
//
|
|||
|
|
|||
|
TimerTicks = msec * 1000 * 90 / 12;
|
|||
|
|
|||
|
while (TimerTicks--) {
|
|||
|
if (READ_PORT_UCHAR((PUCHAR)&KEYBOARD_READ->Status) & KBD_OBF_MASK) {
|
|||
|
*C = READ_PORT_UCHAR((PUCHAR)&KEYBOARD_READ->Data);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
SendKbdData(
|
|||
|
IN UCHAR Data
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine polls the Status Register until the controller is ready to
|
|||
|
accept a data or timeout, then it send the Data.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if timeout, FALSE if OK;
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
|
|||
|
for (i=0; i <KBD_TIMEOUT; i++) {
|
|||
|
if ((READ_PORT_UCHAR((PUCHAR)&KEYBOARD_READ->Status) & KBD_IBF_MASK) == 0) {
|
|||
|
WRITE_PORT_UCHAR((PUCHAR)&KEYBOARD_WRITE->Data,Data);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
SendKbdCommand(
|
|||
|
IN UCHAR Command
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine polls the Status Register until the controller is ready to
|
|||
|
accept a command or timeout, then it send the Command.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if timeout, FALSE if OK;
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
|
|||
|
for (i=0; i <KBD_TIMEOUT; i++) {
|
|||
|
if ((READ_PORT_UCHAR((PUCHAR)&KEYBOARD_READ->Status) & KBD_IBF_MASK) == 0) {
|
|||
|
WRITE_PORT_UCHAR((PUCHAR)&KEYBOARD_WRITE->Command,Command);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
InitKeyboard(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine enables and initializes the keyboard. It assumes a
|
|||
|
101-key keyboard. It leaves the keyboard in XT mode (scan code = 01).
|
|||
|
|
|||
|
To account for the user accidentally typing on the keyboard, this
|
|||
|
routine repeats the test a few times before giving up.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE if passed,
|
|||
|
|
|||
|
TRUE if bad ACK or BAT received, or if no response is received from
|
|||
|
the keyboard.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR Result;
|
|||
|
ULONG i;
|
|||
|
ULONG Index;
|
|||
|
BOOLEAN TestPassed;
|
|||
|
|
|||
|
TestPassed = FALSE;
|
|||
|
|
|||
|
for (Index = 0; Index < MAXIMUM_KEYBOARD_MOUSE_RETRY_COUNT; Index++) {
|
|||
|
|
|||
|
//
|
|||
|
// Send Reset to Keyboard.
|
|||
|
//
|
|||
|
|
|||
|
ClearKbdFifo();
|
|||
|
for (;;) {
|
|||
|
if (SendKbdData(KbdReset)) {
|
|||
|
goto LoopAgain;
|
|||
|
}
|
|||
|
if (GetKbdData(&Result,1000)) {
|
|||
|
goto LoopAgain;
|
|||
|
}
|
|||
|
if (Result == KbdResend) {
|
|||
|
if (GetKbdData(&Result,1000)) {
|
|||
|
goto LoopAgain;
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (Result != KbdAck) {
|
|||
|
goto LoopAgain;
|
|||
|
}
|
|||
|
if (GetKbdData(&Result,7000)) {
|
|||
|
goto LoopAgain;
|
|||
|
}
|
|||
|
if (Result != KbdBat) {
|
|||
|
goto LoopAgain;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Enable Kbd and Select keyboard Scan code.
|
|||
|
//
|
|||
|
|
|||
|
if (SendKbdCommand(KBD_CTR_ENABLE_KBD)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (SendKbdData(KbdSelScanCode)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (GetKbdData(&Result,1000)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (SendKbdData(1)) { // select Scan code 1
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (GetKbdData(&Result,1000)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
TestPassed = TRUE;
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Here when an inner loop init fails and we want to do the outer
|
|||
|
// loop again.
|
|||
|
//
|
|||
|
|
|||
|
LoopAgain:
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (TestPassed) {
|
|||
|
return FALSE;
|
|||
|
} else {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
InitKeyboardController(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine Initializes the Keyboard controller. To account for
|
|||
|
the user accidentally moving the mouse or typing on the keyboard, this
|
|||
|
routine repeats the test a few times before giving up.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE if passed,
|
|||
|
TRUE if bad response received from keyboard controller,
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR Result;
|
|||
|
ULONG Index;
|
|||
|
BOOLEAN TestPassed;
|
|||
|
|
|||
|
TestPassed = FALSE;
|
|||
|
|
|||
|
for (Index = 0; Index < MAXIMUM_KEYBOARD_MOUSE_RETRY_COUNT; Index++) {
|
|||
|
|
|||
|
//
|
|||
|
// Clear both fifos.
|
|||
|
//
|
|||
|
|
|||
|
ClearKbdFifo();
|
|||
|
|
|||
|
//
|
|||
|
// Init Control Register 1 with the PS/2/AT bit clear.
|
|||
|
// This puts the keyboard into PS/2 mode.
|
|||
|
//
|
|||
|
|
|||
|
FwpWriteIOChip (RTC_APORT, RTC_REGNUMBER_RTC_CR1);
|
|||
|
Result = FwpReadIOChip(RTC_DPORT) & ~0x2;
|
|||
|
FwpWriteIOChip (RTC_APORT, RTC_REGNUMBER_RTC_CR1);
|
|||
|
FwpWriteIOChip (RTC_DPORT, Result);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Send Selftest Command. This has to be done before anything else.
|
|||
|
//
|
|||
|
|
|||
|
if (SendKbdCommand(KBD_CTR_SELFTEST)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (GetKbdData(&Result,1000)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (Result != Kbd_Ctr_Selftest_Passed) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now the Keyboard and Mouse are disabled.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Test Keyboard lines.
|
|||
|
//
|
|||
|
|
|||
|
if (SendKbdCommand(KBD_CTR_KBDLINES_TEST)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (GetKbdData(&Result,1000)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (Result != INTERFACE_NO_ERROR) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Test Aux lines.
|
|||
|
//
|
|||
|
|
|||
|
if (SendKbdCommand(KBD_CTR_AUXLINES_TEST)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (GetKbdData(&Result,1000)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
#ifndef ALPHA
|
|||
|
// This test is disabled for Alpha/Jensen. It fails for some reason,
|
|||
|
// but the VMS/OSF console front-end has more comprehensive
|
|||
|
// tests than this routine anyway.
|
|||
|
if (Result != INTERFACE_NO_ERROR) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
#endif
|
|||
|
TestPassed = TRUE;
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (TestPassed) {
|
|||
|
return FALSE;
|
|||
|
} else {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|