mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 02:25:17 +00:00
c0c57e2324
- Fix IRP handling, add missing IRP handlers - Specify the device name for DO - The legacy IRQ descriptor is edge-triggered - Improve pool tagging - Place the PNP code in a pageable section CORE-17256
507 lines
13 KiB
C
507 lines
13 KiB
C
/*
|
|
* PROJECT: PCI IDE bus driver extension
|
|
* LICENSE: See COPYING in the top level directory
|
|
* PURPOSE: IRP_MJ_PNP operations for FDOs
|
|
* COPYRIGHT: Copyright 2005 Hervé Poussineau <hpoussin@reactos.org>
|
|
* Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
|
|
*/
|
|
|
|
#include "pciidex.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
NTSTATUS
|
|
PciIdeXFdoParseResources(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
|
_In_ PCM_RESOURCE_LIST ResourcesTranslated)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR BusMasterDescriptor = NULL;
|
|
PVOID IoBase;
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (!ResourcesTranslated)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
for (i = 0; i < ResourcesTranslated->List[0].PartialResourceList.Count; ++i)
|
|
{
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
|
|
|
|
Descriptor = &ResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i];
|
|
switch (Descriptor->Type)
|
|
{
|
|
case CmResourceTypePort:
|
|
case CmResourceTypeMemory:
|
|
{
|
|
switch (Descriptor->u.Port.Length)
|
|
{
|
|
/* Bus master port base */
|
|
case 16:
|
|
{
|
|
if (!BusMasterDescriptor)
|
|
BusMasterDescriptor = Descriptor;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!BusMasterDescriptor)
|
|
return STATUS_DEVICE_CONFIGURATION_ERROR;
|
|
|
|
if ((BusMasterDescriptor->Type == CmResourceTypePort) &&
|
|
(BusMasterDescriptor->Flags & CM_RESOURCE_PORT_IO))
|
|
{
|
|
IoBase = (PVOID)(ULONG_PTR)BusMasterDescriptor->u.Port.Start.QuadPart;
|
|
}
|
|
else
|
|
{
|
|
IoBase = MmMapIoSpace(BusMasterDescriptor->u.Memory.Start, 16, MmNonCached);
|
|
if (!IoBase)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
FdoExtension->IoBaseMapped = TRUE;
|
|
}
|
|
FdoExtension->BusMasterPortBase = IoBase;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
NTSTATUS
|
|
PciIdeXFdoStartDevice(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
|
_In_ PIRP Irp)
|
|
{
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IoStack;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (!NT_VERIFY(IoForwardIrpSynchronously(FdoExtension->Ldo, Irp)))
|
|
{
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
Status = Irp->IoStatus.Status;
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
Status = PciIdeXFdoParseResources(FdoExtension,
|
|
IoStack->Parameters.StartDevice.AllocatedResourcesTranslated);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to parse resources 0x%lx\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
Status = PciIdeXStartMiniport(FdoExtension);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Miniport initialization failed 0x%lx\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
VOID
|
|
PciIdeXFdoFreeResources(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (FdoExtension->IoBaseMapped)
|
|
{
|
|
MmUnmapIoSpace(FdoExtension->BusMasterPortBase, 16);
|
|
FdoExtension->IoBaseMapped = FALSE;
|
|
}
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
NTSTATUS
|
|
PciIdeXFdoStopDevice(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
PciIdeXFdoFreeResources(FdoExtension);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
NTSTATUS
|
|
PciIdeXFdoRemoveDevice(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
|
_In_ PIRP Irp)
|
|
{
|
|
PPDO_DEVICE_EXTENSION PdoExtension;
|
|
NTSTATUS Status;
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
PciIdeXFdoFreeResources(FdoExtension);
|
|
|
|
ExAcquireFastMutex(&FdoExtension->DeviceSyncMutex);
|
|
|
|
for (i = 0; i < MAX_IDE_CHANNEL; ++i)
|
|
{
|
|
PdoExtension = FdoExtension->Channels[i];
|
|
|
|
if (PdoExtension)
|
|
{
|
|
IoDeleteDevice(PdoExtension->Common.Self);
|
|
|
|
FdoExtension->Channels[i] = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ExReleaseFastMutex(&FdoExtension->DeviceSyncMutex);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
Status = IoCallDriver(FdoExtension->Ldo, Irp);
|
|
|
|
IoDetachDevice(FdoExtension->Ldo);
|
|
IoDeleteDevice(FdoExtension->Common.Self);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
NTSTATUS
|
|
PciIdeXFdoQueryPnpDeviceState(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
|
_In_ PIRP Irp)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (FdoExtension->Common.PageFiles ||
|
|
FdoExtension->Common.HibernateFiles ||
|
|
FdoExtension->Common.DumpFiles)
|
|
{
|
|
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
PPDO_DEVICE_EXTENSION
|
|
PciIdeXPdoCreateDevice(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
|
_In_ ULONG ChannelNumber)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING DeviceName;
|
|
WCHAR DeviceNameBuffer[sizeof("\\Device\\Ide\\PciIde999Channel9-FFF")];
|
|
PDEVICE_OBJECT Pdo;
|
|
PPDO_DEVICE_EXTENSION PdoExtension;
|
|
ULONG Alignment;
|
|
static ULONG DeviceNumber = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
Status = RtlStringCbPrintfW(DeviceNameBuffer,
|
|
sizeof(DeviceNameBuffer),
|
|
L"\\Device\\Ide\\PciIde%uChannel%u-%x",
|
|
FdoExtension->ControllerNumber,
|
|
ChannelNumber,
|
|
DeviceNumber++);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
|
|
|
|
Status = IoCreateDevice(FdoExtension->Common.Self->DriverObject,
|
|
sizeof(*PdoExtension),
|
|
&DeviceName,
|
|
FILE_DEVICE_CONTROLLER,
|
|
FILE_DEVICE_SECURE_OPEN,
|
|
FALSE,
|
|
&Pdo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to create PDO 0x%lx\n", Status);
|
|
return NULL;
|
|
}
|
|
|
|
DPRINT("Created device object %p '%wZ'\n", Pdo, &DeviceName);
|
|
|
|
/* DMA buffers alignment */
|
|
Alignment = FdoExtension->Properties.AlignmentRequirement;
|
|
Alignment = max(Alignment, FdoExtension->Common.Self->AlignmentRequirement);
|
|
Alignment = max(Alignment, FILE_WORD_ALIGNMENT);
|
|
Pdo->AlignmentRequirement = Alignment;
|
|
|
|
PdoExtension = Pdo->DeviceExtension;
|
|
|
|
RtlZeroMemory(PdoExtension, sizeof(*PdoExtension));
|
|
PdoExtension->Common.Self = Pdo;
|
|
PdoExtension->Channel = ChannelNumber;
|
|
PdoExtension->ParentController = FdoExtension;
|
|
|
|
Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
return PdoExtension;
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
NTSTATUS
|
|
PciIdeXFdoQueryBusRelations(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
|
_In_ PIRP Irp)
|
|
{
|
|
PPDO_DEVICE_EXTENSION PdoExtension;
|
|
IDE_CHANNEL_STATE ChannelState;
|
|
PDEVICE_RELATIONS DeviceRelations;
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
DeviceRelations = ExAllocatePoolWithTag(PagedPool,
|
|
FIELD_OFFSET(DEVICE_RELATIONS,
|
|
Objects[MAX_IDE_CHANNEL]),
|
|
TAG_PCIIDEX);
|
|
if (!DeviceRelations)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
DeviceRelations->Count = 0;
|
|
|
|
ExAcquireFastMutex(&FdoExtension->DeviceSyncMutex);
|
|
|
|
for (i = 0; i < MAX_IDE_CHANNEL; ++i)
|
|
{
|
|
PdoExtension = FdoExtension->Channels[i];
|
|
|
|
/* Ignore disabled channels */
|
|
ChannelState = PciIdeXChannelState(FdoExtension, i);
|
|
if (ChannelState == ChannelDisabled)
|
|
{
|
|
if (PdoExtension)
|
|
{
|
|
PdoExtension->ReportedMissing = TRUE;
|
|
}
|
|
|
|
DPRINT("Channel %lu is disabled\n", i);
|
|
continue;
|
|
}
|
|
|
|
/* Need to create a PDO */
|
|
if (!PdoExtension)
|
|
{
|
|
PdoExtension = PciIdeXPdoCreateDevice(FdoExtension, i);
|
|
|
|
FdoExtension->Channels[i] = PdoExtension;
|
|
}
|
|
|
|
if (PdoExtension && !PdoExtension->ReportedMissing)
|
|
{
|
|
DeviceRelations->Objects[DeviceRelations->Count++] = PdoExtension->Common.Self;
|
|
ObReferenceObject(PdoExtension->Common.Self);
|
|
}
|
|
}
|
|
|
|
ExReleaseFastMutex(&FdoExtension->DeviceSyncMutex);
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
NTSTATUS
|
|
PciIdeXFdoQueryDeviceUsageNotification(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
|
_In_ PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
volatile LONG* Counter;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (!NT_VERIFY(IoForwardIrpSynchronously(FdoExtension->Ldo, Irp)))
|
|
{
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
Status = Irp->IoStatus.Status;
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
switch (IoStack->Parameters.UsageNotification.Type)
|
|
{
|
|
case DeviceUsageTypePaging:
|
|
Counter = &FdoExtension->Common.PageFiles;
|
|
break;
|
|
|
|
case DeviceUsageTypeHibernation:
|
|
Counter = &FdoExtension->Common.HibernateFiles;
|
|
break;
|
|
|
|
case DeviceUsageTypeDumpFile:
|
|
Counter = &FdoExtension->Common.DumpFiles;
|
|
break;
|
|
|
|
default:
|
|
return Status;
|
|
}
|
|
|
|
IoAdjustPagingPathCount(Counter, IoStack->Parameters.UsageNotification.InPath);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
CODE_SEG("PAGE")
|
|
NTSTATUS
|
|
PciIdeXFdoQueryInterface(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
|
_In_ PIO_STACK_LOCATION IoStack)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (IsEqualGUIDAligned(IoStack->Parameters.QueryInterface.InterfaceType,
|
|
&GUID_TRANSLATOR_INTERFACE_STANDARD))
|
|
{
|
|
CM_RESOURCE_TYPE ResourceType;
|
|
ULONG BusNumber;
|
|
|
|
ResourceType = (ULONG_PTR)IoStack->Parameters.QueryInterface.InterfaceSpecificData;
|
|
|
|
/* In native mode the IDE controller does not use any legacy interrupt resources */
|
|
if (FdoExtension->InNativeMode ||
|
|
ResourceType != CmResourceTypeInterrupt ||
|
|
IoStack->Parameters.QueryInterface.Size < sizeof(TRANSLATOR_INTERFACE))
|
|
{
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
return HalGetInterruptTranslator(PCIBus,
|
|
0,
|
|
InterfaceTypeUndefined,
|
|
sizeof(TRANSLATOR_INTERFACE),
|
|
IoStack->Parameters.QueryInterface.Version,
|
|
(PTRANSLATOR_INTERFACE)IoStack->
|
|
Parameters.QueryInterface.Interface,
|
|
&BusNumber);
|
|
}
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
CODE_SEG("PAGE")
|
|
NTSTATUS
|
|
PciIdeXFdoDispatchPnp(
|
|
_In_ PFDO_DEVICE_EXTENSION FdoExtension,
|
|
_Inout_ PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
switch (IoStack->MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE:
|
|
{
|
|
Status = PciIdeXFdoStartDevice(FdoExtension, Irp);
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
}
|
|
|
|
case IRP_MN_STOP_DEVICE:
|
|
{
|
|
Status = PciIdeXFdoStopDevice(FdoExtension);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
return PciIdeXFdoRemoveDevice(FdoExtension, Irp);
|
|
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE:
|
|
{
|
|
Status = PciIdeXFdoQueryPnpDeviceState(FdoExtension, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
{
|
|
if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
|
|
break;
|
|
|
|
Status = PciIdeXFdoQueryBusRelations(FdoExtension, Irp);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
}
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
|
|
{
|
|
Status = PciIdeXFdoQueryDeviceUsageNotification(FdoExtension, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_INTERFACE:
|
|
{
|
|
Status = PciIdeXFdoQueryInterface(FdoExtension, IoStack);
|
|
if (Status == STATUS_NOT_SUPPORTED)
|
|
break;
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(FdoExtension->Ldo, Irp);
|
|
}
|