|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
abiosc.c
Abstract:
This module implements keybaord detection C routines.
Author:
Shie-Lin Tzong (shielint) 18-Dec-1991
Environment:
Real Mode.
Revision History:
--*/
#include "hwdetect.h"
#include "string.h"
#if !defined(_GAMBIT_)
extern UCHAR GetKeyboardFlags ( VOID );
extern USHORT HwGetKey ( VOID );
extern BOOLEAN NoBiosKbdCheck; #endif // _GAMBIT_
#if defined(NEC_98)
ULONG GetKeyboard2ndIDNEC98( VOID ); //
// Definitions for the keyboard type returned from
// the detect keyboard function.
//
#define PC98_106KEY 10
#define PC98_NmodeKEY 11
#define PC98_HmodeKEY 12
#define PC98_LaptopKEY 13
#define PC98_N106KEY 14
#define N5200E_KEY 15
#define PC98_KEYBOARD_ID_FIRST_BYTE 0xA0
#define PC98_KEYBOARD_ID_2ND_BYTE_STD 0x80
#define PC98_KEYBOARD_ID_2ND_BYTE_N106 0x82
#define PC98_KEYBOARD_ID_2ND_BYTE_Win95 0x83
#define READ_KEYBOARD_2ND_ID 0x96
#define PC98_8251_BUFFER_EMPTY 0x01
#define PC98_8251_DATA_READY 0x02
#define ACKNOWLEDGE 0xFA
#define RESEND 0xFC
#define STATUS_SUCCESS 0x00000000L // from ntstatus.h
#define STATUS_IO_TIMEOUT 0xC00000B5L // from ntstatus.h
#define POLLING_ITERATION 12000
#define RESEND_ITERATION 3
#define KBD_COMMAND_STATUS_PORT 0x43
#define KBD_DATA_PORT 0x41
#define PIC1_PORT1 0x02
#endif // PC98
//
// SavedKey is used to save the key left in the keyboard type-ahead buffer
// before we start our keyboard/mouse tests. The key will be push back
// to the type-ahead buffer once the mouse detection is done.
//
USHORT SavedKey = 0;
//
// String table to map keyboard id to an ascii string.
//
PUCHAR KeyboardIdentifier[] = { "UNKNOWN_KEYBOARD", "OLI_83KEY", "OLI_102KEY", "OLI_86KEY", "OLI_A101_102KEY", "XT_83KEY", "ATT_302", "PCAT_ENHANCED", "PCAT_86KEY", "PCXT_84KEY" #if defined(NEC_98)
, "PC98_106KEY", "PC98_NmodeKEY", "PC98_HmodeKEY", "PC98_LaptopKEY", "PC98_N106KEY", "N5200/E_KEY" #endif // PC98
};
UCHAR KeyboardType[] = { -1, 1, 2, 3, 4, 1, 1, 4, 3, 1 #if defined(NEC_98)
, 7, //Japanese Keyboard Type
7, //Japanese Keyboard Type
7, //Japanese Keyboard Type
7, //Japanese Keyboard Type
7, //Japanese Keyboard Type
7 //Japanese Keyboard Type
#endif // PC98
};
UCHAR KeyboardSubtype[] = { -1, 0, 1, 10, 4, 42, 4, 0, 0, 0 #if defined(NEC_98)
, 1, //10 PC-9800 Serise S/W Lock Keyboard
2, //11 PC-9801 VX/UX,PC-98XL/XL2 H/W Lock Keyboard
3, //12 PC-98XL/XL2 H/W Lock Keyboard
4, //13 PC-9800 Serise Laptop Keyboard
5, //14 PC-9801-116 Keyboard
6 //15 N5200/E Serise Keyboard
#endif // PC98
};
USHORT GetKeyboardId( VOID )
/*++
Routine Description:
This routine determines the Id of the keyboard. It calls GetKeyboardIdBytes to complete the task.
Arguments:
None.
Return Value:
Keyboard ID.
--*/
{ #if defined(_GAMBIT_)
return (7); // PCAT_ENHANCED
#else
#if defined(NEC_98)
char KeybID_Bytes[5]; int Num_ID_Bytes; ULONG NEC2ndKeyID; int keytype = UNKNOWN_KEYBOARD;
Num_ID_Bytes = GetKeyboardIdBytes(KeybID_Bytes, 0x05); if (Num_ID_Bytes > 0) { switch(KeybID_Bytes[0] & 0x00ff) {
case 0x80: keytype = PC98_NmodeKEY; break;
case 0x88: keytype = PC98_HmodeKEY; break;
case 0x40: NEC2ndKeyID = GetKeyboard2ndIDNEC98(); if (NEC2ndKeyID == PC98_N106KEY) { keytype = PC98_N106KEY; }else{ keytype = PC98_106KEY; } break;
case 0x08: case 0x48: keytype = PC98_LaptopKEY; break;
default: keytype = UNKNOWN_KEYBOARD; break; } } else { keytype = PCAT_ENHANCED; }
return(keytype); #else // PC98
char KeybID_Bytes[5]; int Num_ID_Bytes; int keytype = UNKNOWN_KEYBOARD;
SavedKey = HwGetKey();
Num_ID_Bytes = GetKeyboardIdBytes(KeybID_Bytes, 0x05); if (Num_ID_Bytes > 0) { switch(KeybID_Bytes[0] & 0x00ff) { case 0x02: keytype = OLI_83KEY; break;
case 0x01: keytype = OLI_102KEY; break;
case 0x10: keytype = OLI_86KEY; break;
case 0x40: keytype = OLI_A101_102KEY; break;
case 0x42: keytype = XT_83KEY; break;
case 0x9c: keytype = PCXT_84KEY; break;
case 0x04: keytype = ATT_302; break;
case 0xfe: Num_ID_Bytes = GetKeyboardIdBytes(KeybID_Bytes, 0xf2); if (Num_ID_Bytes > 0) { if ((KeybID_Bytes[0] & 0x00ff) == 0xfa) { keytype = PCAT_86KEY; } else if ((KeybID_Bytes[0] & 0x00ff) == 0xfe) { keytype = PCAT_86KEY; } else if (Num_ID_Bytes >= 3 && ((KeybID_Bytes[1] & 0x00ff) == 0xAB) && ((KeybID_Bytes[2] & 0x00ff) == 0x41)) { keytype = PCAT_ENHANCED; } else { keytype = UNKNOWN_KEYBOARD; } } else { keytype = UNKNOWN_KEYBOARD; } break;
default: keytype = UNKNOWN_KEYBOARD; break; } } else { keytype = PCXT_84KEY; }
if (!NoBiosKbdCheck) {
//
// Sometimes enhanced keyboards get detected as 84/86 key keyboards
// So we will look into the ROM DATA area (40:96) and see if the
// Enhanced Keyboard bit is set. If it is we will assume that the
// detection failed to detect the presence of an enhanced keyb.
//
if ((keytype == PCXT_84KEY) || (keytype == PCAT_86KEY) || (keytype == UNKNOWN_KEYBOARD)) {
if (IsEnhancedKeyboard()) { keytype = PCAT_ENHANCED; } } } return(keytype); #endif // PC98
#endif // _GAMBIT_
}
FPFWCONFIGURATION_COMPONENT_DATA SetKeyboardConfigurationData ( USHORT KeyboardId )
/*++
Routine Description:
This routine maps Keyboard Id information to an ASCII string and stores the string in configuration data heap.
Arguments:
KeyboardId - Supplies a USHORT which describes the keyboard id information.
Buffer - Supplies a pointer to a buffer where to put the ascii.
Returns:
None.
--*/ { FPFWCONFIGURATION_COMPONENT_DATA Controller, CurrentEntry; FPFWCONFIGURATION_COMPONENT Component; HWCONTROLLER_DATA ControlData; FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList; CM_KEYBOARD_DEVICE_DATA far *KeyboardData; USHORT z, Length;
//
// Set up Keyboard COntroller component
//
ControlData.NumberPortEntries = 0; ControlData.NumberIrqEntries = 0; ControlData.NumberMemoryEntries = 0; ControlData.NumberDmaEntries = 0; z = 0; Controller = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap ( sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
Component = &Controller->ComponentEntry;
Component->Class = ControllerClass; Component->Type = KeyboardController; Component->Flags.ConsoleIn = 1; Component->Flags.Input = 1; Component->Version = 0; Component->Key = 0; Component->AffinityMask = 0xffffffff;
//
// Set up Port information
//
#if !defined(_GAMBIT_)
ControlData.NumberPortEntries = 2; ControlData.DescriptorList[z].Type = RESOURCE_PORT; ControlData.DescriptorList[z].ShareDisposition = CmResourceShareDeviceExclusive; ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO; #if defined(NEC_98)
ControlData.DescriptorList[z].u.Port.Start.LowPart = 0x41; #else // PC98
ControlData.DescriptorList[z].u.Port.Start.LowPart = 0x60; #endif // PC98
ControlData.DescriptorList[z].u.Port.Start.HighPart = 0; ControlData.DescriptorList[z].u.Port.Length = 1; z++; ControlData.DescriptorList[z].Type = RESOURCE_PORT; ControlData.DescriptorList[z].ShareDisposition = CmResourceShareDeviceExclusive; ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO; #if defined(NEC_98)
ControlData.DescriptorList[z].u.Port.Start.LowPart = 0x43; #else // PC98
ControlData.DescriptorList[z].u.Port.Start.LowPart = 0x64; #endif // PC98
ControlData.DescriptorList[z].u.Port.Start.HighPart = 0; ControlData.DescriptorList[z].u.Port.Length = 1; z++;
//
// Set up Irq information
//
ControlData.NumberIrqEntries = 1; ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT; ControlData.DescriptorList[z].ShareDisposition = CmResourceShareUndetermined; ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS; ControlData.DescriptorList[z].u.Interrupt.Level = 1; ControlData.DescriptorList[z].u.Interrupt.Vector = 1; if (HwBusType == MACHINE_TYPE_MCA) { ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE; } else {
//
// For EISA the LevelTriggered is temporarily set to FALSE.
//
ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED; } #endif // _GAMBIT_
Controller->ConfigurationData = HwSetUpResourceDescriptor(Component, NULL, &ControlData, 0, NULL );
//
// Set up Keyboard peripheral component
//
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap ( sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
Component = &CurrentEntry->ComponentEntry;
Component->Class = PeripheralClass; Component->Type = KeyboardPeripheral; Component->Flags.ConsoleIn = 1; Component->Flags.Input = 1; Component->Version = 0; Component->Key = 0; Component->AffinityMask = 0xffffffff; Component->ConfigurationDataLength = 0; CurrentEntry->ConfigurationData = (FPVOID)NULL; Length = strlen(KeyboardIdentifier[KeyboardId]) + 1; Component->IdentifierLength = Length; Component->Identifier = HwAllocateHeap(Length, FALSE); _fstrcpy(Component->Identifier, KeyboardIdentifier[KeyboardId]);
if (KeyboardId != UNKNOWN_KEYBOARD) {
Length = sizeof(HWRESOURCE_DESCRIPTOR_LIST) + sizeof(CM_KEYBOARD_DEVICE_DATA); DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap( Length, TRUE); CurrentEntry->ConfigurationData = DescriptorList; Component->ConfigurationDataLength = Length; DescriptorList->Count = 1; DescriptorList->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA; DescriptorList->PartialDescriptors[0].u.DeviceSpecificData.DataSize = sizeof(CM_KEYBOARD_DEVICE_DATA); KeyboardData = (CM_KEYBOARD_DEVICE_DATA far *)(DescriptorList + 1); #if defined(_GAMBIT_)
KeyboardData->KeyboardFlags = 0; #else
KeyboardData->KeyboardFlags = GetKeyboardFlags(); #endif
KeyboardData->Type = KeyboardType[KeyboardId]; KeyboardData->Subtype = KeyboardSubtype[KeyboardId]; }
Controller->Child = CurrentEntry; Controller->Sibling = NULL; CurrentEntry->Parent = Controller; CurrentEntry->Sibling = NULL; CurrentEntry->Child = NULL; return(Controller); } #if defined(NEC_98)
ULONG KbdGetBytePolled( OUT PUCHAR Byte )
/*++
--*/
{ ULONG i; UCHAR response; UCHAR desiredMask;
i = 0; desiredMask = (UCHAR)PC98_8251_DATA_READY;
IoDelay(34); // 20 micro second
//
// Poll until we get back a controller status value that indicates
// the output buffer is full. If we want to read a byte from the mouse,
// further ensure that the auxiliary device output buffer full bit is
// set.
//
while ((i < POLLING_ITERATION ) && ((UCHAR)((response = READ_PORT_UCHAR((PUCHAR)KBD_COMMAND_STATUS_PORT)) & desiredMask) != desiredMask)) {
IoDelay(83); // 50 micro second
i += 1;
} if (i >= (ULONG)POLLING_ITERATION) { return(STATUS_IO_TIMEOUT); }
IoDelay(34); // 20 micro second
//
// Grab the byte from the hardware, and return success.
//
*Byte = READ_PORT_UCHAR((PUCHAR)KBD_DATA_PORT);
return(STATUS_SUCCESS); }
ULONG NEC98_KeyboardCommandByte( IN UCHAR KeyboardCommand )
/*++
Routine Description:
This routine is command out routine for NEC_98 Keyboard controller
Arguments:
KeyboardCommand - A command sent to keyboard.
Return Value:
None.
--*/
{ ULONG i,j; ULONG Status;
WRITE_PORT_UCHAR( (PUCHAR)KBD_COMMAND_STATUS_PORT, (UCHAR)0x37 );
IoDelay(17); // 10 micro second
WRITE_PORT_UCHAR( (PUCHAR)KBD_DATA_PORT, (UCHAR)KeyboardCommand );
IoDelay(75); // 45 micro second
Status = STATUS_SUCCESS; for (j = 0; j < RESEND_ITERATION; j++) {
//
// Make sure the Input Buffer Full controller status bit is clear.
// Time out if necessary.
//
i = 0; while ((i++ < POLLING_ITERATION) && (READ_PORT_UCHAR((PUCHAR)KBD_COMMAND_STATUS_PORT) & PC98_8251_BUFFER_EMPTY) != PC98_8251_BUFFER_EMPTY) {
IoDelay(83); // 50 micro second
} if (i >= POLLING_ITERATION) { Status = STATUS_IO_TIMEOUT; break; } }
WRITE_PORT_UCHAR( (PUCHAR)KBD_COMMAND_STATUS_PORT, (UCHAR)0x16 );
IoDelay(167); // 100 micro second
return(Status); }
ULONG KbdPutBytePolled( IN UCHAR Byte )
/*++
Routine Description:
This routine sends a command or data byte to the controller or keyboard or mouse, in polling mode. It waits for acknowledgment and resends the command/data if necessary.
Arguments:
Byte - The byte to send to the hardware.
Return Value:
STATUS_IO_TIMEOUT - The hardware was not ready for input or did not respond.
STATUS_SUCCESS - The byte was successfully sent to the hardware.
--*/
{ ULONG i,j; UCHAR response; ULONG status; BOOLEAN keepTrying; UCHAR byte, d;
for (j=0;j < RESEND_ITERATION;j++) {
//
// Drain the i8042 output buffer to get rid of stale data.
//
while (d = READ_PORT_UCHAR((PUCHAR)KBD_COMMAND_STATUS_PORT) & PC98_8251_DATA_READY) { //
// Eat the output buffer byte.
//
byte = READ_PORT_UCHAR((PUCHAR)KBD_DATA_PORT); } //
// Send the byte to the appropriate (command/data) hardware register.
//
status = NEC98_KeyboardCommandByte( Byte );
if (status != STATUS_SUCCESS){ return(status); }
//
// Wait for an ACK back from the controller. If we get an ACK,
// the operation was successful. If we get a RESEND, break out to
// the for loop and try the operation again. Ignore anything other
// than ACK or RESEND.
//
keepTrying = FALSE; while ((status = KbdGetBytePolled(&response)) == STATUS_SUCCESS) {
if (response == ACKNOWLEDGE) { break; } else if (response == RESEND) { keepTrying = TRUE; break; }
//
// Ignore any other response, and keep trying.
//
}
if (!keepTrying) break; } //
// Check to see if the number of allowable retries was exceeded.
//
if (j >= RESEND_ITERATION) { status = STATUS_IO_TIMEOUT; }
return(status); }
ULONG GetKeyboard2ndIDNEC98( VOID )
/*++
Routine Description:
This routine detects keyboard hardware for NEC_98.
Arguments:
Return Value:
keyboard type(see i8042prt.h)
--*/
{ UCHAR IDStatus = 0; ULONG KeyboardType; UCHAR temp;
KeyboardType = PC98_106KEY; // default keyboard type.
//
// mask keyboard interrupt.
//
_asm{ cli } temp = READ_PORT_UCHAR((PUCHAR)PIC1_PORT1); WRITE_PORT_UCHAR((PUCHAR)PIC1_PORT1,(temp | 0x02)); _asm{ sti }
if (KbdPutBytePolled( (UCHAR)READ_KEYBOARD_2ND_ID) == STATUS_SUCCESS) {
while( KbdGetBytePolled( &IDStatus ) != STATUS_SUCCESS);
switch(IDStatus){ case PC98_KEYBOARD_ID_FIRST_BYTE: while ( KbdGetBytePolled( &IDStatus ) != STATUS_SUCCESS);
switch(IDStatus){ case PC98_KEYBOARD_ID_2ND_BYTE_N106: KeyboardType = PC98_N106KEY; break; case PC98_KEYBOARD_ID_2ND_BYTE_Win95: default: break; } break; default: break; } }
//
// unmask keyboard interrupt.
//
WRITE_PORT_UCHAR((PUCHAR)PIC1_PORT1,temp);
return KeyboardType; } #endif // defined(NEC_98)
|