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.
432 lines
11 KiB
432 lines
11 KiB
#include "spsim.h"
|
|
#include "spsimioct.h"
|
|
|
|
NTSTATUS
|
|
SpSimCreateStaOpRegion(
|
|
IN PSPSIM_EXTENSION SpSim
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Retrieves information to construct the STA array that tells us
|
|
what devices we control the _STA on
|
|
|
|
Arguments:
|
|
|
|
SpSim - device extension
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ACPI_EVAL_INPUT_BUFFER input;
|
|
PACPI_EVAL_OUTPUT_BUFFER output = NULL;
|
|
ULONG i;
|
|
PACPI_METHOD_ARGUMENT argument;
|
|
//
|
|
// Allocate a buffer big enough for all possible slots
|
|
//
|
|
|
|
ULONG outputSize = sizeof(ACPI_EVAL_OUTPUT_BUFFER);
|
|
|
|
PAGED_CODE();
|
|
|
|
output = ExAllocatePool(PagedPool, outputSize);
|
|
|
|
if (!output) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Send a IOCTL to ACPI to request evaluate the
|
|
// SPSIM_STA_NAMES_METHOD under this object if present.
|
|
//
|
|
|
|
RtlZeroMemory(&input, sizeof(ACPI_EVAL_INPUT_BUFFER));
|
|
input.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
|
input.MethodNameAsUlong = SPSIM_STA_NAMES_METHOD;
|
|
|
|
status = SpSimSendIoctl(SpSim->PhysicalDeviceObject,
|
|
IOCTL_ACPI_EVAL_METHOD,
|
|
&input,
|
|
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
|
output,
|
|
outputSize
|
|
);
|
|
if (status == STATUS_BUFFER_OVERFLOW) {
|
|
outputSize = output->Length;
|
|
ExFreePool(output);
|
|
output = ExAllocatePool(PagedPool, outputSize);
|
|
|
|
if (!output) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
status = SpSimSendIoctl(SpSim->PhysicalDeviceObject,
|
|
IOCTL_ACPI_EVAL_METHOD,
|
|
&input,
|
|
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
|
output,
|
|
outputSize
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
argument = output->Argument;
|
|
for (i = 0; i < output->Count; i++) {
|
|
if (argument->Type != ACPI_METHOD_ARGUMENT_STRING) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
argument = ACPI_METHOD_NEXT_ARGUMENT(argument);
|
|
}
|
|
SpSim->StaOpRegionValues = ExAllocatePool(NonPagedPool,
|
|
sizeof(UCHAR) * output->Count);
|
|
if (SpSim->StaOpRegionValues == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
SpSim->StaNames = output;
|
|
SpSim->StaCount = output->Count;
|
|
RtlZeroMemory(SpSim->StaOpRegionValues,
|
|
sizeof(UCHAR) * SpSim->StaCount);
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ExFreePool(output);
|
|
SpSim->StaOpRegionValues = NULL;
|
|
SpSim->StaNames = NULL;
|
|
SpSim->StaCount = 0;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
SpSimDeleteStaOpRegion(
|
|
IN PSPSIM_EXTENSION SpSim
|
|
)
|
|
{
|
|
if (SpSim->StaNames) {
|
|
ExFreePool(SpSim->StaNames);
|
|
SpSim->StaNames = NULL;
|
|
}
|
|
|
|
if (SpSim->StaOpRegionValues) {
|
|
ExFreePool(SpSim->StaOpRegionValues);
|
|
SpSim->StaOpRegionValues = NULL;
|
|
}
|
|
}
|
|
NTSTATUS
|
|
SpSimGetDeviceName(
|
|
PSPSIM_EXTENSION SpSim,
|
|
PIRP Irp,
|
|
PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PSPSIM_DEVICE_NAME name;
|
|
PACPI_METHOD_ARGUMENT argument;
|
|
PUCHAR source;
|
|
PWCHAR dest;
|
|
ULONG remainingBuffer, i, nameSize;
|
|
|
|
if (Irp->AssociatedIrp.SystemBuffer == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (SpSim->StaNames == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
name = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (name->Device >= SpSim->StaCount) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SPSIM_DEVICE_NAME)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
argument = SpSim->StaNames->Argument;
|
|
i = 0;
|
|
while (i != name->Device) {
|
|
argument = ACPI_METHOD_NEXT_ARGUMENT(argument);
|
|
i++;
|
|
}
|
|
|
|
nameSize = argument->DataLength * sizeof(WCHAR);
|
|
name->DeviceNameLength = argument->DataLength;
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(SPSIM_DEVICE_NAME) + (nameSize - sizeof(WCHAR)))) {
|
|
Irp->IoStatus.Information = sizeof(SPSIM_DEVICE_NAME);
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
source = argument->Data;
|
|
dest = name->DeviceName;
|
|
while(*source) {
|
|
*dest++ = (WCHAR) *source++;
|
|
}
|
|
*dest = UNICODE_NULL;
|
|
Irp->IoStatus.Information = sizeof(SPSIM_DEVICE_NAME) - sizeof(WCHAR) +
|
|
nameSize;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
NTSTATUS
|
|
SpSimGetManagedDevicesIoctl(
|
|
PSPSIM_EXTENSION SpSim,
|
|
PIRP Irp,
|
|
PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PACPI_METHOD_ARGUMENT argument;
|
|
PSPSIM_MANAGED_DEVICES managed;
|
|
ULONG i, outputSize;
|
|
PUCHAR current;
|
|
NTSTATUS status;
|
|
|
|
if (Irp->AssociatedIrp.SystemBuffer == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (SpSim->StaOpRegionValues == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SPSIM_MANAGED_DEVICES)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
managed = Irp->AssociatedIrp.SystemBuffer;
|
|
managed->Count = SpSim->StaCount;
|
|
|
|
outputSize = (sizeof(SPSIM_MANAGED_DEVICES) - sizeof(UCHAR)) +
|
|
SpSim->StaCount * sizeof(UCHAR);
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < outputSize) {
|
|
Irp->IoStatus.Information = sizeof(SPSIM_MANAGED_DEVICES);
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
RtlCopyMemory(managed->StaValues,
|
|
SpSim->StaOpRegionValues,
|
|
SpSim->StaCount);
|
|
|
|
Irp->IoStatus.Information = outputSize;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpSimStaOpRegionReadWrite(
|
|
PSPSIM_EXTENSION SpSim,
|
|
ULONG AccessType,
|
|
ULONG Offset,
|
|
ULONG Size,
|
|
PUCHAR Data
|
|
)
|
|
{
|
|
ULONG i;
|
|
PUCHAR current;
|
|
|
|
if (SpSim->StaOpRegionValues == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Offset >= SpSim->StaCount) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Offset + Size > SpSim->StaCount) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ASSERT(Offset < SpSim->StaCount);
|
|
|
|
current = SpSim->StaOpRegionValues + Offset;
|
|
|
|
if (AccessType & ACPI_OPREGION_WRITE) {
|
|
for (i = 0 ; i < Size; i++) {
|
|
*current++ = *Data++;
|
|
}
|
|
} else {
|
|
for (i = 0 ; i < Size; i++) {
|
|
*Data++ = *current++;
|
|
}
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
EXPORT
|
|
SpSimStaOpRegionHandler (
|
|
ULONG AccessType,
|
|
PVOID OpRegion,
|
|
ULONG Address,
|
|
ULONG Size,
|
|
PULONG Data,
|
|
ULONG_PTR Context,
|
|
PACPI_OPREGION_CALLBACK CompletionHandler,
|
|
PVOID CompletionContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles requests to service the
|
|
SPSIM operation region contained within this driver
|
|
|
|
Arguments:
|
|
|
|
AccessType - Read or Write data
|
|
OpRegion - Operation region object
|
|
Address - Address within the EC address space
|
|
Size - Number of bytes to transfer
|
|
Data - Data buffer to transfer to/from
|
|
Context - SpSim
|
|
CompletionHandler - AMLI handler to call when operation is complete
|
|
CompletionContext - Context to pass to the AMLI handler
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = SpSimStaOpRegionReadWrite((PSPSIM_EXTENSION) Context,
|
|
AccessType,
|
|
Address,
|
|
Size,
|
|
(PUCHAR)Data);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpSimInstallStaOpRegionHandler(
|
|
IN OUT PSPSIM_EXTENSION SpSim
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This calls the ACPI driver to install itself as the op region
|
|
handler for the STA region. It also allocates the memory for the
|
|
opregion itself.
|
|
|
|
Arguments:
|
|
|
|
pSpSimData - Pointer to the SpSim extension
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status=RegisterOpRegionHandler (
|
|
SpSim->AttachedDevice,
|
|
ACPI_OPREGION_ACCESS_AS_COOKED,
|
|
STA_OPREGION,
|
|
SpSimStaOpRegionHandler,
|
|
SpSim,
|
|
0,
|
|
&SpSim->StaOpRegion
|
|
);
|
|
|
|
//
|
|
// Check the status code
|
|
//
|
|
if(!NT_SUCCESS(status)) {
|
|
SpSim->StaOpRegion = NULL;
|
|
DbgPrint("Not successful in installing:=%x\n", status);
|
|
return status;
|
|
}
|
|
|
|
// XXXX
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpSimRemoveStaOpRegionHandler (
|
|
IN OUT PSPSIM_EXTENSION SpSim
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Uninstalls itself as the opregion handler.
|
|
|
|
Arguments:
|
|
|
|
SpSim - Pointer to the SpSim extension
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIRP irp;
|
|
|
|
if (SpSim->StaOpRegion != NULL) {
|
|
status = DeRegisterOpRegionHandler (
|
|
SpSim->AttachedDevice,
|
|
SpSim->StaOpRegion
|
|
);
|
|
SpSim->StaOpRegion = NULL;
|
|
} else {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SpSimAccessStaIoctl(
|
|
PSPSIM_EXTENSION SpSim,
|
|
PIRP Irp,
|
|
PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PSPSIM_ACCESS_STA access;
|
|
NTSTATUS status;
|
|
ULONG accessType;
|
|
|
|
if (Irp->AssociatedIrp.SystemBuffer == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (SpSim->StaNames == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SPSIM_ACCESS_STA)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
access = Irp->AssociatedIrp.SystemBuffer;
|
|
accessType = access->WriteOperation ? ACPI_OPREGION_WRITE :
|
|
ACPI_OPREGION_READ;
|
|
status = SpSimStaOpRegionReadWrite(SpSim,
|
|
accessType,
|
|
access->Device,
|
|
sizeof(UCHAR),
|
|
&access->StaValue);
|
|
if (NT_SUCCESS(status)) {
|
|
Irp->IoStatus.Information = sizeof(SPSIM_ACCESS_STA);
|
|
} else {
|
|
Irp->IoStatus.Information = 0;
|
|
}
|
|
return status;
|
|
}
|