NT4/private/ntos/boot/detect/i386/mousec.c
2020-09-30 17:12:29 +02:00

759 lines
20 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
hwdata.c
Abstract:
This module contains the C code to set up mouse configuration data.
Author:
Shie-Lin Tzong (shielint) 18-Jan-1991
Revision History:
--*/
#include "hwdetect.h"
#include "string.h"
//
// External References
//
extern PMOUSE_INFORMATION
LookForPS2Mouse (
VOID
);
extern PMOUSE_INFORMATION
LookForInportMouse (
VOID
);
extern PMOUSE_INFORMATION
LookForSerialMouse (
VOID
);
extern PMOUSE_INFORMATION
LookForBusMouse (
VOID
);
extern VOID
Empty8042 (
VOID
);
extern USHORT
HwGetKey (
VOID
);
extern VOID
HwPushKey (
USHORT Key
);
extern USHORT SavedKey;
//
// Define the master and slave i8259 IRQ bitmask.
//
#define MASTER_IRQ_MASK_BITS 0xB8
#define SLAVE_IRQ_MASK_BITS 0x02
//
// Define the lowest i8259 IRQ that the Inport mouse can reside on. This
// has the highest NT priority.
//
#define INPORT_LOWEST_IRQ 0x03
//
// Define the Inport chip reset value.
//
#define INPORT_RESET 0x80
//
// Define the data registers (pointed to by the Inport address register).
//
#define INPORT_DATA_REGISTER_1 1
#define INPORT_DATA_REGISTER_2 2
//
// Define the Inport mouse mode register and mode bits.
//
#define INPORT_MODE_REGISTER 7
#define INPORT_MODE_0 0x00 // 0 HZ - INTR = 0
#define INPORT_MODE_30HZ 0x01
#define INPORT_MODE_50HZ 0x02
#define INPORT_MODE_100HZ 0x03
#define INPORT_MODE_200HZ 0x04
#define INPORT_MODE_1 0x06 // 0 HZ - INTR = 1
#define INPORT_DATA_INTERRUPT_ENABLE 0x08
#define INPORT_TIMER_INTERRUPT_ENABLE 0x10
#define INPORT_MODE_HOLD 0x20
#define INPORT_MODE_QUADRATURE 0x00
//
// Video adaptor type identifiers.
//
PUCHAR MouseIdentifier[] = {
"UNKNOWN",
"NO MOUSE",
"MICROSOFT",
"MICROSOFT BALLPOINT",
"LOGITECH"
};
PUCHAR MouseSubidentifier[] = {
"",
" PS2 MOUSE",
" SERIAL MOUSE",
" INPORT MOUSE",
" BUS MOUSE",
" PS2 MOUSE WITH WHEEL",
" SERIAL MOUSE WITH WHEEL"
};
//
// The following table translates keyboard make code to
// ascii code. Note, only 0-9 and A-Z are translated.
// Everything else is translated to '?'
//
UCHAR MakeToAsciiTable[] = {
0x3f, 0x3f, 0x31, 0x32, 0x33, // ?, ?, 1, 2, 3,
0x34, 0x35, 0x36, 0x37, 0x38, // 4, 5, 6, 7, 8,
0x39, 0x30, 0x3f, 0x3f, 0x3f, // 9, 0, ?, ?, ?,
0x3f, 0x51, 0x57, 0x45, 0x52, // ?, Q, W, E, R,
0x54, 0x59, 0x55, 0x49, 0x4f, // T, Y, U, I, O,
0x50, 0x3f, 0x3f, 0x3f, 0x3f, // P, ?, ?, ?, ?,
0x41, 0x53, 0x44, 0x46, 0x47, // A, S, D, F, G,
0x48, 0x4a, 0x4b, 0x4c, 0x3f, // H, J, K, L, ?,
0x3f, 0x3f, 0x3f, 0x3f, 0x5a, // ?, ?, ?, ?, Z,
0x58, 0x43, 0x56, 0x42, 0x4e, // X, C, V, B, N,
0x4d}; // W
#define MAX_MAKE_CODE_TRANSLATED 0x32
static ULONG MouseControllerKey = 0;
FPFWCONFIGURATION_COMPONENT_DATA
SetMouseConfigurationData (
PMOUSE_INFORMATION MouseInfo,
FPFWCONFIGURATION_COMPONENT_DATA MouseList
)
/*++
Routine Description:
This routine fills in mouse configuration data.
Arguments:
MouseInfo - Supplies a pointer to the MOUSE_INFOR structure
MouseList - Supplies a pointer to the existing mouse component list.
Returns:
Returns a pointer to our mice controller list.
--*/
{
UCHAR i = 0;
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, Controller, PeripheralEntry;
FPFWCONFIGURATION_COMPONENT Component;
HWCONTROLLER_DATA ControlData;
USHORT z, Length;
FPUCHAR fpString;
if ((MouseInfo->MouseSubtype != SERIAL_MOUSE) &&
(MouseInfo->MouseSubtype != SERIAL_MOUSE_WITH_WHEEL)) {
//
// Initialize Controller data
//
ControlData.NumberPortEntries = 0;
ControlData.NumberIrqEntries = 0;
ControlData.NumberMemoryEntries = 0;
ControlData.NumberDmaEntries = 0;
z = 0;
//
// If it is not SERIAL_MOUSE, set up controller component
//
Controller = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
Component = &Controller->ComponentEntry;
Component->Class = ControllerClass;
Component->Type = PointerController;
Component->Flags.Input = 1;
Component->Version = 0;
Component->Key = MouseControllerKey;
MouseControllerKey++;
Component->AffinityMask = 0xffffffff;
Component->IdentifierLength = 0;
Component->Identifier = NULL;
//
// If we have mouse irq or port information, allocate configuration
// data space for mouse controller component to store these information
//
if (MouseInfo->MouseIrq != 0xffff || MouseInfo->MousePort != 0xffff) {
//
// Set up port and Irq information
//
if (MouseInfo->MousePort != 0xffff) {
ControlData.NumberPortEntries = 1;
ControlData.DescriptorList[z].Type = RESOURCE_PORT;
ControlData.DescriptorList[z].ShareDisposition =
CmResourceShareDeviceExclusive;
ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
ControlData.DescriptorList[z].u.Port.Start.LowPart =
(ULONG)MouseInfo->MousePort;
ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
ControlData.DescriptorList[z].u.Port.Length = 4;
z++;
}
if (MouseInfo->MouseIrq != 0xffff) {
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 =
(ULONG)MouseInfo->MouseIrq;
ControlData.DescriptorList[z].u.Interrupt.Vector =
(ULONG)MouseInfo->MouseIrq;
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;
}
}
Controller->ConfigurationData =
HwSetUpResourceDescriptor(Component,
NULL,
&ControlData,
0,
NULL
);
} else {
//
// Otherwise, we don't have configuration data for the controller
//
Controller->ConfigurationData = NULL;
Component->ConfigurationDataLength = 0;
}
}
//
// Set up Mouse peripheral component
//
PeripheralEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
Component = &PeripheralEntry->ComponentEntry;
Component->Class = PeripheralClass;
Component->Type = PointerPeripheral;
Component->Flags.Input = 1;
Component->Version = 0;
Component->Key = 0;
Component->AffinityMask = 0xffffffff;
Component->ConfigurationDataLength = 0;
PeripheralEntry->ConfigurationData = (FPVOID)NULL;
//
// If Mouse PnP device id is found, translate it to ascii code.
// (The mouse device id is presented to us by keyboard make code.)
//
Length = 0;
if (MouseInfo->DeviceIdLength != 0) {
USHORT i;
if (MouseInfo->MouseSubtype == PS_MOUSE_WITH_WHEEL) {
for (i = 0; i < MouseInfo->DeviceIdLength; i++) {
if (MouseInfo->DeviceId[i] > MAX_MAKE_CODE_TRANSLATED) {
MouseInfo->DeviceId[i] = '?';
} else {
MouseInfo->DeviceId[i] = MakeToAsciiTable[MouseInfo->DeviceId[i]];
}
}
} else if (MouseInfo->MouseSubtype == SERIAL_MOUSE_WITH_WHEEL) {
for (i = 0; i < MouseInfo->DeviceIdLength; i++) {
MouseInfo->DeviceId[i] += 0x20;
}
}
Length = MouseInfo->DeviceIdLength + 3;
}
Length += strlen(MouseIdentifier[MouseInfo->MouseType]) +
strlen(MouseSubidentifier[MouseInfo->MouseSubtype]) + 1;
fpString = (FPUCHAR)HwAllocateHeap(Length, FALSE);
if (MouseInfo->DeviceIdLength != 0) {
_fstrcpy(fpString, MouseInfo->DeviceId);
_fstrcat(fpString, " - ");
_fstrcat(fpString, MouseIdentifier[MouseInfo->MouseType]);
} else {
_fstrcpy(fpString, MouseIdentifier[MouseInfo->MouseType]);
}
_fstrcat(fpString, MouseSubidentifier[MouseInfo->MouseSubtype]);
Component->IdentifierLength = Length;
Component->Identifier = fpString;
if ((MouseInfo->MouseSubtype != SERIAL_MOUSE) &&
(MouseInfo->MouseSubtype != SERIAL_MOUSE_WITH_WHEEL)) {
Controller->Child = PeripheralEntry;
PeripheralEntry->Parent = Controller;
if (MouseList) {
//
// Put the current mouse component to the beginning of the list
//
Controller->Sibling = MouseList;
}
return(Controller);
} else {
CurrentEntry = AdapterEntry->Child; // AdapterEntry MUST have child
while (CurrentEntry) {
if (CurrentEntry->ComponentEntry.Type == SerialController) {
if (MouseInfo->MousePort == (USHORT)CurrentEntry->ComponentEntry.Key) {
//
// For serial mouse, the MousePort field contains
// COM port number.
//
PeripheralEntry->Parent = CurrentEntry;
CurrentEntry->Child = PeripheralEntry;
break;
}
}
CurrentEntry = CurrentEntry->Sibling;
}
return(NULL);
}
}
FPFWCONFIGURATION_COMPONENT_DATA
GetMouseInformation (
VOID
)
/*++
Routine Description:
This routine is the entry for mouse detection routine. It will invoke
lower level routines to detect ALL the mice in the system.
Arguments:
None.
Returns:
A pointer to a mouse component structure, if mouse/mice is detected.
Otherwise a NULL pointer is returned.
--*/
{
PMOUSE_INFORMATION MouseInfo;
FPFWCONFIGURATION_COMPONENT_DATA MouseList = NULL;
//
// Check if there is a key in keyboard look ahead buffer. If yes and
// we have not saved any, we will read it and remember it.
//
if (SavedKey == 0) {
SavedKey = HwGetKey();
}
if (MouseInfo = LookForPS2Mouse()) {
MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
}
if (MouseInfo = LookForInportMouse()) {
MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
}
while (MouseInfo = LookForSerialMouse()) {
SetMouseConfigurationData(MouseInfo, MouseList);
}
if (MouseInfo = LookForBusMouse()) {
MouseList = SetMouseConfigurationData(MouseInfo, MouseList);
}
//
// Finally drain 8042 output buffer again before we leave
//
Empty8042();
//
// If we have a keystroke before the mouse/keyboard detection, we
// needs to push the key back to the keyboard look ahead buffer such
// that ntldr can read it.
//
if (SavedKey) {
HwPushKey(SavedKey);
}
return(MouseList);
}
BOOLEAN
InportMouseIrqDetection(
IN USHORT CurrentPort,
OUT PUSHORT Vector
)
/*++
Routine Description:
This routine attempts to locate the interrupt vector for which
the Inport mouse is configured. The allowable vectors are
3, 4, 5, 7, and 9. If no interrupt vector is found, or more than
one is found, the routine returns FALSE. Otherwise, TRUE is returned.
Note that we diddle the i8259 interrupt controllers here.
Arguments:
CurrentPort - I/O port to use for the mouse.
Vector - Pointer to the location to store the mouse interrupt vector.
Return Value:
Returns TRUE if the Inport interrupt vector was located; otherwise,
FALSE is returned.
--*/
{
UCHAR OldMasterMask, OldSlaveMask;
UCHAR MasterMask, SlaveMask;
UCHAR InterruptBits;
UCHAR PossibleInterruptBits;
int i;
int NumberOfIRQs;
BOOLEAN VectorFound = FALSE;
//
// Get the i8259 interrupt masks.
//
OldMasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
OldSlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
//
// Raise IRQL to the highest priority IRQL the inport would use.
//
WRITE_PORT_UCHAR(
(PUCHAR) PIC1_PORT1,
(UCHAR) 0xff ^ ((UCHAR)(1<<INPORT_LOWEST_IRQ) - 1)
);
WRITE_PORT_UCHAR(
(PUCHAR) PIC2_PORT1,
(UCHAR) 0xff
);
//
// Get the master i8259 interrupt mask.
//
MasterMask = READ_PORT_UCHAR((PUCHAR) PIC1_PORT1);
//
// Reset the Inport chip.
//
WRITE_PORT_UCHAR((PUCHAR)CurrentPort, INPORT_RESET);
//
// Select the Inport mode register for use as the current data register.
//
WRITE_PORT_UCHAR((PUCHAR)CurrentPort, INPORT_MODE_REGISTER);
//
// Disable potential Inport mouse interrupts.
//
WRITE_PORT_UCHAR(
(PUCHAR) PIC1_PORT1,
(UCHAR) (MasterMask | MASTER_IRQ_MASK_BITS)
);
//
// Select the i8259 Interrupt Request Register.
//
WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_IRR);
//
// Attempt to locate the Inport interrupt line on the master i8259.
// Why try this 10 times? It's magic...
//
PossibleInterruptBits = MASTER_IRQ_MASK_BITS;
for (i = 0; i < 10; i++) {
//
// Generate a 0 on the Inport IRQ on the master i8259.
//
WRITE_PORT_UCHAR(
(PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_0
);
//
// Read the interrupt bits off the master i8259. Only bits
// 7, 5, 4, 3, and 2 are of interest. Eliminate non-functional
// IRQs. Only continue looking at the master i8259 if there
// is at least one functional IRQ.
//
InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
InterruptBits &= MASTER_IRQ_MASK_BITS;
InterruptBits ^= MASTER_IRQ_MASK_BITS;
PossibleInterruptBits &= InterruptBits;
if (!PossibleInterruptBits)
break;
//
// Generate a 1 on the Inport IRQ on the master i8259.
//
WRITE_PORT_UCHAR(
(PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_1
);
//
// Read the interrupt bits off the master i8259. Only bits
// 7, 5, 4, 3, and 2 are of interest. Eliminate non-functional
// IRQs. Only continue looking at the master i8259 if there
// is at least one functional IRQ.
//
InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC1_PORT0);
InterruptBits &= MASTER_IRQ_MASK_BITS;
PossibleInterruptBits &= InterruptBits;
if (!PossibleInterruptBits)
break;
}
if (PossibleInterruptBits) {
//
// We found at least one IRQ on the master i8259 that could belong
// to the Inport mouse. Count how many we found. If there is
// more than one, we haven't found the vector. Otherwise, we've
// successfully located the Inport interrupt vector on the master
// i8259 (provided the interrupt vector is 3, 4, 5, or 7).
//
PossibleInterruptBits >>= 3;
NumberOfIRQs = 0;
for (i = 3; i <= 7; i++) {
if (PossibleInterruptBits & 1) {
NumberOfIRQs += 1;
*Vector = (CCHAR) i;
}
PossibleInterruptBits >>= 1;
}
if (NumberOfIRQs == 1) {
VectorFound = TRUE;
} else {
*Vector = 0xffff;
}
}
//
// If we didn't locate the interrupt vector on the master i8259, attempt
// to locate it on the slave i8259.
//
if (!VectorFound) {
//
// Get the slave i8259 interrupt mask.
//
SlaveMask = READ_PORT_UCHAR((PUCHAR) PIC2_PORT1);
//
// Disable potential Inport mouse interrupts.
//
WRITE_PORT_UCHAR(
(PUCHAR) PIC2_PORT1,
(UCHAR) (SlaveMask | SLAVE_IRQ_MASK_BITS)
);
//
// Select the i8259 Interrupt Request Register.
//
WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_IRR);
//
// Attempt to locate the Inport interrupt line on the slave i8259.
// Why try this 10 times? It's magic...
//
PossibleInterruptBits = SLAVE_IRQ_MASK_BITS;
for (i = 0; i < 10; i++) {
//
// Generate a 0 on the Inport IRQ on the slave i8259.
//
WRITE_PORT_UCHAR(
(PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_0
);
//
// Read the interrupt bits off the slave i8259. Only bit 2
// is of interest. Eliminate non-functional IRQs. Only continue
// looking at the slave i8259 if there is at least one
// functional IRQ.
//
InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
InterruptBits &= SLAVE_IRQ_MASK_BITS;
InterruptBits ^= SLAVE_IRQ_MASK_BITS;
PossibleInterruptBits &= InterruptBits;
if (!PossibleInterruptBits)
break;
//
// Generate a 1 on the Inport IRQ on the slave i8259.
//
WRITE_PORT_UCHAR(
(PUCHAR)(CurrentPort + INPORT_DATA_REGISTER_1),
INPORT_TIMER_INTERRUPT_ENABLE + INPORT_MODE_1
);
//
// Read the interrupt bits off the slave i8259. Only bit 2
// is of interest. Eliminate non-functional IRQs. Only continue
// looking at the slave i8259 if there is at least one
// functional IRQ.
//
InterruptBits = READ_PORT_UCHAR((PUCHAR) PIC2_PORT0);
InterruptBits &= SLAVE_IRQ_MASK_BITS;
PossibleInterruptBits &= InterruptBits;
if (!PossibleInterruptBits)
break;
}
//
// We may have found the Inport IRQ. If it's not 2 on slave (really
// 9, overall) then we have NOT found the Inport interrupt vector.
// Otherwise, we have successfully located the Inport vector on
// the slave i8259.
//
if (PossibleInterruptBits == 2) {
*Vector = 9;
VectorFound = TRUE;
} else {
*Vector = 0xffff;
}
//
// Restore the i8259 slave.
//
WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT0, OCW3_READ_ISR);
//
// Restore the i8259 slave interrupt mask.
//
WRITE_PORT_UCHAR((PUCHAR) PIC2_PORT1, SlaveMask);
}
//
// Tri-state the Inport IRQ line.
//
WRITE_PORT_UCHAR((PUCHAR) (CurrentPort + INPORT_DATA_REGISTER_1), 0);
//
// Restore the i8259 master.
//
WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT0, OCW3_READ_ISR);
//
// Restore the i8259 master interrupt mask.
//
WRITE_PORT_UCHAR((PUCHAR) PIC1_PORT1, MasterMask);
//
// Restore the previous IRQL.
//
WRITE_PORT_UCHAR(
(PUCHAR) PIC1_PORT1,
OldMasterMask
);
WRITE_PORT_UCHAR(
(PUCHAR) PIC2_PORT1,
OldSlaveMask
);
return(VectorFound);
}