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.
466 lines
12 KiB
466 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation All Rights Reserved
|
|
|
|
Module Name:
|
|
|
|
memory.c
|
|
|
|
Abstract:
|
|
|
|
This module controls access to the simulated memory space of the SHPC.
|
|
|
|
|
|
|
|
Environment:
|
|
|
|
Kernel Mode
|
|
|
|
Revision History:
|
|
|
|
Davis Walker (dwalker) Sept 8 2000
|
|
|
|
--*/
|
|
|
|
#include "hpsp.h"
|
|
|
|
NTSTATUS
|
|
HpsInitHBRB(
|
|
IN PHPS_DEVICE_EXTENSION Extension
|
|
)
|
|
{
|
|
|
|
NTSTATUS status;
|
|
ACPI_EVAL_INPUT_BUFFER input;
|
|
PACPI_EVAL_OUTPUT_BUFFER output = NULL;
|
|
ULONG count;
|
|
PACPI_METHOD_ARGUMENT argument;
|
|
ULONG outputSize = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + sizeof(ACPI_METHOD_ARGUMENT) * HBRB_PACKAGE_COUNT;
|
|
PHYSICAL_ADDRESS HBRB;
|
|
PHBRB_HEADER HBRBHeader;
|
|
PHBRB_CAPABILITIES_HEADER HBRBCapHeader;
|
|
|
|
PAGED_CODE();
|
|
|
|
output = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, outputSize);
|
|
|
|
if (!output) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
RtlZeroMemory(&input, sizeof(ACPI_EVAL_INPUT_BUFFER));
|
|
RtlZeroMemory(output, outputSize);
|
|
|
|
//
|
|
// Send a IOCTL to ACPI to request it to run the HBRB method on this device
|
|
// if the method it is present
|
|
//
|
|
|
|
input.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
|
input.MethodNameAsUlong = (ULONG)'BRBH';
|
|
|
|
//
|
|
// HpsSendIoctl deals with sending this from the top of the stack.
|
|
//
|
|
|
|
status = HpsSendIoctl(Extension->Self,
|
|
IOCTL_ACPI_EVAL_METHOD,
|
|
&input,
|
|
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
|
output,
|
|
outputSize
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Check they are all integers and in the right bounds
|
|
//
|
|
ASSERT(output->Count <= HBRB_PACKAGE_COUNT);
|
|
if (output->Argument[0].Type != ACPI_METHOD_ARGUMENT_INTEGER) {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto cleanup;
|
|
}
|
|
HBRB.LowPart = output->Argument[0].Argument;
|
|
|
|
if (output->Count > 1) {
|
|
if (output->Argument[1].Type != ACPI_METHOD_ARGUMENT_INTEGER) {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto cleanup;
|
|
}
|
|
HBRB.HighPart = output->Argument[1].Argument;
|
|
}
|
|
Extension->HBRBOffset = (PUCHAR)HBRB.QuadPart;
|
|
Extension->HBRBLength = sizeof(HBRB_HEADER) + sizeof(HBRB_CAPABILITIES_HEADER) + sizeof(SHPC_REGISTER_SET);
|
|
Extension->HBRBRegisterSetOffset = sizeof(HBRB_HEADER) + sizeof(HBRB_CAPABILITIES_HEADER);
|
|
|
|
Extension->HBRB = ExAllocatePool(NonPagedPool,sizeof(HBRB_HEADER) +
|
|
sizeof(HBRB_CAPABILITIES_HEADER) +
|
|
sizeof(SHPC_REGISTER_SET)
|
|
);
|
|
if (!Extension->HBRB) {
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
HBRBHeader = (PHBRB_HEADER)Extension->HBRB;
|
|
HBRBHeader->BusNumber = 0;
|
|
HBRBHeader->VendorID = 0x9999;
|
|
HBRBHeader->DeviceID = 0x0123;
|
|
HBRBHeader->SubSystemID = 0x1234;
|
|
HBRBHeader->SubVendorID = 0x9999;
|
|
HBRBHeader->ProgIF = 1;
|
|
HBRBHeader->RevisionID = 1;
|
|
HBRBHeader->HBRBVersion = 1;
|
|
HBRBHeader->CapabilitiesPtr = sizeof(HBRB_HEADER);
|
|
HBRBHeader->Size = sizeof(HBRB_HEADER) + sizeof(HBRB_CAPABILITIES_HEADER) + sizeof(SHPC_REGISTER_SET);
|
|
|
|
HBRBCapHeader = (PHBRB_CAPABILITIES_HEADER)((PUCHAR)HBRBHeader + sizeof(HBRB_HEADER));
|
|
HBRBCapHeader->CapabilityID = 0xC;
|
|
HBRBCapHeader->Next = 0x0;
|
|
|
|
status = HpsInitRegisters(Extension);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
RtlCopyMemory((PUCHAR)HBRBCapHeader + sizeof(HBRB_CAPABILITIES_HEADER),
|
|
&Extension->RegisterSet,
|
|
sizeof(SHPC_REGISTER_SET)
|
|
);
|
|
|
|
cleanup:
|
|
|
|
if (output) {
|
|
ExFreePool(output);
|
|
}
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsGetHBRBHwInit(
|
|
IN PHPS_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ACPI_EVAL_INPUT_BUFFER input;
|
|
PACPI_EVAL_OUTPUT_BUFFER output = NULL;
|
|
ULONG count;
|
|
PACPI_METHOD_ARGUMENT argument;
|
|
ULONG outputSize = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + sizeof(ACPI_METHOD_ARGUMENT) + sizeof(HPS_HWINIT_DESCRIPTOR);
|
|
PHYSICAL_ADDRESS HBRB;
|
|
PHBRB_HEADER HBRBHeader;
|
|
PHBRB_CAPABILITIES_HEADER HBRBCapHeader;
|
|
|
|
PAGED_CODE();
|
|
|
|
output = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, outputSize);
|
|
|
|
if (!output) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
RtlZeroMemory(&input, sizeof(ACPI_EVAL_INPUT_BUFFER));
|
|
RtlZeroMemory(output, outputSize);
|
|
|
|
//
|
|
// Send a IOCTL to ACPI to request it to run the HBRB method on this device
|
|
// if the method it is present
|
|
//
|
|
|
|
input.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
|
input.MethodNameAsUlong = (ULONG)'IHBH';
|
|
|
|
//
|
|
// HpsSendIoctl deals with sending this from the top of the stack.
|
|
//
|
|
|
|
status = HpsSendIoctl(DeviceExtension->Self,
|
|
IOCTL_ACPI_EVAL_METHOD,
|
|
&input,
|
|
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
|
output,
|
|
outputSize
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
//
|
|
// Check they are all integers and in the right bounds
|
|
//
|
|
ASSERT(output->Count == 1);
|
|
if ((output->Argument[0].Type != ACPI_METHOD_ARGUMENT_BUFFER) ||
|
|
(output->Argument[0].DataLength != sizeof(HPS_HWINIT_DESCRIPTOR))) {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto cleanup;
|
|
}
|
|
RtlCopyMemory(&DeviceExtension->HwInitData,
|
|
output->Argument[0].Data,
|
|
output->Argument[0].DataLength
|
|
);
|
|
|
|
cleanup:
|
|
|
|
if (output) {
|
|
ExFreePool(output);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HpsSendIoctl(
|
|
IN PDEVICE_OBJECT Device,
|
|
IN ULONG IoctlCode,
|
|
IN PVOID InputBuffer OPTIONAL,
|
|
IN ULONG InputBufferLength,
|
|
IN PVOID OutputBuffer OPTIONAL,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Builds and send an IOCTL to a device and return the results
|
|
|
|
Arguments:
|
|
|
|
Device - a device on the device stack to receive the IOCTL - the
|
|
irp is always sent to the top of the stack
|
|
|
|
IoctlCode - the IOCTL to run
|
|
|
|
InputBuffer - arguments to the IOCTL
|
|
|
|
InputBufferLength - length in bytes of the InputBuffer
|
|
|
|
OutputBuffer - data returned by the IOCTL
|
|
|
|
OnputBufferLength - the size in bytes of the OutputBuffer
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
KEVENT event;
|
|
PIRP irp;
|
|
PDEVICE_OBJECT targetDevice = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
|
|
|
//
|
|
// Get the top of the stack to send the IRP to
|
|
//
|
|
|
|
targetDevice = IoGetAttachedDeviceReference(Device);
|
|
|
|
if (!targetDevice) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Get Io to build the IRP for us
|
|
//
|
|
|
|
irp = IoBuildDeviceIoControlRequest(IoctlCode,
|
|
targetDevice,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength,
|
|
FALSE, // InternalDeviceIoControl
|
|
&event,
|
|
&ioStatus
|
|
);
|
|
|
|
|
|
if (!irp) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Send the IRP and wait for it to complete
|
|
//
|
|
|
|
status = IoCallDriver(targetDevice, irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
status = ioStatus.Status;
|
|
}
|
|
|
|
exit:
|
|
|
|
if (targetDevice) {
|
|
ObDereferenceObject(targetDevice);
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
VOID
|
|
HpsMemoryInterfaceReference(
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PHPS_DEVICE_EXTENSION Extension = (PHPS_DEVICE_EXTENSION)Context;
|
|
|
|
if (InterlockedExchangeAdd(&Extension->MemoryInterfaceCount,1) == 0) {
|
|
|
|
//
|
|
// This is the first increment. Put this device extension on the
|
|
// list of device extensions.
|
|
//
|
|
InsertHeadList(&HpsDeviceExtensions,&Extension->ListEntry);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HpsMemoryInterfaceDereference(
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PHPS_DEVICE_EXTENSION Extension = (PHPS_DEVICE_EXTENSION)Context;
|
|
LONG decrementedValue;
|
|
|
|
decrementedValue = InterlockedDecrement(&Extension->MemoryInterfaceCount);
|
|
|
|
ASSERT(decrementedValue >= 0);
|
|
|
|
if (decrementedValue == 0) {
|
|
|
|
//
|
|
// This is the final decrement. Remove the device extension from the list
|
|
//
|
|
RemoveEntryList(&Extension->ListEntry);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HpsReadRegister(
|
|
IN PUCHAR Register,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
)
|
|
{
|
|
PHPS_DEVICE_EXTENSION extension;
|
|
ULONG offset;
|
|
|
|
extension = HpsFindExtensionForHbrb(Register,Length);
|
|
|
|
offset = (ULONG)(Register - extension->HBRBOffset);
|
|
|
|
if ((offset < extension->HBRBLength) &&
|
|
((offset+Length) <= extension->HBRBLength)) {
|
|
|
|
RtlCopyMemory(Buffer,(PUCHAR)extension->HBRB + offset,Length);
|
|
|
|
}
|
|
|
|
}
|
|
VOID
|
|
HpsWriteRegister(
|
|
IN PUCHAR Register,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
)
|
|
{
|
|
PHPS_DEVICE_EXTENSION extension;
|
|
ULONG hbrbOffset, shpcOffset, shpcLength, bufferOffset;
|
|
ULONG registerNum, registerOffset, registerLength, registerData;
|
|
KIRQL irql;
|
|
|
|
extension = HpsFindExtensionForHbrb(Register,Length);
|
|
|
|
HpsLockRegisterSet(extension,
|
|
&irql
|
|
);
|
|
|
|
hbrbOffset = (ULONG)(Register - extension->HBRBOffset);
|
|
|
|
if ((hbrbOffset < extension->HBRBLength) &&
|
|
((hbrbOffset+Length) <= extension->HBRBLength)) {
|
|
|
|
RtlCopyMemory((PUCHAR)extension->HBRB + hbrbOffset,Buffer,Length);
|
|
|
|
}
|
|
|
|
if ((hbrbOffset >= extension->HBRBRegisterSetOffset) &&
|
|
((hbrbOffset + Length) < (extension->HBRBRegisterSetOffset + sizeof(SHPC_REGISTER_SET)))) {
|
|
|
|
//
|
|
// The write is to the SHPC register set.
|
|
//
|
|
shpcOffset = hbrbOffset - extension->HBRBRegisterSetOffset;
|
|
shpcLength = Length;
|
|
|
|
bufferOffset = 0;
|
|
while (bufferOffset < Length) {
|
|
registerNum = shpcOffset / sizeof(ULONG);
|
|
registerOffset = shpcOffset - (registerNum * sizeof(ULONG));
|
|
registerLength = min(shpcLength,sizeof(ULONG)-registerOffset);
|
|
registerData = *(PULONG)((PUCHAR)Buffer + bufferOffset);
|
|
registerData <<= (registerOffset*8);
|
|
|
|
RegisterWriteCommands[registerNum](extension,
|
|
registerNum,
|
|
®isterData,
|
|
HPS_ULONG_WRITE_MASK(registerOffset,registerLength)
|
|
);
|
|
|
|
bufferOffset += registerLength;
|
|
shpcOffset += registerLength;
|
|
shpcLength -= registerLength;
|
|
}
|
|
}
|
|
|
|
RtlCopyMemory((PUCHAR)extension->HBRB + extension->HBRBRegisterSetOffset,
|
|
&extension->RegisterSet,
|
|
sizeof(SHPC_REGISTER_SET)
|
|
);
|
|
|
|
HpsUnlockRegisterSet(extension,
|
|
irql
|
|
);
|
|
|
|
}
|
|
|
|
PHPS_DEVICE_EXTENSION
|
|
HpsFindExtensionForHbrb(
|
|
IN PUCHAR Register,
|
|
IN ULONG Length
|
|
)
|
|
{
|
|
PHPS_DEVICE_EXTENSION currentExtension;
|
|
|
|
FOR_ALL_IN_LIST(HPS_DEVICE_EXTENSION,&HpsDeviceExtensions,currentExtension) {
|
|
|
|
if (IS_SUBSET(Register,Length,currentExtension->HBRBOffset,currentExtension->HBRBLength)) {
|
|
|
|
return currentExtension;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|