|
|
/*++
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; }
|