mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
773 lines
21 KiB
773 lines
21 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pbiosc.c
|
|
|
|
Abstract:
|
|
|
|
This module contains Pnp BIOS dependent routines. It includes code to initialize
|
|
16 bit GDT selectors and to call pnp bios api.
|
|
|
|
Author:
|
|
|
|
Shie-Lin Tzong (shielint) 26-Apr-1995
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "busp.h"
|
|
|
|
WCHAR rgzMultiFunctionAdapter[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
|
|
WCHAR rgzConfigurationData[] = L"Configuration Data";
|
|
WCHAR rgzIdentifier[] = L"Identifier";
|
|
WCHAR rgzBIOSIdentifier[] = L"PNP BIOS";
|
|
|
|
//
|
|
// PbBiosKeyInformation points to the registry data information
|
|
// which includes key value full information and data.
|
|
//
|
|
|
|
PVOID PbBiosKeyInformation;
|
|
|
|
//
|
|
// PbBiosRegistryData points to the pnp bios data
|
|
//
|
|
|
|
PPNP_BIOS_INSTALLATION_CHECK PbBiosRegistryData;
|
|
|
|
//
|
|
// PbBiosCodeSelector contains the selector of the PNP
|
|
// BIOS code.
|
|
//
|
|
|
|
USHORT PbBiosCodeSelector;
|
|
|
|
//
|
|
// PbBiosDataSelector contains the selector of the PNP
|
|
// BIOS data area (F0000-FFFFF)
|
|
//
|
|
|
|
USHORT PbBiosDataSelector;
|
|
|
|
//
|
|
// PbSelectors[] contains general purpose preallocated selectors
|
|
//
|
|
|
|
USHORT PbSelectors[2];
|
|
|
|
//
|
|
// PbBiosEventAddress contains the virtual address of the PNP
|
|
// BIOS Event Flag.
|
|
//
|
|
|
|
PUCHAR PbBiosEventAddress;
|
|
|
|
//
|
|
// PbBiosEntryPoint contains the Pnp Bios entry offset
|
|
//
|
|
|
|
ULONG PbBiosEntryPoint;
|
|
|
|
//
|
|
// PbDockConnectorRegistered
|
|
//
|
|
|
|
BOOLEAN PbDockConnectorRegistered;
|
|
|
|
//
|
|
// SpinLock to serialize Pnp Bios call
|
|
//
|
|
|
|
KSPIN_LOCK PbBiosSpinlock;
|
|
|
|
//
|
|
// 16 bit protected mode event message address
|
|
//
|
|
|
|
USHORT PbEventMessageOffset;
|
|
USHORT PbEventMessageSelector;
|
|
USHORT PbBiosEventMessage;
|
|
|
|
//
|
|
// External References
|
|
//
|
|
|
|
extern
|
|
USHORT
|
|
PbCallPnpBiosWorker (
|
|
IN ULONG EntryOffset,
|
|
IN ULONG EntrySelector,
|
|
IN PUSHORT Parameters,
|
|
IN USHORT Size
|
|
);
|
|
|
|
extern
|
|
BOOLEAN
|
|
RtlEqualUnicodeString(
|
|
IN PUNICODE_STRING String1,
|
|
IN PUNICODE_STRING String2,
|
|
IN BOOLEAN CaseInSensitive
|
|
);
|
|
|
|
extern
|
|
NTSTATUS
|
|
KeI386AllocateGdtSelectors(
|
|
OUT PUSHORT SelectorArray,
|
|
IN USHORT NumberOfSelectors
|
|
);
|
|
|
|
extern
|
|
NTSTATUS
|
|
KeI386SetGdtSelector (
|
|
IN ULONG Selector,
|
|
IN PKGDTENTRY GdtValue
|
|
);
|
|
|
|
VOID
|
|
PbTimerRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context
|
|
);
|
|
|
|
//
|
|
// Internal prototypes
|
|
//
|
|
|
|
VOID
|
|
PbAddress32ToAddress16 (
|
|
IN PVOID Address32,
|
|
IN PUSHORT Address16,
|
|
IN USHORT Selector
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,PbInitialize)
|
|
#pragma alloc_text(PAGE,PbAddress32ToAddress16)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
PbInitialize (
|
|
ULONG Phase,
|
|
PDEVICE_OBJECT DeviceObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
At phase 0, this routine checks registry for the data collected by
|
|
ntdetect.com to make sure PnP Bios is present and initializes the
|
|
internal data structures for pnp bios bus extender.
|
|
|
|
Phase 0 init is called only once at DriverEntry. Phase 1 is called
|
|
whenever a new bus is registered. If phase 1 is called for bus number
|
|
1 (i.e. docking station bus), a timer will be start to poll Pnp Bios
|
|
event if necessary.
|
|
|
|
Note, only Bus 0 (mother board devices) and bus 1 (docking station devices)
|
|
are supported.
|
|
|
|
Arguments:
|
|
|
|
Phase - supplies a number to indicate the phase of the initialization.
|
|
|
|
DeviceObject - a pointer to the bus extender device object. At phase 0,
|
|
it is NULL.
|
|
|
|
Return Value:
|
|
|
|
A NTSTATUS code to indicate the result of the initialization.
|
|
|
|
--*/
|
|
{
|
|
KGDTENTRY gdtEntry;
|
|
UNICODE_STRING unicodeString, unicodeValueName, biosId;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
HANDLE hMFunc, hBus;
|
|
WCHAR wbuffer[10];
|
|
ULONG codeBase, i, length;
|
|
PWSTR p;
|
|
PKEY_VALUE_FULL_INFORMATION valueInfo;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR desc;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDesc;
|
|
NTSTATUS status;
|
|
BOOLEAN same;
|
|
USHORT selectors[4];
|
|
PHYSICAL_ADDRESS physicalAddr;
|
|
PVOID virtualAddr;
|
|
PB_PARAMETERS biosParameters;
|
|
USHORT pnpControl;
|
|
|
|
if (Phase == 1) {
|
|
if (((PMB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->BusHandler->BusNumber ==
|
|
MbpBusNumber[0]) {
|
|
if (PbBiosEventAddress) {
|
|
|
|
//
|
|
// First disable pnp bios default event timeout
|
|
//
|
|
|
|
biosParameters.Function = PNP_BIOS_SEND_MESSAGE;
|
|
biosParameters.u.SendMessage.Message = PNP_OS_ACTIVE;
|
|
status = PbHardwareService(&biosParameters);
|
|
if (!NT_SUCCESS(status)) {
|
|
DebugPrint((DEBUG_MESSAGE, "PnpBios: Disable Event timeout failed\n"));
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Create timer to poll for PNP BIOS events.
|
|
//
|
|
|
|
IoInitializeTimer (DeviceObject, PbTimerRoutine, NULL);
|
|
IoStartTimer (DeviceObject);
|
|
}
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Look in the registery for the "PNP BIOS bus" data
|
|
//
|
|
|
|
RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter);
|
|
InitializeObjectAttributes (&objectAttributes,
|
|
&unicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL, // handle
|
|
NULL);
|
|
|
|
|
|
status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes);
|
|
if (!NT_SUCCESS(status)) {
|
|
DebugPrint((DEBUG_MESSAGE, "PnpBIos:Can not open MultifunctionAdapter registry key.\n"));
|
|
return status;
|
|
}
|
|
|
|
unicodeString.Buffer = wbuffer;
|
|
unicodeString.MaximumLength = sizeof(wbuffer);
|
|
RtlInitUnicodeString(&biosId, rgzBIOSIdentifier);
|
|
|
|
for (i = 0; TRUE; i++) {
|
|
RtlIntegerToUnicodeString (i, 10, &unicodeString);
|
|
InitializeObjectAttributes (
|
|
&objectAttributes,
|
|
&unicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hMFunc,
|
|
NULL);
|
|
|
|
status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Out of Multifunction adapter entries...
|
|
//
|
|
|
|
DebugPrint((DEBUG_MESSAGE, "PnpBIos: Pnp BIOS MultifunctionAdapter registry key not found.\n"));
|
|
ZwClose (hMFunc);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Check the Indentifier to see if this is a Pnp BIOS entry
|
|
//
|
|
|
|
status = PbGetRegistryValue (hBus, rgzIdentifier, &valueInfo);
|
|
if (!NT_SUCCESS (status)) {
|
|
ZwClose (hBus);
|
|
continue;
|
|
}
|
|
|
|
p = (PWSTR) ((PUCHAR) valueInfo + valueInfo->DataOffset);
|
|
unicodeValueName.Buffer = p;
|
|
unicodeValueName.MaximumLength = (USHORT)valueInfo->DataLength;
|
|
length = valueInfo->DataLength;
|
|
|
|
//
|
|
// Determine the real length of the ID string
|
|
//
|
|
|
|
while (length) {
|
|
if (p[length / sizeof(WCHAR) - 1] == UNICODE_NULL) {
|
|
length -= 2;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
unicodeValueName.Length = (USHORT)length;
|
|
same = RtlEqualUnicodeString(&biosId, &unicodeValueName, TRUE);
|
|
ExFreePool(valueInfo);
|
|
if (!same) {
|
|
ZwClose (hBus);
|
|
continue;
|
|
}
|
|
|
|
status = PbGetRegistryValue(hBus, rgzConfigurationData, &valueInfo);
|
|
ZwClose (hBus);
|
|
if (!NT_SUCCESS(status)) {
|
|
continue ;
|
|
}
|
|
|
|
desc = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR)
|
|
valueInfo + valueInfo->DataOffset);
|
|
partialDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)
|
|
desc->PartialResourceList.PartialDescriptors);
|
|
|
|
if (partialDesc->Type == CmResourceTypeDeviceSpecific) {
|
|
|
|
//
|
|
// got it.. Perform sanity check
|
|
//
|
|
|
|
PbBiosRegistryData = (PPNP_BIOS_INSTALLATION_CHECK) (partialDesc+1);
|
|
if (PbBiosRegistryData->Signature[0] == '$'&&
|
|
PbBiosRegistryData->Signature[1] == 'P'&&
|
|
PbBiosRegistryData->Signature[2] == 'n'&&
|
|
PbBiosRegistryData->Signature[3] == 'P') {
|
|
PbBiosKeyInformation = (PVOID)valueInfo;
|
|
ZwClose (hMFunc);
|
|
break;
|
|
}
|
|
}
|
|
ExFreePool(valueInfo);
|
|
}
|
|
|
|
//
|
|
// We find the Pnp BIOS data stored by ntdetect.com. Initialize Pnp BIOS
|
|
// get/set event if supported.
|
|
//
|
|
|
|
pnpControl = PbBiosRegistryData->ControlField & PNP_BIOS_CONTROL_MASK;
|
|
if ((pnpControl & PNP_BIOS_CONTROL_MASK) != PNP_BIOS_EVENT_NOT_SUPPORTED) {
|
|
if ((pnpControl & PNP_BIOS_CONTROL_MASK) == PNP_BIOS_EVENT_POLLING) {
|
|
|
|
//
|
|
// Pnp BIOS event notification is supported thru polling. We need
|
|
// to map event address to non paged pool virtual address.
|
|
//
|
|
|
|
physicalAddr.LowPart = PbBiosRegistryData->EventFlagAddress;
|
|
physicalAddr.HighPart = 0;
|
|
virtualAddr = MmMapIoSpace (physicalAddr, 1, FALSE);
|
|
PbBiosEventAddress = (PUCHAR)virtualAddr;
|
|
} else if ((pnpControl & PNP_BIOS_CONTROL_MASK) == PNP_BIOS_EVENT_ASYNC) {
|
|
|
|
//
|
|
// Add code here
|
|
//
|
|
}
|
|
|
|
//
|
|
// Create eject callback object to notify dock/undock events
|
|
//
|
|
|
|
RtlInitUnicodeString(&unicodeString, L"\\Callback\\PnpBiosEvent");
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&unicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = ExCreateCallback (&MbpEjectCallbackObject, &objectAttributes, TRUE, TRUE);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate 4 or 5 selectors for calling PnP Bios Apis.
|
|
// If event notification is supported thru polling, we set up an selector for the event
|
|
// addr (16 bit.). Because the GET EVENT call is made from DPC level and we can not
|
|
// call kernel routine to set selector at DPC level.
|
|
//
|
|
|
|
if (PbBiosEventAddress) {
|
|
i = 5;
|
|
} else {
|
|
i = 4;
|
|
}
|
|
status = KeI386AllocateGdtSelectors (selectors, (USHORT) i);
|
|
if (!NT_SUCCESS(status)) {
|
|
DebugPrint((DEBUG_MESSAGE, "PnpBios: Failed to allocate selectors\n"));
|
|
ExFreePool(valueInfo);
|
|
return status;
|
|
}
|
|
|
|
PbBiosCodeSelector = selectors[0];
|
|
PbBiosDataSelector = selectors[1];
|
|
PbSelectors[0] = selectors[2];
|
|
PbSelectors[1] = selectors[3];
|
|
|
|
PbBiosEntryPoint = (ULONG)PbBiosRegistryData->ProtectedModeEntryOffset;
|
|
|
|
//
|
|
// Initialize selectors to use PNP bios code
|
|
//
|
|
|
|
//
|
|
// initialize 16 bit code selector
|
|
//
|
|
|
|
gdtEntry.LimitLow = 0xFFFF;
|
|
gdtEntry.HighWord.Bytes.Flags1 = 0;
|
|
gdtEntry.HighWord.Bytes.Flags2 = 0;
|
|
gdtEntry.HighWord.Bits.Pres = 1;
|
|
gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM;
|
|
gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE;
|
|
gdtEntry.HighWord.Bits.Type = 31;
|
|
gdtEntry.HighWord.Bits.Default_Big = 0;
|
|
physicalAddr.LowPart = PbBiosRegistryData->ProtectedModeCodeBaseAddress;
|
|
virtualAddr = MmMapIoSpace (physicalAddr, 0x10000, TRUE);
|
|
codeBase = (ULONG)virtualAddr;
|
|
gdtEntry.BaseLow = (USHORT) (codeBase & 0xffff);
|
|
gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (codeBase >> 16) & 0xff;
|
|
gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (codeBase >> 24) & 0xff;
|
|
KeI386SetGdtSelector (PbBiosCodeSelector, &gdtEntry);
|
|
|
|
//
|
|
// initialize 16 bit data selector for Pnp BIOS
|
|
//
|
|
|
|
gdtEntry.LimitLow = 0xFFFF;
|
|
gdtEntry.HighWord.Bytes.Flags1 = 0;
|
|
gdtEntry.HighWord.Bytes.Flags2 = 0;
|
|
gdtEntry.HighWord.Bits.Pres = 1;
|
|
gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM;
|
|
gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE;
|
|
gdtEntry.HighWord.Bits.Type = 19;
|
|
gdtEntry.HighWord.Bits.Default_Big = 1;
|
|
physicalAddr.LowPart = PbBiosRegistryData->ProtectedModeDataBaseAddress;
|
|
virtualAddr = MmMapIoSpace (physicalAddr, 0x10000, TRUE);
|
|
codeBase = (ULONG)virtualAddr;
|
|
gdtEntry.BaseLow = (USHORT) (codeBase & 0xffff);
|
|
gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (codeBase >> 16) & 0xff;
|
|
gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (codeBase >> 24) & 0xff;
|
|
KeI386SetGdtSelector (PbBiosDataSelector, &gdtEntry);
|
|
|
|
//
|
|
// initialize selecot part of message address for calling BIOS
|
|
//
|
|
|
|
if (PbBiosEventAddress) {
|
|
PbEventMessageSelector = selectors[4];
|
|
PbEventMessageOffset = 0;
|
|
|
|
gdtEntry.LimitLow = 0x3; // 1?
|
|
gdtEntry.HighWord.Bytes.Flags1 = 0;
|
|
gdtEntry.HighWord.Bytes.Flags2 = 0;
|
|
gdtEntry.HighWord.Bits.Pres = 1;
|
|
gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM;
|
|
gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE;
|
|
gdtEntry.HighWord.Bits.Type = 19;
|
|
gdtEntry.HighWord.Bits.Default_Big = 1;
|
|
codeBase = (ULONG)&PbBiosEventMessage;
|
|
gdtEntry.BaseLow = (USHORT) (codeBase & 0xffff);
|
|
gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (codeBase >> 16) & 0xff;
|
|
gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (codeBase >> 24) & 0xff;
|
|
KeI386SetGdtSelector (PbEventMessageSelector, &gdtEntry);
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the other two general purpose data selector such that
|
|
// on subsequent init we only need to init the base addr.
|
|
//
|
|
|
|
KeI386SetGdtSelector (PbSelectors[0], &gdtEntry);
|
|
KeI386SetGdtSelector (PbSelectors[1], &gdtEntry);
|
|
|
|
//
|
|
// Initialize BIOS call spinlock
|
|
//
|
|
|
|
KeInitializeSpinLock (&PbBiosSpinlock);
|
|
|
|
//
|
|
// Get maximum pnp bios slot data size
|
|
//
|
|
|
|
biosParameters.Function = PNP_BIOS_GET_NUMBER_DEVICE_NODES;
|
|
biosParameters.u.GetNumberDeviceNodes.NumberNodes = (PUSHORT)&i;
|
|
biosParameters.u.GetNumberDeviceNodes.NodeSize = (PUSHORT) &MbpMaxDeviceData;
|
|
status = PbHardwareService(&biosParameters);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PbHardwareService (
|
|
IN PPB_PARAMETERS Parameters
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets up stack parameters and calls an
|
|
assembly worker routine to actually invoke the PNP BIOS code.
|
|
|
|
Arguments:
|
|
|
|
Parameters - supplies a pointer to the parameter block.
|
|
|
|
Return Value:
|
|
|
|
An NTSTATUS code to indicate the result of the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
USHORT stackParameters[PB_MAXIMUM_STACK_SIZE / 2];
|
|
ULONG i = 0;
|
|
USHORT retCode;
|
|
KIRQL oldIrql;
|
|
|
|
//
|
|
// Convert and copy the caller's parameters to the format that
|
|
// will be used to invoked pnp bios.
|
|
//
|
|
|
|
stackParameters[i] = Parameters->Function;
|
|
i++;
|
|
|
|
switch (Parameters->Function) {
|
|
case PNP_BIOS_GET_NUMBER_DEVICE_NODES:
|
|
PbAddress32ToAddress16(Parameters->u.GetNumberDeviceNodes.NumberNodes,
|
|
&stackParameters[i],
|
|
PbSelectors[0]);
|
|
i += 2;
|
|
PbAddress32ToAddress16(Parameters->u.GetNumberDeviceNodes.NodeSize,
|
|
&stackParameters[i],
|
|
PbSelectors[1]);
|
|
i += 2;
|
|
stackParameters[i++] = PbBiosDataSelector;
|
|
break;
|
|
case PNP_BIOS_GET_DEVICE_NODE:
|
|
PbAddress32ToAddress16(Parameters->u.GetDeviceNode.Node,
|
|
&stackParameters[i],
|
|
PbSelectors[0]);
|
|
i += 2;
|
|
PbAddress32ToAddress16(Parameters->u.GetDeviceNode.NodeBuffer,
|
|
&stackParameters[i],
|
|
PbSelectors[1]);
|
|
i += 2;
|
|
stackParameters[i++] = Parameters->u.GetDeviceNode.Control;
|
|
stackParameters[i++] = PbBiosDataSelector;
|
|
break;
|
|
case PNP_BIOS_SET_DEVICE_NODE:
|
|
stackParameters[i++] = Parameters->u.SetDeviceNode.Node;
|
|
PbAddress32ToAddress16(Parameters->u.SetDeviceNode.NodeBuffer,
|
|
&stackParameters[i],
|
|
PbSelectors[0]);
|
|
i += 2;
|
|
stackParameters[i++] = Parameters->u.SetDeviceNode.Control;
|
|
stackParameters[i++] = PbBiosDataSelector;
|
|
break;
|
|
case PNP_BIOS_GET_EVENT:
|
|
stackParameters[i++] = PbEventMessageOffset;
|
|
stackParameters[i++] = PbEventMessageSelector;
|
|
stackParameters[i++] = PbBiosDataSelector;
|
|
break;
|
|
case PNP_BIOS_SEND_MESSAGE:
|
|
stackParameters[i++] = Parameters->u.SendMessage.Message;
|
|
stackParameters[i++] = PbBiosDataSelector;
|
|
break;
|
|
case PNP_BIOS_GET_DOCK_INFORMATION:
|
|
PbAddress32ToAddress16(Parameters->u.GetDockInfo.DockingStationInfo,
|
|
&stackParameters[i],
|
|
PbSelectors[0]);
|
|
i += 2;
|
|
stackParameters[i++] = PbBiosDataSelector;
|
|
break;
|
|
default:
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
//
|
|
// Copy the parameters to stack and invoke Pnp Bios.
|
|
//
|
|
|
|
KeAcquireSpinLock (&PbBiosSpinlock, &oldIrql);
|
|
|
|
retCode = PbCallPnpBiosWorker (
|
|
PbBiosEntryPoint,
|
|
PbBiosCodeSelector,
|
|
stackParameters,
|
|
(USHORT)(i * sizeof(USHORT)));
|
|
|
|
KeReleaseSpinLock (&PbBiosSpinlock, oldIrql);
|
|
|
|
//
|
|
// Special handling for Get Docking station information. We need to
|
|
// return the docking state (i.e. the returned code.)
|
|
//
|
|
|
|
if (Parameters->Function == PNP_BIOS_GET_DOCK_INFORMATION) {
|
|
*(Parameters->u.GetDockInfo.DockState) = 0;
|
|
if (retCode == SYSTEM_NOT_DOCKED) {
|
|
*(Parameters->u.GetDockInfo.DockState) = retCode;
|
|
retCode = 0;
|
|
} else if (retCode == UNABLE_TO_DETERMINE_DOCK_CAPABILITIES) {
|
|
Parameters->u.GetDockInfo.DockingStationInfo->Capabilities = (USHORT) -1;
|
|
retCode = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Map Bios returned code to nt status code.
|
|
//
|
|
|
|
if (retCode == 0) {
|
|
return STATUS_SUCCESS;
|
|
} else {
|
|
DebugPrint((DEBUG_BREAK, "PnpBios: Bios API call failed.\n"));
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PbAddress32ToAddress16 (
|
|
IN PVOID Address32,
|
|
IN PUSHORT Address16,
|
|
IN USHORT Selector
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts the 32 bit address to 16 bit selector:offset address
|
|
and stored in user specified location.
|
|
|
|
Arguments:
|
|
|
|
Address32 - the 32 bit address to be converted.
|
|
|
|
Address16 - supplies the location to receive the 16 bit sel:offset address
|
|
|
|
Selector - the 16 bit selector for seg:offset address
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KGDTENTRY gdtEntry;
|
|
ULONG baseAddr;
|
|
|
|
//
|
|
// Map virtual address to selector:0 address
|
|
//
|
|
|
|
gdtEntry.LimitLow = 0xFFFF;
|
|
gdtEntry.HighWord.Bytes.Flags1 = 0;
|
|
gdtEntry.HighWord.Bytes.Flags2 = 0;
|
|
gdtEntry.HighWord.Bits.Pres = 1;
|
|
gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM;
|
|
gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE;
|
|
gdtEntry.HighWord.Bits.Type = 19;
|
|
gdtEntry.HighWord.Bits.Default_Big = 1;
|
|
baseAddr = (ULONG)Address32;
|
|
gdtEntry.BaseLow = (USHORT) (baseAddr & 0xffff);
|
|
gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (baseAddr >> 16) & 0xff;
|
|
gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (baseAddr >> 24) & 0xff;
|
|
KeI386SetGdtSelector (Selector, &gdtEntry);
|
|
*Address16 = 0;
|
|
*(Address16 + 1) = Selector;
|
|
}
|
|
|
|
VOID
|
|
PbTimerRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PB_PARAMETERS biosParameters;
|
|
NTSTATUS status;
|
|
USHORT junk;
|
|
|
|
//
|
|
// Check for Pnp BIOS event
|
|
//
|
|
|
|
if (*PbBiosEventAddress & 1) {
|
|
|
|
//
|
|
// Get Pnp BIOS event.
|
|
//
|
|
|
|
biosParameters.Function = PNP_BIOS_GET_EVENT;
|
|
biosParameters.u.GetEvent.Message = &PbBiosEventMessage;
|
|
status = PbHardwareService(&biosParameters);
|
|
if (!NT_SUCCESS(status)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Process the event ...
|
|
//
|
|
|
|
switch (PbBiosEventMessage) {
|
|
case ABOUT_TO_CHANGE_CONFIG:
|
|
DebugPrint((DEBUG_MESSAGE, "PnpBios:Configuration about to change ...\n"));
|
|
if (MbpConfigAboutToChange()) {
|
|
biosParameters.Function = PNP_BIOS_SEND_MESSAGE;
|
|
biosParameters.u.SendMessage.Message = OK_TO_CHANGE_CONFIG;
|
|
PbHardwareService(&biosParameters);
|
|
}
|
|
break;
|
|
|
|
case DOCK_CHANGED:
|
|
case SYSTEM_DEVICE_CHANGED:
|
|
|
|
//
|
|
// For dock, undock and system device changes, we invalidate cached
|
|
// pnp bios data and notify enumerator to reenumerate the devices.
|
|
//
|
|
|
|
DebugPrint((DEBUG_MESSAGE, "PnpBios:Configuration changed\n"));
|
|
if (PbBiosKeyInformation) {
|
|
PbBiosKeyInformation = NULL;
|
|
PbBiosRegistryData = NULL;
|
|
ExFreePool(PbBiosKeyInformation);
|
|
}
|
|
|
|
//
|
|
// Invalidate maximum slot data information after configuration changed.
|
|
//
|
|
|
|
MbpMaxDeviceData = 0;
|
|
|
|
MbpConfigChanged();
|
|
break;
|
|
|
|
case CONFIG_CHANGE_FAILED:
|
|
|
|
//
|
|
// do nothing.
|
|
// BUGBUG - We should define someway to notify the dock/undock
|
|
// failed. So, user can be notified.
|
|
//
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|