mirror of
https://github.com/reactos/reactos.git
synced 2024-08-26 05:08:39 +00:00
482 lines
13 KiB
C
482 lines
13 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: PCI IDE bus driver extension
|
|
* FILE: drivers/storage/pciidex/fdo.c
|
|
* PURPOSE: IRP_MJ_PNP operations for FDOs
|
|
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
|
|
*/
|
|
|
|
#include "pciidex.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#include <initguid.h>
|
|
#include <wdmguid.h>
|
|
|
|
static NTSTATUS
|
|
GetBusInterface(
|
|
IN PFDO_DEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
PBUS_INTERFACE_STANDARD BusInterface = NULL;
|
|
KEVENT Event;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION Stack;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
if (DeviceExtension->BusInterface)
|
|
{
|
|
DPRINT("We already have the bus interface\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
BusInterface = ExAllocatePool(PagedPool, sizeof(BUS_INTERFACE_STANDARD));
|
|
if (!BusInterface)
|
|
{
|
|
DPRINT("ExAllocatePool() failed\n");
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
|
|
Irp = IoBuildSynchronousFsdRequest(
|
|
IRP_MJ_PNP,
|
|
DeviceExtension->LowerDevice,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&Event,
|
|
&IoStatus);
|
|
if (!Irp)
|
|
{
|
|
DPRINT("IoBuildSynchronousFsdRequest() failed\n");
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
Stack = IoGetNextIrpStackLocation(Irp);
|
|
Stack->MajorFunction = IRP_MJ_PNP;
|
|
Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;
|
|
Stack->Parameters.QueryInterface.Version = 1;
|
|
Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
|
|
Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
|
|
Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
|
|
|
Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
|
Status = IoStatus.Status;
|
|
}
|
|
if (!NT_SUCCESS(Status))
|
|
goto cleanup;
|
|
|
|
DeviceExtension->BusInterface = BusInterface;
|
|
BusInterface = NULL;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
cleanup:
|
|
if (BusInterface) ExFreePool(BusInterface);
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS
|
|
ReleaseBusInterface(
|
|
IN PFDO_DEVICE_EXTENSION DeviceExtension)
|
|
{
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
if (DeviceExtension->BusInterface)
|
|
{
|
|
(*DeviceExtension->BusInterface->InterfaceDereference)(
|
|
DeviceExtension->BusInterface->Context);
|
|
DeviceExtension->BusInterface = NULL;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
PciIdeXAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo)
|
|
{
|
|
PPCIIDEX_DRIVER_EXTENSION DriverExtension;
|
|
PFDO_DEVICE_EXTENSION DeviceExtension;
|
|
PDEVICE_OBJECT Fdo;
|
|
ULONG BytesRead;
|
|
PCI_COMMON_CONFIG PciConfig;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("PciIdeXAddDevice(%p %p)\n", DriverObject, Pdo);
|
|
|
|
DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
|
|
ASSERT(DriverExtension);
|
|
|
|
Status = IoCreateDevice(
|
|
DriverObject,
|
|
sizeof(FDO_DEVICE_EXTENSION) + DriverExtension->MiniControllerExtensionSize,
|
|
NULL,
|
|
FILE_DEVICE_BUS_EXTENDER,
|
|
FILE_DEVICE_SECURE_OPEN,
|
|
TRUE,
|
|
&Fdo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
|
|
RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));
|
|
|
|
DeviceExtension->Common.IsFDO = TRUE;
|
|
|
|
Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
Status = GetBusInterface(DeviceExtension);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("GetBusInterface() failed with status 0x%08lx\n", Status);
|
|
IoDetachDevice(DeviceExtension->LowerDevice);
|
|
return Status;
|
|
}
|
|
|
|
BytesRead = (*DeviceExtension->BusInterface->GetBusData)(
|
|
DeviceExtension->BusInterface->Context,
|
|
PCI_WHICHSPACE_CONFIG,
|
|
&PciConfig,
|
|
0,
|
|
PCI_COMMON_HDR_LENGTH);
|
|
if (BytesRead != PCI_COMMON_HDR_LENGTH)
|
|
{
|
|
DPRINT("BusInterface->GetBusData() failed()\n");
|
|
ReleaseBusInterface(DeviceExtension);
|
|
IoDetachDevice(DeviceExtension->LowerDevice);
|
|
return STATUS_IO_DEVICE_ERROR;
|
|
}
|
|
|
|
DeviceExtension->VendorId = PciConfig.VendorID;
|
|
DeviceExtension->DeviceId = PciConfig.DeviceID;
|
|
|
|
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static NTSTATUS NTAPI
|
|
PciIdeXUdmaModesSupported(
|
|
IN IDENTIFY_DATA IdentifyData,
|
|
OUT PULONG BestXferMode,
|
|
OUT PULONG CurrentXferMode)
|
|
{
|
|
ULONG Best = PIO_MODE0;
|
|
ULONG Current = PIO_MODE0;
|
|
|
|
DPRINT("PciIdeXUdmaModesSupported(%lu, %p %p)\n",
|
|
IdentifyData, BestXferMode, CurrentXferMode);
|
|
|
|
/* FIXME: if current mode is a PIO mode, how to get it?
|
|
* At the moment, PIO_MODE0 is always returned...
|
|
*/
|
|
|
|
if (IdentifyData.TranslationFieldsValid & 0x2)
|
|
{
|
|
/* PIO modes and some DMA modes are supported */
|
|
if (IdentifyData.AdvancedPIOModes & 0x10)
|
|
Best = PIO_MODE4;
|
|
else if (IdentifyData.AdvancedPIOModes & 0x8)
|
|
Best = PIO_MODE3;
|
|
else if (IdentifyData.AdvancedPIOModes & 0x4)
|
|
Best = PIO_MODE2;
|
|
else if (IdentifyData.AdvancedPIOModes & 0x2)
|
|
Best = PIO_MODE1;
|
|
else if (IdentifyData.AdvancedPIOModes & 0x1)
|
|
Best = PIO_MODE0;
|
|
|
|
if (IdentifyData.SingleWordDMASupport & 0x4)
|
|
Best = SWDMA_MODE2;
|
|
else if (IdentifyData.SingleWordDMASupport & 0x2)
|
|
Best = SWDMA_MODE1;
|
|
else if (IdentifyData.SingleWordDMASupport & 0x1)
|
|
Best = SWDMA_MODE0;
|
|
|
|
if (IdentifyData.SingleWordDMAActive & 0x4)
|
|
Current = SWDMA_MODE2;
|
|
else if (IdentifyData.SingleWordDMAActive & 0x2)
|
|
Current = SWDMA_MODE1;
|
|
else if (IdentifyData.SingleWordDMAActive & 0x1)
|
|
Current = SWDMA_MODE0;
|
|
|
|
if (IdentifyData.MultiWordDMASupport & 0x4)
|
|
Best = MWDMA_MODE2;
|
|
else if (IdentifyData.MultiWordDMASupport & 0x2)
|
|
Best = MWDMA_MODE1;
|
|
else if (IdentifyData.MultiWordDMASupport & 0x1)
|
|
Best = MWDMA_MODE0;
|
|
|
|
if (IdentifyData.MultiWordDMAActive & 0x4)
|
|
Current = MWDMA_MODE2;
|
|
else if (IdentifyData.MultiWordDMAActive & 0x2)
|
|
Current = MWDMA_MODE1;
|
|
else if (IdentifyData.MultiWordDMAActive & 0x1)
|
|
Current = MWDMA_MODE0;
|
|
}
|
|
|
|
if (IdentifyData.TranslationFieldsValid & 0x4)
|
|
{
|
|
/* UDMA modes are supported */
|
|
if (IdentifyData.UltraDMAActive & 0x10)
|
|
Current = UDMA_MODE4;
|
|
else if (IdentifyData.UltraDMAActive & 0x8)
|
|
Current = UDMA_MODE3;
|
|
else if (IdentifyData.UltraDMAActive & 0x4)
|
|
Current = UDMA_MODE2;
|
|
else if (IdentifyData.UltraDMAActive & 0x2)
|
|
Current = UDMA_MODE1;
|
|
else if (IdentifyData.UltraDMAActive & 0x1)
|
|
Current = UDMA_MODE0;
|
|
|
|
if (IdentifyData.UltraDMASupport & 0x10)
|
|
Best = UDMA_MODE4;
|
|
else if (IdentifyData.UltraDMASupport & 0x8)
|
|
Best = UDMA_MODE3;
|
|
else if (IdentifyData.UltraDMASupport & 0x4)
|
|
Best = UDMA_MODE2;
|
|
else if (IdentifyData.UltraDMASupport & 0x2)
|
|
Best = UDMA_MODE1;
|
|
else if (IdentifyData.UltraDMASupport & 0x1)
|
|
Best = UDMA_MODE0;
|
|
}
|
|
|
|
*BestXferMode = Best;
|
|
*CurrentXferMode = Current;
|
|
return TRUE;
|
|
}
|
|
|
|
static NTSTATUS
|
|
PciIdeXFdoStartDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PPCIIDEX_DRIVER_EXTENSION DriverExtension;
|
|
PFDO_DEVICE_EXTENSION DeviceExtension;
|
|
PCM_RESOURCE_LIST ResourceList;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("PciIdeXStartDevice(%p %p)\n", DeviceObject, Irp);
|
|
|
|
DriverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, DeviceObject->DriverObject);
|
|
ASSERT(DriverExtension);
|
|
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
ASSERT(DeviceExtension);
|
|
ASSERT(DeviceExtension->Common.IsFDO);
|
|
|
|
DeviceExtension->Properties.Size = sizeof(IDE_CONTROLLER_PROPERTIES);
|
|
DeviceExtension->Properties.ExtensionSize = DriverExtension->MiniControllerExtensionSize;
|
|
Status = DriverExtension->HwGetControllerProperties(
|
|
DeviceExtension->MiniControllerExtension,
|
|
&DeviceExtension->Properties);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
DriverExtension->HwUdmaModesSupported = DeviceExtension->Properties.PciIdeUdmaModesSupported;
|
|
if (!DriverExtension->HwUdmaModesSupported)
|
|
/* This method is optional, so provide our own one */
|
|
DriverExtension->HwUdmaModesSupported = PciIdeXUdmaModesSupported;
|
|
|
|
/* Get bus master port base, if any */
|
|
ResourceList = IoGetCurrentIrpStackLocation(Irp)->Parameters.StartDevice.AllocatedResources;
|
|
if (ResourceList
|
|
&& ResourceList->Count == 1
|
|
&& ResourceList->List[0].PartialResourceList.Count == 1
|
|
&& ResourceList->List[0].PartialResourceList.Version == 1
|
|
&& ResourceList->List[0].PartialResourceList.Revision == 1
|
|
&& ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Type == CmResourceTypePort
|
|
&& ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length == 16)
|
|
{
|
|
DeviceExtension->BusMasterPortBase = ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static NTSTATUS
|
|
PciIdeXFdoQueryBusRelations(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
OUT PDEVICE_RELATIONS* pDeviceRelations)
|
|
{
|
|
PFDO_DEVICE_EXTENSION DeviceExtension;
|
|
PDEVICE_RELATIONS DeviceRelations = NULL;
|
|
PDEVICE_OBJECT Pdo;
|
|
PPDO_DEVICE_EXTENSION PdoDeviceExtension;
|
|
ULONG i, j;
|
|
ULONG PDOs = 0;
|
|
IDE_CHANNEL_STATE ChannelState;
|
|
NTSTATUS Status;
|
|
|
|
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
ASSERT(DeviceExtension);
|
|
ASSERT(DeviceExtension->Common.IsFDO);
|
|
|
|
for (i = 0; i < MAX_IDE_CHANNEL; i++)
|
|
{
|
|
if (DeviceExtension->Pdo[i])
|
|
{
|
|
PDOs++;
|
|
continue;
|
|
}
|
|
ChannelState = DeviceExtension->Properties.PciIdeChannelEnabled(
|
|
DeviceExtension->MiniControllerExtension, i);
|
|
if (ChannelState == ChannelDisabled)
|
|
{
|
|
DPRINT("Channel %lu is disabled\n", i);
|
|
continue;
|
|
}
|
|
|
|
/* Need to create a PDO */
|
|
Status = IoCreateDevice(
|
|
DeviceObject->DriverObject,
|
|
sizeof(PDO_DEVICE_EXTENSION),
|
|
NULL,
|
|
FILE_DEVICE_CONTROLLER,
|
|
FILE_AUTOGENERATED_DEVICE_NAME,
|
|
FALSE,
|
|
&Pdo);
|
|
if (!NT_SUCCESS(Status))
|
|
/* FIXME: handle error */
|
|
continue;
|
|
|
|
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
|
|
RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
|
|
PdoDeviceExtension->Common.IsFDO = FALSE;
|
|
PdoDeviceExtension->Channel = i;
|
|
PdoDeviceExtension->ControllerFdo = DeviceObject;
|
|
Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
|
|
Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
DeviceExtension->Pdo[i] = Pdo;
|
|
PDOs++;
|
|
}
|
|
|
|
if (PDOs == 0)
|
|
{
|
|
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
|
|
PagedPool,
|
|
sizeof(DEVICE_RELATIONS));
|
|
}
|
|
else
|
|
{
|
|
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
|
|
PagedPool,
|
|
sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (PDOs - 1));
|
|
}
|
|
if (!DeviceRelations)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
DeviceRelations->Count = PDOs;
|
|
for (i = 0, j = 0; i < MAX_IDE_CHANNEL; i++)
|
|
{
|
|
if (DeviceExtension->Pdo[i])
|
|
{
|
|
ObReferenceObject(DeviceExtension->Pdo[i]);
|
|
DeviceRelations->Objects[j++] = DeviceExtension->Pdo[i];
|
|
}
|
|
}
|
|
|
|
*pDeviceRelations = DeviceRelations;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS NTAPI
|
|
PciIdeXFdoPnpDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
ULONG MinorFunction;
|
|
PIO_STACK_LOCATION Stack;
|
|
ULONG_PTR Information = Irp->IoStatus.Information;
|
|
NTSTATUS Status;
|
|
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
MinorFunction = Stack->MinorFunction;
|
|
|
|
switch (MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE: /* 0x00 */
|
|
{
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
|
|
/* Call lower driver */
|
|
Status = ForwardIrpAndWait(DeviceObject, Irp);
|
|
if (NT_SUCCESS(Status))
|
|
Status = PciIdeXFdoStartDevice(DeviceObject, Irp);
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_REMOVE_DEVICE: /* 0x01 */
|
|
{
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
|
|
{
|
|
switch (Stack->Parameters.QueryDeviceRelations.Type)
|
|
{
|
|
case BusRelations:
|
|
{
|
|
PDEVICE_RELATIONS DeviceRelations = NULL;
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
|
|
Status = PciIdeXFdoQueryBusRelations(DeviceObject, &DeviceRelations);
|
|
Information = (ULONG_PTR)DeviceRelations;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
|
|
Stack->Parameters.QueryDeviceRelations.Type);
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */
|
|
{
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
|
|
Information |= PNP_DEVICE_NOT_DISABLEABLE;
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
|
|
{
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
|
|
return ForwardIrpAndForget(DeviceObject, Irp);
|
|
}
|
|
case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
|
|
{
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
|
|
return ForwardIrpAndForget(DeviceObject, Irp);
|
|
}
|
|
default:
|
|
{
|
|
DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", MinorFunction);
|
|
return ForwardIrpAndForget(DeviceObject, Irp);
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Information = Information;
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|