mirror of
https://github.com/reactos/reactos.git
synced 2024-10-31 03:48:17 +00:00
5cfc1e3152
CORE-13866
387 lines
12 KiB
C
387 lines
12 KiB
C
/*
|
|
* PROJECT: ReactOS Storport Driver
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Storport helper functions
|
|
* COPYRIGHT: Copyright 2017 Eric Kohl (eric.kohl@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
static
|
|
NTSTATUS
|
|
NTAPI
|
|
ForwardIrpAndWaitCompletion(
|
|
_In_ PDEVICE_OBJECT DeviceObject,
|
|
_In_ PIRP Irp,
|
|
_In_ PVOID Context)
|
|
{
|
|
if (Irp->PendingReturned)
|
|
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ForwardIrpAndWait(
|
|
_In_ PDEVICE_OBJECT LowerDevice,
|
|
_In_ PIRP Irp)
|
|
{
|
|
KEVENT Event;
|
|
NTSTATUS Status;
|
|
|
|
ASSERT(LowerDevice);
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
|
|
|
|
Status = IoCallDriver(LowerDevice, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
|
|
if (NT_SUCCESS(Status))
|
|
Status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ForwardIrpAndForget(
|
|
_In_ PDEVICE_OBJECT LowerDevice,
|
|
_In_ PIRP Irp)
|
|
{
|
|
ASSERT(LowerDevice);
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(LowerDevice, Irp);
|
|
}
|
|
|
|
|
|
INTERFACE_TYPE
|
|
GetBusInterface(
|
|
PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
GUID Guid;
|
|
ULONG Length;
|
|
NTSTATUS Status;
|
|
|
|
Status = IoGetDeviceProperty(DeviceObject,
|
|
DevicePropertyBusTypeGuid,
|
|
sizeof(Guid),
|
|
&Guid,
|
|
&Length);
|
|
if (!NT_SUCCESS(Status))
|
|
return InterfaceTypeUndefined;
|
|
|
|
if (RtlCompareMemory(&Guid, &GUID_BUS_TYPE_PCMCIA, sizeof(GUID)) == sizeof(GUID))
|
|
return PCMCIABus;
|
|
else if (RtlCompareMemory(&Guid, &GUID_BUS_TYPE_PCI, sizeof(GUID)) == sizeof(GUID))
|
|
return PCIBus;
|
|
else if (RtlCompareMemory(&Guid, &GUID_BUS_TYPE_ISAPNP, sizeof(GUID)) == sizeof(GUID))
|
|
return PNPISABus;
|
|
|
|
return InterfaceTypeUndefined;
|
|
}
|
|
|
|
|
|
static
|
|
ULONG
|
|
GetResourceListSize(
|
|
PCM_RESOURCE_LIST ResourceList)
|
|
{
|
|
PCM_FULL_RESOURCE_DESCRIPTOR Descriptor;
|
|
INT i;
|
|
ULONG Size;
|
|
|
|
DPRINT1("GetResourceListSize(%p)\n", ResourceList);
|
|
|
|
Size = sizeof(CM_RESOURCE_LIST);
|
|
if (ResourceList->Count == 0)
|
|
{
|
|
DPRINT1("Size: 0x%lx (%u)\n", Size, Size);
|
|
return Size;
|
|
}
|
|
|
|
DPRINT1("ResourceList->Count: %lu\n", ResourceList->Count);
|
|
|
|
Descriptor = &ResourceList->List[0];
|
|
for (i = 0; i < ResourceList->Count; i++)
|
|
{
|
|
/* Process resources in CM_FULL_RESOURCE_DESCRIPTOR block number ix. */
|
|
|
|
DPRINT1("PartialResourceList->Count: %lu\n", Descriptor->PartialResourceList.Count);
|
|
|
|
/* Add the size of the current full descriptor */
|
|
Size += sizeof(CM_FULL_RESOURCE_DESCRIPTOR) +
|
|
(Descriptor->PartialResourceList.Count - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|
|
|
/* Advance to next CM_FULL_RESOURCE_DESCRIPTOR block in memory. */
|
|
Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)(Descriptor->PartialResourceList.PartialDescriptors +
|
|
Descriptor->PartialResourceList.Count);
|
|
}
|
|
|
|
DPRINT1("Size: 0x%lx (%u)\n", Size, Size);
|
|
return Size;
|
|
}
|
|
|
|
|
|
PCM_RESOURCE_LIST
|
|
CopyResourceList(
|
|
POOL_TYPE PoolType,
|
|
PCM_RESOURCE_LIST Source)
|
|
{
|
|
PCM_RESOURCE_LIST Destination;
|
|
ULONG Size;
|
|
|
|
DPRINT1("CopyResourceList(%lu %p)\n",
|
|
PoolType, Source);
|
|
|
|
/* Get the size of the resource list */
|
|
Size = GetResourceListSize(Source);
|
|
|
|
/* Allocate a new buffer */
|
|
Destination = ExAllocatePoolWithTag(PoolType,
|
|
Size,
|
|
TAG_RESOURCE_LIST);
|
|
if (Destination == NULL)
|
|
return NULL;
|
|
|
|
/* Copy the resource list */
|
|
RtlCopyMemory(Destination,
|
|
Source,
|
|
Size);
|
|
|
|
return Destination;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
QueryBusInterface(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PGUID Guid,
|
|
USHORT Size,
|
|
USHORT Version,
|
|
PBUS_INTERFACE_STANDARD Interface,
|
|
PVOID InterfaceSpecificData)
|
|
{
|
|
KEVENT Event;
|
|
NTSTATUS Status;
|
|
PIRP Irp;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
PIO_STACK_LOCATION Stack;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
|
|
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
|
|
DeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&Event,
|
|
&IoStatus);
|
|
if (Irp == NULL)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
Stack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
Stack->MajorFunction = IRP_MJ_PNP;
|
|
Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
Stack->Parameters.QueryInterface.InterfaceType = Guid;
|
|
Stack->Parameters.QueryInterface.Size = Size;
|
|
Stack->Parameters.QueryInterface.Version = Version;
|
|
Stack->Parameters.QueryInterface.Interface = (PINTERFACE)Interface;
|
|
Stack->Parameters.QueryInterface.InterfaceSpecificData = InterfaceSpecificData;
|
|
|
|
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
Status = IoCallDriver(DeviceObject, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
|
|
Status=IoStatus.Status;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
TranslateResourceListAddress(
|
|
PFDO_DEVICE_EXTENSION DeviceExtension,
|
|
INTERFACE_TYPE BusType,
|
|
ULONG SystemIoBusNumber,
|
|
STOR_PHYSICAL_ADDRESS IoAddress,
|
|
ULONG NumberOfBytes,
|
|
BOOLEAN InIoSpace,
|
|
PPHYSICAL_ADDRESS TranslatedAddress)
|
|
{
|
|
PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptorA, FullDescriptorT;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorA, PartialDescriptorT;
|
|
INT i, j;
|
|
|
|
DPRINT1("TranslateResourceListAddress(%p)\n", DeviceExtension);
|
|
|
|
FullDescriptorA = DeviceExtension->AllocatedResources->List;
|
|
FullDescriptorT = DeviceExtension->TranslatedResources->List;
|
|
for (i = 0; i < DeviceExtension->AllocatedResources->Count; i++)
|
|
{
|
|
for (j = 0; j < FullDescriptorA->PartialResourceList.Count; j++)
|
|
{
|
|
PartialDescriptorA = FullDescriptorA->PartialResourceList.PartialDescriptors + j;
|
|
PartialDescriptorT = FullDescriptorT->PartialResourceList.PartialDescriptors + j;
|
|
|
|
switch (PartialDescriptorA->Type)
|
|
{
|
|
case CmResourceTypePort:
|
|
DPRINT1("Port: 0x%I64x (0x%lx)\n",
|
|
PartialDescriptorA->u.Port.Start.QuadPart,
|
|
PartialDescriptorA->u.Port.Length);
|
|
if (InIoSpace &&
|
|
IoAddress.QuadPart >= PartialDescriptorA->u.Port.Start.QuadPart &&
|
|
IoAddress.QuadPart + NumberOfBytes <= PartialDescriptorA->u.Port.Start.QuadPart + PartialDescriptorA->u.Port.Length)
|
|
{
|
|
TranslatedAddress->QuadPart = PartialDescriptorT->u.Port.Start.QuadPart +
|
|
(IoAddress.QuadPart - PartialDescriptorA->u.Port.Start.QuadPart);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeMemory:
|
|
DPRINT1("Memory: 0x%I64x (0x%lx)\n",
|
|
PartialDescriptorA->u.Memory.Start.QuadPart,
|
|
PartialDescriptorA->u.Memory.Length);
|
|
if (!InIoSpace &&
|
|
IoAddress.QuadPart >= PartialDescriptorA->u.Memory.Start.QuadPart &&
|
|
IoAddress.QuadPart + NumberOfBytes <= PartialDescriptorA->u.Memory.Start.QuadPart + PartialDescriptorA->u.Memory.Length)
|
|
{
|
|
TranslatedAddress->QuadPart = PartialDescriptorT->u.Memory.Start.QuadPart +
|
|
(IoAddress.QuadPart - PartialDescriptorA->u.Memory.Start.QuadPart);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Advance to next CM_FULL_RESOURCE_DESCRIPTOR block in memory. */
|
|
FullDescriptorA = (PCM_FULL_RESOURCE_DESCRIPTOR)(FullDescriptorA->PartialResourceList.PartialDescriptors +
|
|
FullDescriptorA->PartialResourceList.Count);
|
|
|
|
FullDescriptorT = (PCM_FULL_RESOURCE_DESCRIPTOR)(FullDescriptorT->PartialResourceList.PartialDescriptors +
|
|
FullDescriptorT->PartialResourceList.Count);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetResourceListInterrupt(
|
|
PFDO_DEVICE_EXTENSION DeviceExtension,
|
|
PULONG Vector,
|
|
PKIRQL Irql,
|
|
KINTERRUPT_MODE *InterruptMode,
|
|
PBOOLEAN ShareVector,
|
|
PKAFFINITY Affinity)
|
|
{
|
|
PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
|
|
INT i, j;
|
|
|
|
DPRINT1("GetResourceListInterrupt(%p)\n",
|
|
DeviceExtension);
|
|
|
|
FullDescriptor = DeviceExtension->TranslatedResources->List;
|
|
for (i = 0; i < DeviceExtension->TranslatedResources->Count; i++)
|
|
{
|
|
for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
|
|
{
|
|
PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors + j;
|
|
|
|
switch (PartialDescriptor->Type)
|
|
{
|
|
case CmResourceTypeInterrupt:
|
|
DPRINT1("Interrupt: Level %lu Vector %lu\n",
|
|
PartialDescriptor->u.Interrupt.Level,
|
|
PartialDescriptor->u.Interrupt.Vector);
|
|
|
|
*Vector = PartialDescriptor->u.Interrupt.Vector;
|
|
*Irql = (KIRQL)PartialDescriptor->u.Interrupt.Level;
|
|
*InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
|
|
*ShareVector = (PartialDescriptor->ShareDisposition == CmResourceShareShared) ? TRUE : FALSE;
|
|
*Affinity = PartialDescriptor->u.Interrupt.Affinity;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* Advance to next CM_FULL_RESOURCE_DESCRIPTOR block in memory. */
|
|
FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)(FullDescriptor->PartialResourceList.PartialDescriptors +
|
|
FullDescriptor->PartialResourceList.Count);
|
|
}
|
|
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AllocateAddressMapping(
|
|
PMAPPED_ADDRESS *MappedAddressList,
|
|
STOR_PHYSICAL_ADDRESS IoAddress,
|
|
PVOID MappedAddress,
|
|
ULONG NumberOfBytes,
|
|
ULONG BusNumber)
|
|
{
|
|
PMAPPED_ADDRESS Mapping;
|
|
|
|
DPRINT1("AllocateAddressMapping()\n");
|
|
|
|
Mapping = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(MAPPED_ADDRESS),
|
|
TAG_ADDRESS_MAPPING);
|
|
if (Mapping == NULL)
|
|
{
|
|
DPRINT1("No memory!\n");
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
RtlZeroMemory(Mapping, sizeof(MAPPED_ADDRESS));
|
|
|
|
Mapping->NextMappedAddress = *MappedAddressList;
|
|
*MappedAddressList = Mapping;
|
|
|
|
Mapping->IoAddress = IoAddress;
|
|
Mapping->MappedAddress = MappedAddress;
|
|
Mapping->NumberOfBytes = NumberOfBytes;
|
|
Mapping->BusNumber = BusNumber;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#if defined(_M_AMD64)
|
|
/* KeQuerySystemTime is an inline function,
|
|
so we cannot forward the export to ntoskrnl */
|
|
STORPORT_API
|
|
VOID
|
|
NTAPI
|
|
StorPortQuerySystemTime(
|
|
_Out_ PLARGE_INTEGER CurrentTime)
|
|
{
|
|
KeQuerySystemTime(CurrentTime);
|
|
}
|
|
#endif /* defined(_M_AMD64) */
|
|
|
|
/* EOF */
|