3142 lines
92 KiB
C
3142 lines
92 KiB
C
/*++
|
|
|
|
Copyright (C) 1993-99 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
chanfdo.c
|
|
|
|
Abstract:
|
|
|
|
--*/
|
|
|
|
#include "ideport.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, ChannelAddDevice)
|
|
#pragma alloc_text(PAGE, ChannelAddChannel)
|
|
#pragma alloc_text(PAGE, ChannelStartDevice)
|
|
#pragma alloc_text(PAGE, ChannelStartChannel)
|
|
#pragma alloc_text(PAGE, ChannelCreateSymblicLinks)
|
|
#pragma alloc_text(PAGE, ChannelDeleteSymblicLinks)
|
|
#pragma alloc_text(PAGE, ChannelRemoveDevice)
|
|
#pragma alloc_text(PAGE, ChannelSurpriseRemoveDevice)
|
|
#pragma alloc_text(PAGE, ChannelStopDevice)
|
|
#pragma alloc_text(PAGE, ChannelRemoveChannel)
|
|
#pragma alloc_text(PAGE, ChannelQueryDeviceRelations)
|
|
#pragma alloc_text(PAGE, ChannelQueryBusRelation)
|
|
#pragma alloc_text(PAGE, ChannelQueryId)
|
|
#pragma alloc_text(PAGE, ChannelUsageNotification)
|
|
#pragma alloc_text(PAGE, DigestResourceList)
|
|
#pragma alloc_text(PAGE, ChannelQueryBusMasterInterface)
|
|
#pragma alloc_text(PAGE, ChannelQueryTransferModeInterface)
|
|
#pragma alloc_text(PAGE, ChannelUnbindBusMasterParent)
|
|
#pragma alloc_text(PAGE, ChannelQuerySyncAccessInterface)
|
|
#pragma alloc_text(PAGE, ChannelEnableInterrupt)
|
|
#pragma alloc_text(PAGE, ChannelDisableInterrupt)
|
|
#pragma alloc_text(PAGE, ChannelFilterResourceRequirements)
|
|
#pragma alloc_text(PAGE, ChannelQueryPnPDeviceState)
|
|
#pragma alloc_text(PAGE, ChannelQueryPcmciaParent)
|
|
|
|
#ifdef IDE_FILTER_PROMISE_TECH_RESOURCES
|
|
#pragma alloc_text(PAGE, ChannelFilterPromiseTechResourceRequirements)
|
|
#endif // IDE_FILTER_PROMISE_TECH_RESOURCES
|
|
|
|
#pragma alloc_text(NONPAGE, ChannelDeviceIoControl)
|
|
#pragma alloc_text(NONPAGE, ChannelRemoveDeviceCompletionRoutine)
|
|
#pragma alloc_text(NONPAGE, ChannelQueryIdCompletionRoutine)
|
|
#pragma alloc_text(NONPAGE, ChannelUsageNotificationCompletionRoutine)
|
|
#pragma alloc_text(NONPAGE, ChannelAcpiTransferModeSelect)
|
|
#pragma alloc_text(NONPAGE, ChannelRestoreTiming)
|
|
#pragma alloc_text(NONPAGE, ChannelStartDeviceCompletionRoutine)
|
|
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
static ULONG AtapiNextIdePortNumber = 0;
|
|
|
|
NTSTATUS
|
|
ChannelAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension;
|
|
|
|
return ChannelAddChannel(DriverObject,
|
|
PhysicalDeviceObject,
|
|
&fdoExtension);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ChannelAddChannel(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
OUT PFDO_EXTENSION *FdoExtension
|
|
)
|
|
{
|
|
PDEVICE_OBJECT functionalDeviceObject;
|
|
PFDO_EXTENSION fdoExtension;
|
|
PPDO_EXTENSION pdoExtension;
|
|
PDEVICE_OBJECT childDeviceObject;
|
|
ULONG deviceExtensionSize;
|
|
NTSTATUS status;
|
|
|
|
UNICODE_STRING deviceName;
|
|
WCHAR deviceNameBuffer[64];
|
|
|
|
PAGED_CODE();
|
|
|
|
swprintf(deviceNameBuffer, DEVICE_OJBECT_BASE_NAME L"\\IdePort%d", AtapiNextIdePortNumber);
|
|
RtlInitUnicodeString(&deviceName, deviceNameBuffer);
|
|
|
|
//
|
|
// We've been given the PhysicalDeviceObject for a IDE controller. Create the
|
|
// FunctionalDeviceObject. Our FDO will be nameless.
|
|
//
|
|
|
|
deviceExtensionSize = sizeof(FDO_EXTENSION) + sizeof(HW_DEVICE_EXTENSION);
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject, // our driver object
|
|
deviceExtensionSize, // size of our extension
|
|
&deviceName, // our name
|
|
FILE_DEVICE_CONTROLLER, // device type
|
|
FILE_DEVICE_SECURE_OPEN, // device characteristics
|
|
FALSE, // not exclusive
|
|
&functionalDeviceObject // store new device object here
|
|
);
|
|
|
|
if( !NT_SUCCESS( status )){
|
|
|
|
return status;
|
|
}
|
|
|
|
fdoExtension = (PFDO_EXTENSION)functionalDeviceObject->DeviceExtension;
|
|
RtlZeroMemory (fdoExtension, deviceExtensionSize);
|
|
|
|
|
|
fdoExtension->HwDeviceExtension = (PVOID)(fdoExtension + 1);
|
|
|
|
//
|
|
// We have our FunctionalDeviceObject, initialize it.
|
|
//
|
|
|
|
fdoExtension->AttacheePdo = PhysicalDeviceObject;
|
|
fdoExtension->DriverObject = DriverObject;
|
|
fdoExtension->DeviceObject = functionalDeviceObject;
|
|
|
|
// Dispatch Table
|
|
fdoExtension->DefaultDispatch = IdePortPassDownToNextDriver;
|
|
fdoExtension->PnPDispatchTable = FdoPnpDispatchTable;
|
|
fdoExtension->PowerDispatchTable = FdoPowerDispatchTable;
|
|
fdoExtension->WmiDispatchTable = FdoWmiDispatchTable;
|
|
|
|
//
|
|
// Now attach to the PDO we were given.
|
|
//
|
|
fdoExtension->AttacheeDeviceObject = IoAttachDeviceToDeviceStack (
|
|
functionalDeviceObject,
|
|
PhysicalDeviceObject
|
|
);
|
|
if (fdoExtension->AttacheeDeviceObject == NULL) {
|
|
|
|
//
|
|
// Couldn't attach. Delete the FDO.
|
|
//
|
|
|
|
IoDeleteDevice (functionalDeviceObject);
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
} else {
|
|
|
|
//
|
|
// fix up alignment requirement
|
|
//
|
|
functionalDeviceObject->AlignmentRequirement = fdoExtension->AttacheeDeviceObject->AlignmentRequirement;
|
|
if (functionalDeviceObject->AlignmentRequirement < 1) {
|
|
functionalDeviceObject->AlignmentRequirement = 1;
|
|
}
|
|
|
|
fdoExtension->IdePortNumber = AtapiNextIdePortNumber;
|
|
AtapiNextIdePortNumber++;
|
|
|
|
*FdoExtension = fdoExtension;
|
|
|
|
CLRMASK (functionalDeviceObject->Flags, DO_DEVICE_INITIALIZING);
|
|
}
|
|
|
|
DebugPrint((DBG_PNP, "DeviceObject %x returnd status %x from Addevice\n",
|
|
PhysicalDeviceObject, status));
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelStartDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
NTSTATUS status;
|
|
PFDO_EXTENSION fdoExtension;
|
|
PCM_RESOURCE_LIST resourceList;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
|
|
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
|
|
ULONG resourceListSize;
|
|
ULONG i;
|
|
PCM_RESOURCE_LIST resourceListForKeep = NULL;
|
|
PIRP newIrp;
|
|
KEVENT event;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
ULONG parentResourceListSize;
|
|
PCM_RESOURCE_LIST parentResourceList = NULL;
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
fdoExtension = (PFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
ASSERT (!(fdoExtension->FdoState & FDOS_STARTED));
|
|
|
|
resourceList = thisIrpSp->Parameters.StartDevice.AllocatedResourcesTranslated;
|
|
|
|
//
|
|
// TEMP CODE for the time without a real PCI driver.
|
|
//
|
|
resourceListSize = 0;
|
|
|
|
if (resourceList) {
|
|
|
|
fullResourceList = resourceList->List;
|
|
|
|
for (i=0; i<resourceList->Count; i++) {
|
|
|
|
ULONG partialResourceListSize;
|
|
|
|
partialResourceList = &(fullResourceList->PartialResourceList);
|
|
partialDescriptors = partialResourceList->PartialDescriptors;
|
|
|
|
partialResourceListSize = 0;
|
|
for (i=0; i<partialResourceList->Count; i++) {
|
|
|
|
partialResourceListSize += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|
|
|
if (partialDescriptors[i].Type == CmResourceTypeDeviceSpecific) {
|
|
|
|
partialResourceListSize += partialDescriptors[i].u.DeviceSpecificData.DataSize;
|
|
}
|
|
}
|
|
|
|
resourceListSize += partialResourceListSize +
|
|
FIELD_OFFSET (CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
|
|
|
|
fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (((UCHAR *) fullResourceList) + resourceListSize);
|
|
}
|
|
resourceListSize += FIELD_OFFSET (CM_RESOURCE_LIST, List);
|
|
}
|
|
|
|
parentResourceListSize = sizeof (CM_RESOURCE_LIST) - sizeof (CM_FULL_RESOURCE_DESCRIPTOR) +
|
|
FULL_RESOURCE_LIST_SIZE(3); // primary IO (2) + IRQ
|
|
parentResourceList = ExAllocatePool (PagedPool, parentResourceListSize);
|
|
|
|
if (!parentResourceList) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
}
|
|
|
|
RtlZeroMemory (parentResourceList, parentResourceListSize);
|
|
|
|
KeInitializeEvent(&event,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
newIrp = IoBuildDeviceIoControlRequest (
|
|
IOCTL_IDE_GET_RESOURCES_ALLOCATED,
|
|
fdoExtension->AttacheeDeviceObject,
|
|
parentResourceList,
|
|
parentResourceListSize,
|
|
parentResourceList,
|
|
parentResourceListSize,
|
|
TRUE,
|
|
&event,
|
|
&ioStatusBlock);
|
|
|
|
if (newIrp == NULL) {
|
|
|
|
DebugPrint ((0, "Unable to allocate irp to bind with busmaster parent\n"));
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
|
|
} else {
|
|
|
|
status = IoCallDriver(fdoExtension->AttacheeDeviceObject, newIrp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
status = KeWaitForSingleObject(&event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
parentResourceListSize = 0;
|
|
|
|
} else {
|
|
|
|
parentResourceListSize = (ULONG)ioStatusBlock.Information;
|
|
}
|
|
|
|
if (resourceListSize + parentResourceListSize) {
|
|
|
|
resourceListForKeep = ExAllocatePool (NonPagedPool, resourceListSize + parentResourceListSize);
|
|
|
|
} else {
|
|
|
|
resourceListForKeep = NULL;
|
|
}
|
|
|
|
if (resourceListForKeep) {
|
|
|
|
PUCHAR d;
|
|
|
|
resourceListForKeep->Count = 0;
|
|
d = (PUCHAR) resourceListForKeep->List;
|
|
|
|
if (resourceListSize) {
|
|
|
|
RtlCopyMemory (
|
|
d,
|
|
resourceList->List,
|
|
resourceListSize - FIELD_OFFSET (CM_RESOURCE_LIST, List)
|
|
);
|
|
|
|
resourceListForKeep->Count = resourceList->Count;
|
|
d += resourceListSize - FIELD_OFFSET (CM_RESOURCE_LIST, List);
|
|
}
|
|
|
|
if (parentResourceListSize) {
|
|
|
|
RtlCopyMemory (
|
|
d,
|
|
parentResourceList->List,
|
|
parentResourceListSize - FIELD_OFFSET (CM_RESOURCE_LIST, List)
|
|
);
|
|
|
|
resourceListForKeep->Count += parentResourceList->Count;
|
|
}
|
|
} else {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
}
|
|
|
|
KeInitializeEvent(&event,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS ;
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
ChannelStartDeviceCompletionRoutine,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
//
|
|
// Pass the irp along
|
|
//
|
|
status = IoCallDriver(fdoExtension->AttacheeDeviceObject, Irp);
|
|
|
|
//
|
|
// Wait for it to come back...
|
|
//
|
|
if (status == STATUS_PENDING) {
|
|
|
|
KeWaitForSingleObject(
|
|
&event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Grab back the 'real' status
|
|
//
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ExFreePool (resourceListForKeep);
|
|
goto GetOut;
|
|
}
|
|
|
|
|
|
status = ChannelStartChannel (fdoExtension,
|
|
resourceListForKeep);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ExFreePool (resourceListForKeep);
|
|
goto GetOut;
|
|
}
|
|
|
|
GetOut:
|
|
if (parentResourceList) {
|
|
|
|
ExFreePool (parentResourceList);
|
|
parentResourceList = NULL;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelStartDeviceCompletionRoutine(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp,
|
|
IN OUT PVOID Context
|
|
)
|
|
{
|
|
PKEVENT event = (PKEVENT) Context;
|
|
|
|
//
|
|
// Signal the event
|
|
//
|
|
KeSetEvent( event, IO_NO_INCREMENT, FALSE );
|
|
|
|
//
|
|
// Always return MORE_PROCESSING_REQUIRED
|
|
// will complete it later
|
|
//
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelStartChannel (
|
|
PFDO_EXTENSION FdoExtension,
|
|
PCM_RESOURCE_LIST ResourceListToKeep
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PLOGICAL_UNIT_EXTENSION logUnitExtension;
|
|
IDE_PATH_ID pathId;
|
|
POWER_STATE newState;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR irqPartialDescriptors;
|
|
ULONG i;
|
|
|
|
#if DBG
|
|
{
|
|
PCM_RESOURCE_LIST resourceList;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
|
|
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
|
|
ULONG resourceListSize;
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
resourceList = ResourceListToKeep;
|
|
fullResourceList = resourceList->List;
|
|
resourceListSize = 0;
|
|
|
|
DebugPrint ((1, "IdePort: Starting device: FDOe\n", FdoExtension));
|
|
|
|
for (i=0; i<resourceList->Count; i++) {
|
|
partialResourceList = &(fullResourceList->PartialResourceList);
|
|
partialDescriptors = fullResourceList->PartialResourceList.PartialDescriptors;
|
|
|
|
for (j=0; j<partialResourceList->Count; j++) {
|
|
if (partialDescriptors[j].Type == CmResourceTypePort) {
|
|
DebugPrint ((1, "IdePort: IO Port = 0x%x. Lenght = 0x%x\n", partialDescriptors[j].u.Port.Start.LowPart, partialDescriptors[j].u.Port.Length));
|
|
} else if (partialDescriptors[j].Type == CmResourceTypeInterrupt) {
|
|
DebugPrint ((1, "IdePort: Int Level = 0x%x. Int Vector = 0x%x\n", partialDescriptors[j].u.Interrupt.Level, partialDescriptors[j].u.Interrupt.Vector));
|
|
} else {
|
|
DebugPrint ((1, "IdePort: Unknown resource\n"));
|
|
}
|
|
}
|
|
fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + j);
|
|
}
|
|
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
//
|
|
// Analyze the resources we are getting
|
|
//
|
|
status = DigestResourceList (
|
|
&FdoExtension->IdeResource,
|
|
ResourceListToKeep,
|
|
&irqPartialDescriptors
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
|
|
} else {
|
|
|
|
PCONFIGURATION_INFORMATION configurationInformation;
|
|
configurationInformation = IoGetConfigurationInformation();
|
|
|
|
if (FdoExtension->IdeResource.AtdiskPrimaryClaimed) {
|
|
FdoExtension->HwDeviceExtension->PrimaryAddress = TRUE;
|
|
FdoExtension->HwDeviceExtension->SecondaryAddress = FALSE;
|
|
configurationInformation->AtDiskPrimaryAddressClaimed = TRUE;
|
|
}
|
|
|
|
if (FdoExtension->IdeResource.AtdiskSecondaryClaimed) {
|
|
FdoExtension->HwDeviceExtension->PrimaryAddress = FALSE;
|
|
FdoExtension->HwDeviceExtension->SecondaryAddress = TRUE;
|
|
configurationInformation->AtDiskSecondaryAddressClaimed = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Build io address structure.
|
|
//
|
|
AtapiBuildIoAddress(
|
|
FdoExtension->IdeResource.TranslatedCommandBaseAddress,
|
|
FdoExtension->IdeResource.TranslatedControlBaseAddress,
|
|
&FdoExtension->HwDeviceExtension->BaseIoAddress1,
|
|
&FdoExtension->HwDeviceExtension->BaseIoAddress2,
|
|
&FdoExtension->HwDeviceExtension->BaseIoAddress1Length,
|
|
&FdoExtension->HwDeviceExtension->BaseIoAddress2Length,
|
|
&FdoExtension->HwDeviceExtension->MaxIdeDevice,
|
|
&FdoExtension->HwDeviceExtension->MaxIdeTargetId);
|
|
|
|
//
|
|
// check for panasonic controller
|
|
//
|
|
FdoExtension->panasonicController =
|
|
IdePortIsThisAPanasonicPCMCIACard(FdoExtension);
|
|
|
|
newState.DeviceState = PowerSystemWorking;
|
|
status = IdePortIssueSetPowerState (
|
|
(PDEVICE_EXTENSION_HEADER) FdoExtension,
|
|
SystemPowerState,
|
|
newState,
|
|
TRUE // sync call
|
|
);
|
|
if (status == STATUS_INVALID_DEVICE_REQUEST) {
|
|
|
|
//
|
|
// The DeviceObject Below us does not support power irp,
|
|
// we will assume we are powered up
|
|
//
|
|
FdoExtension->SystemPowerState = PowerSystemWorking;
|
|
|
|
} else if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
newState.DeviceState = PowerDeviceD0;
|
|
status = IdePortIssueSetPowerState (
|
|
(PDEVICE_EXTENSION_HEADER) FdoExtension,
|
|
DevicePowerState,
|
|
newState,
|
|
TRUE // sync call
|
|
);
|
|
if (status == STATUS_INVALID_DEVICE_REQUEST) {
|
|
|
|
//
|
|
// The DeviceObject Below us does not support power irp,
|
|
// we will assume we are powered up
|
|
//
|
|
FdoExtension->DevicePowerState = PowerDeviceD0;
|
|
|
|
} else if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// Initialize "miniport" data structure
|
|
//
|
|
FdoExtension->HwDeviceExtension->InterruptMode = FdoExtension->IdeResource.InterruptMode;
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
//
|
|
// Get parent's interrupt interface
|
|
//
|
|
ChannelQueryInterruptInterface (
|
|
FdoExtension
|
|
);
|
|
|
|
#endif
|
|
//
|
|
// Connect our interrupt
|
|
//
|
|
if (irqPartialDescriptors) {
|
|
|
|
status = IoConnectInterrupt(&FdoExtension->InterruptObject,
|
|
(PKSERVICE_ROUTINE) IdePortInterrupt,
|
|
FdoExtension->DeviceObject,
|
|
(PKSPIN_LOCK) NULL,
|
|
irqPartialDescriptors->u.Interrupt.Vector,
|
|
(KIRQL) irqPartialDescriptors->u.Interrupt.Level,
|
|
(KIRQL) irqPartialDescriptors->u.Interrupt.Level,
|
|
irqPartialDescriptors->Flags & CM_RESOURCE_INTERRUPT_LATCHED ? Latched : LevelSensitive,
|
|
(BOOLEAN) (irqPartialDescriptors->ShareDisposition == CmResourceShareShared),
|
|
irqPartialDescriptors->u.Interrupt.Affinity,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DebugPrint((0, "IdePort: Can't connect interrupt %d\n", irqPartialDescriptors->u.Interrupt.Vector));
|
|
FdoExtension->InterruptObject = NULL;
|
|
goto GetOut;
|
|
}
|
|
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
|
|
//
|
|
// Disconnect the parent ISR stub
|
|
//
|
|
if ( FdoExtension->InterruptInterface.PciIdeInterruptControl) {
|
|
|
|
DebugPrint((1, "IdePort: %d fdoe 0x%x Invoking disconnect\n",
|
|
irqPartialDescriptors->u.Interrupt.Vector,
|
|
FdoExtension
|
|
));
|
|
|
|
status = FdoExtension->InterruptInterface.PciIdeInterruptControl (
|
|
FdoExtension->InterruptInterface.Context,
|
|
1
|
|
);
|
|
ASSERT(NT_SUCCESS(status));
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Enable Interrupt
|
|
//
|
|
ChannelEnableInterrupt (FdoExtension);
|
|
}
|
|
|
|
if (FdoExtension->FdoState & FDOS_STOPPED) {
|
|
|
|
//
|
|
// we are restarting, no need to do the rest of start code
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// Get parent's busmaster interface
|
|
//
|
|
ChannelQueryBusMasterInterface (
|
|
FdoExtension
|
|
);
|
|
|
|
//
|
|
// Maintain a default timing table
|
|
//
|
|
if (FdoExtension->DefaultTransferModeTimingTable == NULL) {
|
|
|
|
ULONG length=0;
|
|
PULONG transferModeTimingTable = ExAllocatePool(NonPagedPool, MAX_XFER_MODE*sizeof(ULONG));
|
|
|
|
if (transferModeTimingTable != NULL) {
|
|
SetDefaultTiming(transferModeTimingTable, length);
|
|
FdoExtension->DefaultTransferModeTimingTable = transferModeTimingTable;
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
}
|
|
}
|
|
ASSERT(FdoExtension->DefaultTransferModeTimingTable);
|
|
|
|
//
|
|
// Get parent's access token to serialize access with siblings (broken pci-ide)
|
|
//
|
|
ChannelQuerySyncAccessInterface (
|
|
FdoExtension
|
|
);
|
|
|
|
//
|
|
// get an interface that tells parent to invalidate out resource requirement
|
|
//
|
|
ChannelQueryRequestProperResourceInterface (
|
|
FdoExtension
|
|
);
|
|
|
|
//
|
|
// Create legacy object names
|
|
//
|
|
status = ChannelCreateSymblicLinks (
|
|
FdoExtension
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// FDO Init Data
|
|
//
|
|
IdePortInitFdo (FdoExtension);
|
|
|
|
//
|
|
// Allocate reserve error log packets to log insufficient resource events
|
|
//
|
|
for (i=0;i<MAX_IDE_DEVICE;i++) {
|
|
|
|
if (FdoExtension->ReserveAllocFailureLogEntry[i] == NULL) {
|
|
FdoExtension->ReserveAllocFailureLogEntry[i] = IoAllocateErrorLogEntry(
|
|
FdoExtension->DeviceObject,
|
|
ALLOC_FAILURE_LOGSIZE
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pre-allocate memory for enumeration
|
|
//
|
|
if (!IdePreAllocEnumStructs(FdoExtension)) {
|
|
status=STATUS_INSUFFICIENT_RESOURCES;
|
|
goto GetOut;
|
|
}
|
|
|
|
|
|
//
|
|
// Reserve pages to perform I/O under low memory conditions
|
|
//
|
|
if (FdoExtension->ReservedPages == NULL) {
|
|
|
|
FdoExtension->ReservedPages = MmAllocateMappingAddress( IDE_NUM_RESERVED_PAGES * PAGE_SIZE,
|
|
'PedI'
|
|
);
|
|
|
|
ASSERT(FdoExtension->ReservedPages);
|
|
|
|
}
|
|
|
|
GetOut:
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// End of Init.
|
|
//
|
|
CLRMASK (FdoExtension->FdoState, FDOS_STOPPED);
|
|
SETMASK (FdoExtension->FdoState, FDOS_STARTED);
|
|
|
|
if (FdoExtension->ResourceList) {
|
|
ExFreePool(FdoExtension->ResourceList);
|
|
FdoExtension->ResourceList = NULL;
|
|
}
|
|
FdoExtension->ResourceList = ResourceListToKeep;
|
|
|
|
} else {
|
|
|
|
ChannelRemoveChannel (FdoExtension);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelCreateSymblicLinks (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG i;
|
|
PULONG scsiportNumber;
|
|
|
|
UNICODE_STRING deviceName;
|
|
WCHAR deviceNameBuffer[64];
|
|
|
|
UNICODE_STRING symbolicDeviceName;
|
|
WCHAR symbolicDeviceNameBuffer[64];
|
|
|
|
swprintf(deviceNameBuffer, DEVICE_OJBECT_BASE_NAME L"\\IdePort%d", FdoExtension->IdePortNumber);
|
|
RtlInitUnicodeString(&deviceName, deviceNameBuffer);
|
|
|
|
scsiportNumber = &IoGetConfigurationInformation()->ScsiPortCount;
|
|
|
|
for (i=0; i <= (*scsiportNumber); i++) {
|
|
|
|
swprintf(symbolicDeviceNameBuffer, L"\\Device\\ScsiPort%d", i);
|
|
RtlInitUnicodeString(&symbolicDeviceName, symbolicDeviceNameBuffer);
|
|
|
|
status = IoCreateSymbolicLink(
|
|
&symbolicDeviceName,
|
|
&deviceName
|
|
);
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
|
|
swprintf(symbolicDeviceNameBuffer, L"\\DosDevices\\Scsi%d:", i);
|
|
RtlInitUnicodeString(&symbolicDeviceName, symbolicDeviceNameBuffer);
|
|
|
|
IoAssignArcName (
|
|
&symbolicDeviceName,
|
|
&deviceName
|
|
);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
FdoExtension->SymbolicLinkCreated = TRUE;
|
|
FdoExtension->ScsiPortNumber = i;
|
|
(*scsiportNumber)++;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelDeleteSymblicLinks (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG i;
|
|
|
|
UNICODE_STRING deviceName;
|
|
WCHAR deviceNameBuffer[64];
|
|
|
|
if (!FdoExtension->SymbolicLinkCreated) {
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
swprintf(deviceNameBuffer, L"\\Device\\ScsiPort%d", FdoExtension->ScsiPortNumber);
|
|
RtlInitUnicodeString(&deviceName, deviceNameBuffer);
|
|
|
|
IoDeleteSymbolicLink(
|
|
&deviceName
|
|
);
|
|
|
|
swprintf(deviceNameBuffer, L"\\DosDevices\\Scsi%d:", FdoExtension->ScsiPortNumber);
|
|
RtlInitUnicodeString(&deviceName, deviceNameBuffer);
|
|
|
|
IoDeassignArcName(&deviceName);
|
|
|
|
FdoExtension->SymbolicLinkCreated = FALSE;
|
|
|
|
IoGetConfigurationInformation()->ScsiPortCount--;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ChannelSurpriseRemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension = (PFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
PPDO_EXTENSION pdoExtension;
|
|
IDE_PATH_ID pathId;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// all my childred should be surprise removed or removed
|
|
//
|
|
pathId.l = 0;
|
|
while (pdoExtension = NextLogUnitExtensionWithTag (
|
|
fdoExtension,
|
|
&pathId,
|
|
TRUE,
|
|
ChannelSurpriseRemoveDevice
|
|
)) {
|
|
|
|
//ASSERT (pdoExtension->PdoState & (PDOS_SURPRISE_REMOVED | PDOS_REMOVED));
|
|
|
|
CLRMASK (pdoExtension->PdoState, PDOS_REPORTED_TO_PNP);
|
|
|
|
UnrefPdoWithTag(
|
|
pdoExtension,
|
|
ChannelSurpriseRemoveDevice
|
|
);
|
|
}
|
|
|
|
status = ChannelRemoveChannel (fdoExtension);
|
|
ASSERT (NT_SUCCESS(status));
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ChannelRemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension = (PFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
PPDO_EXTENSION pdoExtension;
|
|
NTSTATUS status;
|
|
KEVENT event;
|
|
|
|
IDE_PATH_ID pathId;
|
|
|
|
DebugPrint ((
|
|
DBG_PNP,
|
|
"fdoe 0x%x 0x%x got a STOP device\n",
|
|
fdoExtension,
|
|
fdoExtension->IdeResource.TranslatedCommandBaseAddress
|
|
));
|
|
|
|
//
|
|
// Kill all the children if any
|
|
//
|
|
pathId.l = 0;
|
|
while (pdoExtension = NextLogUnitExtensionWithTag (
|
|
fdoExtension,
|
|
&pathId,
|
|
TRUE,
|
|
ChannelRemoveDevice
|
|
)) {
|
|
|
|
if (pdoExtension->PdoState & PDOS_SURPRISE_REMOVED) {
|
|
|
|
CLRMASK (pdoExtension->PdoState, PDOS_REPORTED_TO_PNP);
|
|
continue;
|
|
}
|
|
|
|
FreePdoWithTag(
|
|
pdoExtension,
|
|
TRUE,
|
|
TRUE,
|
|
ChannelRemoveDevice
|
|
);
|
|
}
|
|
|
|
status = ChannelRemoveChannel (fdoExtension);
|
|
ASSERT (NT_SUCCESS(status));
|
|
|
|
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
ChannelRemoveDeviceCompletionRoutine,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
status = IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
|
|
IoDetachDevice (fdoExtension->AttacheeDeviceObject);
|
|
|
|
IoDeleteDevice (DeviceObject);
|
|
|
|
//return STATUS_SUCCESS;
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ChannelRemoveDeviceCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PKEVENT event = Context;
|
|
|
|
KeSetEvent(event, 0, FALSE);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelStopDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension;
|
|
|
|
fdoExtension = DeviceObject->DeviceExtension;
|
|
|
|
DebugPrint ((
|
|
DBG_PNP,
|
|
"fdoe 0x%x 0x%x got a STOP device\n",
|
|
fdoExtension,
|
|
fdoExtension->IdeResource.TranslatedCommandBaseAddress
|
|
));
|
|
|
|
//
|
|
// disable interrupt
|
|
//
|
|
ChannelDisableInterrupt (fdoExtension);
|
|
|
|
if (fdoExtension->InterruptObject) {
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
|
|
//
|
|
// Reconnect the parent ISR stub
|
|
//
|
|
if (fdoExtension->InterruptInterface.PciIdeInterruptControl) {
|
|
|
|
NTSTATUS status;
|
|
|
|
DebugPrint((1, "fdoe 0x%x invoking reconnect\n", fdoExtension));
|
|
|
|
status = fdoExtension->InterruptInterface.PciIdeInterruptControl (
|
|
fdoExtension->InterruptInterface.Context,
|
|
0
|
|
);
|
|
ASSERT(NT_SUCCESS(status));
|
|
}
|
|
|
|
#endif
|
|
|
|
IoDisconnectInterrupt (
|
|
fdoExtension->InterruptObject
|
|
);
|
|
|
|
fdoExtension->InterruptObject = 0;
|
|
|
|
}
|
|
|
|
if (fdoExtension->FdoState & FDOS_STARTED) {
|
|
|
|
//
|
|
// indicate we have been stopped only if we have started
|
|
//
|
|
CLRMASK (fdoExtension->FdoState, FDOS_STARTED);
|
|
SETMASK (fdoExtension->FdoState, FDOS_STOPPED);
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelRemoveChannel (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
PCONFIGURATION_INFORMATION configurationInformation;
|
|
ULONG i;
|
|
|
|
configurationInformation = IoGetConfigurationInformation();
|
|
|
|
DebugPrint((1, "ChannelRemoveChannel for FDOe %x\n", FdoExtension));
|
|
|
|
if (FdoExtension->IdeResource.AtdiskPrimaryClaimed) {
|
|
configurationInformation->AtDiskPrimaryAddressClaimed = FALSE;
|
|
}
|
|
|
|
if (FdoExtension->IdeResource.AtdiskSecondaryClaimed) {
|
|
configurationInformation->AtDiskSecondaryAddressClaimed = FALSE;
|
|
}
|
|
FdoExtension->IdeResource.AtdiskPrimaryClaimed = FALSE;
|
|
FdoExtension->IdeResource.AtdiskSecondaryClaimed = FALSE;
|
|
FdoExtension->HwDeviceExtension->PrimaryAddress = FALSE;
|
|
|
|
if ((FdoExtension->IdeResource.CommandBaseAddressSpace == MEMORY_SPACE) &&
|
|
(FdoExtension->IdeResource.TranslatedCommandBaseAddress)) {
|
|
|
|
MmUnmapIoSpace (
|
|
FdoExtension->IdeResource.TranslatedCommandBaseAddress,
|
|
FdoExtension->HwDeviceExtension->BaseIoAddress1Length
|
|
);
|
|
}
|
|
FdoExtension->IdeResource.TranslatedCommandBaseAddress = 0;
|
|
|
|
if ((FdoExtension->IdeResource.ControlBaseAddressSpace == MEMORY_SPACE) &&
|
|
(FdoExtension->IdeResource.TranslatedControlBaseAddress)) {
|
|
|
|
MmUnmapIoSpace (
|
|
FdoExtension->IdeResource.TranslatedControlBaseAddress,
|
|
1
|
|
);
|
|
}
|
|
FdoExtension->IdeResource.TranslatedControlBaseAddress = 0;
|
|
|
|
if (FdoExtension->InterruptObject) {
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
|
|
//
|
|
// Reconnect the parent ISR stub
|
|
//
|
|
if (FdoExtension->InterruptInterface.PciIdeInterruptControl) {
|
|
|
|
NTSTATUS status;
|
|
|
|
DebugPrint((1, "fdoe 0x%x invoking reconnect\n", FdoExtension));
|
|
|
|
status = FdoExtension->InterruptInterface.PciIdeInterruptControl (
|
|
FdoExtension->InterruptInterface.Context,
|
|
0
|
|
);
|
|
ASSERT(NT_SUCCESS(status));
|
|
}
|
|
|
|
#endif
|
|
|
|
IoDisconnectInterrupt (
|
|
FdoExtension->InterruptObject
|
|
);
|
|
|
|
FdoExtension->InterruptObject = 0;
|
|
}
|
|
|
|
// unbind from the bm stuff if NECESSARY
|
|
// release parent's access token to serialize access with siblings (broken pci-ide)
|
|
|
|
if (FdoExtension->ResourceList) {
|
|
|
|
ExFreePool (FdoExtension->ResourceList);
|
|
FdoExtension->ResourceList = NULL;
|
|
|
|
}
|
|
else {
|
|
DebugPrint((1, "ATAPI: Resource list for FDOe %x already freed\n",
|
|
FdoExtension));
|
|
}
|
|
|
|
//
|
|
// Lock
|
|
//
|
|
ASSERT(InterlockedCompareExchange(&(FdoExtension->EnumStructLock), 1, 0) == 0);
|
|
|
|
//
|
|
// Free pre-allocated memory
|
|
//
|
|
IdeFreeEnumStructs(FdoExtension->PreAllocEnumStruct);
|
|
|
|
FdoExtension->PreAllocEnumStruct = NULL;
|
|
|
|
//
|
|
// Unlock
|
|
//
|
|
ASSERT(InterlockedCompareExchange(&(FdoExtension->EnumStructLock), 0, 1) == 1);
|
|
|
|
//
|
|
// Free the reserve error log entries
|
|
//
|
|
for (i=0; i< MAX_IDE_DEVICE; i++) {
|
|
PVOID entry;
|
|
PVOID currentValue;
|
|
|
|
entry = FdoExtension->ReserveAllocFailureLogEntry[i];
|
|
|
|
if (entry == NULL) {
|
|
continue;
|
|
}
|
|
//
|
|
// We have to ensure that we are the only instance to use this
|
|
// event. To do so, we attempt to NULL the event in the driver
|
|
// extension. If somebody else beats us to it, they own the
|
|
// event and we have to give up.
|
|
//
|
|
|
|
currentValue = InterlockedCompareExchangePointer(
|
|
&(FdoExtension->ReserveAllocFailureLogEntry[i]),
|
|
NULL,
|
|
entry
|
|
);
|
|
|
|
if (entry != currentValue) {
|
|
continue;
|
|
}
|
|
|
|
// Note that you cannot ExFreePool the entry
|
|
// because Io returns an offset into the pool allocation, not the start.
|
|
// Use the API provided by Iomanager
|
|
IoFreeErrorLogEntry(entry);
|
|
}
|
|
|
|
//
|
|
// Free the default timing table
|
|
//
|
|
if (FdoExtension->DefaultTransferModeTimingTable) {
|
|
|
|
ExFreePool(FdoExtension->DefaultTransferModeTimingTable);
|
|
|
|
FdoExtension->DefaultTransferModeTimingTable = NULL;
|
|
FdoExtension->TransferModeInterface.TransferModeTimingTable = NULL;
|
|
FdoExtension->TransferModeInterface.TransferModeTableLength =0;
|
|
}
|
|
|
|
//
|
|
// Unmap the reserved mapping
|
|
//
|
|
if (FdoExtension->ReservedPages != NULL) {
|
|
|
|
MmFreeMappingAddress(FdoExtension->ReservedPages,
|
|
'PedI'
|
|
);
|
|
FdoExtension->ReservedPages = NULL;
|
|
}
|
|
|
|
ChannelDeleteSymblicLinks (
|
|
FdoExtension
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelQueryDeviceRelations (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
PIDE_WORK_ITEM_CONTEXT workItemContext;
|
|
PENUMERATION_STRUCT enumStruct = fdoExtension->PreAllocEnumStruct;
|
|
|
|
if (!(fdoExtension->FdoState & FDOS_STARTED)) {
|
|
|
|
Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return STATUS_DEVICE_NOT_READY;
|
|
}
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
switch (thisIrpSp->Parameters.QueryDeviceRelations.Type) {
|
|
case BusRelations:
|
|
|
|
DebugPrint ((DBG_BUSSCAN, "IdeQueryDeviceRelations: bus relations\n"));
|
|
|
|
ASSERT(enumStruct);
|
|
workItemContext = (PIDE_WORK_ITEM_CONTEXT) enumStruct->EnumWorkItemContext;
|
|
ASSERT(workItemContext);
|
|
ASSERT(workItemContext->WorkItem);
|
|
|
|
workItemContext->Irp = Irp;
|
|
|
|
#ifdef SYNC_DEVICE_RELATIONS
|
|
|
|
return ChannelQueryBusRelation (
|
|
DeviceObject,
|
|
workItemContext);
|
|
|
|
#else
|
|
Irp->IoStatus.Status = STATUS_PENDING;
|
|
IoMarkIrpPending(Irp);
|
|
|
|
IoQueueWorkItem(
|
|
workItemContext->WorkItem,
|
|
ChannelQueryBusRelation,
|
|
DelayedWorkQueue,
|
|
workItemContext
|
|
);
|
|
|
|
return STATUS_PENDING;
|
|
#endif //!SYNC_DEVICE_RELATIONS
|
|
break;
|
|
|
|
default:
|
|
DebugPrint ((1, "IdeQueryDeviceRelations: Unsupported device relation\n"));
|
|
|
|
//
|
|
// Don't set the status if it is not success and is being passed
|
|
// down
|
|
//
|
|
|
|
//Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelQueryBusRelation (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIDE_WORK_ITEM_CONTEXT WorkItemContext
|
|
)
|
|
{
|
|
|
|
PIRP irp;
|
|
PFDO_EXTENSION fdoExtension;
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
LARGE_INTEGER tickCount;
|
|
ULONG timeDiff;
|
|
|
|
irp = WorkItemContext->Irp;
|
|
|
|
//
|
|
// do not release resource for this worker item as they are pre-alloced
|
|
//
|
|
// IoFreeWorkItem(WorkItemContext->WorkItem);
|
|
//ExFreePool (WorkItemContext);
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation(irp);
|
|
fdoExtension = thisIrpSp->DeviceObject->DeviceExtension;
|
|
|
|
LogBusScanStartTimer(&tickCount);
|
|
|
|
//
|
|
// grab the acpi/bios timing settings if any
|
|
// GTM should be called for every enumeration
|
|
//
|
|
DeviceQueryChannelTimingSettings (
|
|
fdoExtension,
|
|
&fdoExtension->AcpiTimingSettings
|
|
);
|
|
|
|
//
|
|
// Get parent's xfer mode interface
|
|
//
|
|
ChannelQueryTransferModeInterface (
|
|
fdoExtension
|
|
);
|
|
|
|
//
|
|
// scan the bus
|
|
//
|
|
IdePortScanBus (fdoExtension);
|
|
|
|
timeDiff = LogBusScanStopTimer(&tickCount);
|
|
LogBusScanTimeDiff(fdoExtension, L"IdeTotalBusScanTime", timeDiff);
|
|
|
|
#ifdef IDE_MEASURE_BUSSCAN_SPEED
|
|
if (timeDiff > 7000) {
|
|
|
|
DebugPrint ((DBG_WARNING, "WARNING: **************************************\n"));
|
|
DebugPrint ((DBG_WARNING, "WARNING: IdePortScanBus 0x%x took %u millisec\n", fdoExtension->IdeResource.TranslatedCommandBaseAddress, timeDiff));
|
|
DebugPrint ((DBG_WARNING, "WARNING: **************************************\n"));
|
|
|
|
} else {
|
|
|
|
DebugPrint ((DBG_BUSSCAN, "IdePortScanBus 0x%x took %u millisec\n", fdoExtension->IdeResource.TranslatedCommandBaseAddress, timeDiff));
|
|
}
|
|
#endif
|
|
|
|
deviceRelations = ChannelBuildDeviceRelationList (
|
|
fdoExtension
|
|
);
|
|
|
|
irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
IoSkipCurrentIrpStackLocation (irp);
|
|
return IoCallDriver (fdoExtension->AttacheeDeviceObject, irp);
|
|
}
|
|
|
|
|
|
PDEVICE_RELATIONS
|
|
ChannelBuildDeviceRelationList (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
IDE_PATH_ID pathId;
|
|
ULONG numPdoChildren;
|
|
NTSTATUS status;
|
|
PPDO_EXTENSION pdoExtension;
|
|
ULONG deviceRelationsSize;
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
pathId.l = 0;
|
|
numPdoChildren = 0;
|
|
while (pdoExtension = NextLogUnitExtensionWithTag(
|
|
FdoExtension,
|
|
&pathId,
|
|
TRUE,
|
|
ChannelBuildDeviceRelationList
|
|
)) {
|
|
|
|
UnrefLogicalUnitExtensionWithTag (
|
|
FdoExtension,
|
|
pdoExtension,
|
|
ChannelBuildDeviceRelationList
|
|
);
|
|
numPdoChildren++;
|
|
}
|
|
|
|
if (numPdoChildren) {
|
|
deviceRelationsSize = FIELD_OFFSET (DEVICE_RELATIONS, Objects) +
|
|
numPdoChildren * sizeof(PDEVICE_OBJECT);
|
|
} else {
|
|
// Current build expect a DEVICE_RELATIONS with a Count of 0
|
|
// if we don't have any PDO to return
|
|
|
|
deviceRelationsSize = FIELD_OFFSET( DEVICE_RELATIONS, Objects ) +
|
|
1 * sizeof( PDEVICE_OBJECT );
|
|
}
|
|
|
|
deviceRelations = ExAllocatePool (NonPagedPool, deviceRelationsSize);
|
|
|
|
if(!deviceRelations) {
|
|
DebugPrint ((DBG_ALWAYS, "ChannelBuildDeviceRelationList: Unable to allocate DeviceRelations structures\n"));
|
|
status = STATUS_NO_MEMORY;
|
|
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
(deviceRelations)->Count = 0;
|
|
|
|
pathId.l = 0;
|
|
while ((deviceRelations->Count < numPdoChildren) &&
|
|
(pdoExtension = NextLogUnitExtensionWithTag(
|
|
FdoExtension,
|
|
&pathId,
|
|
TRUE,
|
|
ChannelBuildDeviceRelationList
|
|
))) {
|
|
|
|
KIRQL currentIrql;
|
|
BOOLEAN deadMeat;
|
|
|
|
KeAcquireSpinLock(&pdoExtension->PdoSpinLock, ¤tIrql);
|
|
deadMeat = pdoExtension->PdoState & PDOS_DEADMEAT ? TRUE : FALSE;
|
|
KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
|
|
|
|
if (!deadMeat) {
|
|
|
|
KeAcquireSpinLock(&pdoExtension->PdoSpinLock, ¤tIrql);
|
|
SETMASK (pdoExtension->PdoState, PDOS_REPORTED_TO_PNP);
|
|
KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
|
|
|
|
deviceRelations->Objects[deviceRelations->Count] = pdoExtension->DeviceObject;
|
|
ObReferenceObjectByPointer(deviceRelations->Objects[deviceRelations->Count],
|
|
0,
|
|
0,
|
|
KernelMode);
|
|
deviceRelations->Count++;
|
|
|
|
} else {
|
|
|
|
KeAcquireSpinLock(&pdoExtension->PdoSpinLock, ¤tIrql);
|
|
CLRMASK (pdoExtension->PdoState, PDOS_REPORTED_TO_PNP);
|
|
KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
|
|
|
|
DebugPrint ((DBG_BUSSCAN, "0x%x target 0x%x pdoExtension 0x%x is marked DEADMEAT\n",
|
|
pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
|
|
pdoExtension->TargetId,
|
|
pdoExtension));
|
|
}
|
|
|
|
UnrefLogicalUnitExtensionWithTag (
|
|
FdoExtension,
|
|
pdoExtension,
|
|
ChannelBuildDeviceRelationList
|
|
);
|
|
}
|
|
|
|
DebugPrint ((DBG_BUSSCAN, "ChannelBuildDeviceRelationList: returning %d children\n", deviceRelations->Count));
|
|
}
|
|
|
|
|
|
return deviceRelations;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelQueryId (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
PFDO_EXTENSION fdoExtension;
|
|
NTSTATUS status;
|
|
PWCHAR returnString;
|
|
ANSI_STRING ansiString;
|
|
UNICODE_STRING unicodeString;
|
|
|
|
PAGED_CODE();
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
fdoExtension = (PFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
|
|
if (!(fdoExtension->FdoState & FDOS_STARTED)) {
|
|
|
|
Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return STATUS_DEVICE_NOT_READY;
|
|
}
|
|
|
|
unicodeString.Buffer = NULL;
|
|
switch (thisIrpSp->Parameters.QueryId.IdType) {
|
|
|
|
case BusQueryCompatibleIDs:
|
|
case BusQueryHardwareIDs:
|
|
|
|
unicodeString.Length = 0;
|
|
unicodeString.MaximumLength = 50 * sizeof(WCHAR);
|
|
unicodeString.Buffer = ExAllocatePool(PagedPool, unicodeString.MaximumLength);
|
|
|
|
//
|
|
// Caller wants the unique id of the device
|
|
//
|
|
RtlInitAnsiString (
|
|
&ansiString,
|
|
"*PNP0600"
|
|
);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (unicodeString.Buffer) {
|
|
|
|
RtlAnsiStringToUnicodeString(
|
|
&unicodeString,
|
|
&ansiString,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// double null terminate it
|
|
//
|
|
unicodeString.Buffer[unicodeString.Length/sizeof(WCHAR) + 0] = L'\0';
|
|
unicodeString.Buffer[unicodeString.Length/sizeof(WCHAR) + 1] = L'\0';
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
//
|
|
// we need to check if the lower driver handles this irp
|
|
// registry a completion routine. we can check
|
|
// when the irp comes back
|
|
//
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
ChannelQueryIdCompletionRoutine,
|
|
unicodeString.Buffer,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// we don't care much about this irp
|
|
//
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
}
|
|
|
|
status = IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
|
|
if (unicodeString.Buffer) {
|
|
|
|
return STATUS_PENDING;
|
|
|
|
} else {
|
|
|
|
return status;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelQueryIdCompletionRoutine (
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp,
|
|
PVOID Context
|
|
)
|
|
{
|
|
if (Irp->IoStatus.Status == STATUS_NOT_SUPPORTED) {
|
|
|
|
//
|
|
// the lower level driver didn't handle the irp
|
|
// return the device text string we created early
|
|
//
|
|
Irp->IoStatus.Information = (ULONG_PTR) Context;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
} else {
|
|
|
|
//
|
|
// the lower driver handled the irp,
|
|
// we don't need to return our device text string
|
|
//
|
|
ExFreePool (Context);
|
|
}
|
|
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelUsageNotification (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PULONG deviceUsageCount;
|
|
|
|
ASSERT (DeviceObject);
|
|
ASSERT (Irp);
|
|
|
|
fdoExtension = (PFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
ASSERT (fdoExtension);
|
|
|
|
if (!(fdoExtension->FdoState & FDOS_STARTED)) {
|
|
|
|
Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return STATUS_DEVICE_NOT_READY;
|
|
}
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging) {
|
|
|
|
//
|
|
// Adjust the paging path count for this device.
|
|
//
|
|
deviceUsageCount = &fdoExtension->PagingPathCount;
|
|
|
|
} else if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeHibernation) {
|
|
|
|
//
|
|
// Adjust the paging path count for this device.
|
|
//
|
|
deviceUsageCount = &fdoExtension->HiberPathCount;
|
|
|
|
} else if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeDumpFile) {
|
|
|
|
//
|
|
// Adjust the paging path count for this device.
|
|
//
|
|
deviceUsageCount = &fdoExtension->CrashDumpPathCount;
|
|
|
|
} else {
|
|
|
|
deviceUsageCount = NULL;
|
|
DebugPrint ((DBG_ALWAYS,
|
|
"ATAPI: Unknown IRP_MN_DEVICE_USAGE_NOTIFICATION type: 0x%x\n",
|
|
irpSp->Parameters.UsageNotification.Type));
|
|
}
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
IoSetCompletionRoutine (
|
|
Irp,
|
|
ChannelUsageNotificationCompletionRoutine,
|
|
deviceUsageCount,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
ASSERT(fdoExtension->AttacheeDeviceObject);
|
|
return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
|
|
} // ChannelPagingNotification
|
|
|
|
NTSTATUS
|
|
ChannelUsageNotificationCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension;
|
|
PULONG deviceUsageCount = Context;
|
|
|
|
fdoExtension = (PFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
ASSERT (fdoExtension);
|
|
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
if (deviceUsageCount) {
|
|
|
|
IoAdjustPagingPathCount (
|
|
deviceUsageCount,
|
|
IoGetCurrentIrpStackLocation(Irp)->Parameters.UsageNotification.InPath
|
|
);
|
|
}
|
|
}
|
|
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ChannelDeviceIoControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
PFDO_EXTENSION fdoExtension = (PFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
PSTORAGE_PROPERTY_QUERY storageQuery;
|
|
STORAGE_ADAPTER_DESCRIPTOR adapterDescriptor;
|
|
ULONG outBufferSize;
|
|
NTSTATUS status;
|
|
|
|
// pass it down if not supported and it is for the FDO stack
|
|
|
|
switch (thisIrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
case IOCTL_STORAGE_QUERY_PROPERTY:
|
|
|
|
storageQuery = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (thisIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_PROPERTY_QUERY)) {
|
|
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
if (storageQuery->PropertyId == StorageAdapterProperty) { // device property
|
|
|
|
switch (storageQuery->QueryType) {
|
|
case PropertyStandardQuery:
|
|
DebugPrint ((1, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyStandardQuery\n"));
|
|
|
|
RtlZeroMemory (&adapterDescriptor, sizeof(adapterDescriptor));
|
|
|
|
//
|
|
// BuildAtaDeviceDescriptor
|
|
//
|
|
adapterDescriptor.Version = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
|
|
adapterDescriptor.Size = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
|
|
adapterDescriptor.MaximumTransferLength = MAX_TRANSFER_SIZE_PER_SRB;
|
|
adapterDescriptor.MaximumPhysicalPages = SP_UNINITIALIZED_VALUE;
|
|
adapterDescriptor.AlignmentMask = DeviceObject->AlignmentRequirement;
|
|
adapterDescriptor.AdapterUsesPio = TRUE; // We always support PIO
|
|
adapterDescriptor.AdapterScansDown = FALSE;
|
|
adapterDescriptor.CommandQueueing = FALSE;
|
|
adapterDescriptor.AcceleratedTransfer = FALSE;
|
|
adapterDescriptor.BusType = BusTypeAta; // Bus type should be ATA
|
|
adapterDescriptor.BusMajorVersion = 1; // Major version
|
|
adapterDescriptor.BusMinorVersion = 0; //
|
|
|
|
if (thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(STORAGE_ADAPTER_DESCRIPTOR)) {
|
|
|
|
outBufferSize = thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
} else {
|
|
|
|
outBufferSize = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
|
|
}
|
|
|
|
RtlCopyMemory (Irp->AssociatedIrp.SystemBuffer,
|
|
&adapterDescriptor,
|
|
outBufferSize);
|
|
Irp->IoStatus.Information = outBufferSize;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case PropertyExistsQuery:
|
|
DebugPrint ((1, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyExistsQuery\n"));
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case PropertyMaskQuery:
|
|
DebugPrint ((1, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyMaskQuery\n"));
|
|
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
default:
|
|
DebugPrint ((1, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY unknown type\n"));
|
|
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// we don't know what this deviceIoControl Irp is
|
|
//
|
|
if (thisIrpSp->DeviceObject == DeviceObject) {
|
|
|
|
//
|
|
// this irp could come from the PDO stack
|
|
//
|
|
// forward this unknown request if and only
|
|
// if this irp is for the FDO stack
|
|
//
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
break;
|
|
}
|
|
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
}
|
|
|
|
status = Irp->IoStatus.Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
ChannelQueryBusMasterInterface (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
IO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
|
|
|
|
FdoExtension->BoundWithBmParent = FALSE;
|
|
|
|
RtlZeroMemory (&irpSp, sizeof(irpSp));
|
|
|
|
irpSp.Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCIIDE_BUSMASTER_INTERFACE;
|
|
irpSp.Parameters.QueryInterface.Version = 1;
|
|
irpSp.Parameters.QueryInterface.Size = sizeof (FdoExtension->HwDeviceExtension->BusMasterInterface);
|
|
irpSp.Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->HwDeviceExtension->BusMasterInterface;
|
|
irpSp.Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
|
|
|
irpSp.MajorFunction = IRP_MJ_PNP;
|
|
irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
status = IdePortSyncSendIrp (FdoExtension->AttacheeDeviceObject, &irpSp, NULL);
|
|
if (NT_SUCCESS(status)) {
|
|
FdoExtension->BoundWithBmParent = TRUE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
VOID
|
|
ChannelQueryInterruptInterface (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
IO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
|
|
|
|
RtlZeroMemory (&irpSp, sizeof(irpSp));
|
|
|
|
irpSp.Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCIIDE_INTERRUPT_INTERFACE;
|
|
irpSp.Parameters.QueryInterface.Version = 1;
|
|
irpSp.Parameters.QueryInterface.Size = sizeof (FdoExtension->InterruptInterface);
|
|
irpSp.Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->InterruptInterface;
|
|
irpSp.Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
|
|
|
irpSp.MajorFunction = IRP_MJ_PNP;
|
|
irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
DebugPrint((1, "Querying interrupt interface for Fdoe 0x%x\n", FdoExtension));
|
|
|
|
status = IdePortSyncSendIrp (FdoExtension->AttacheeDeviceObject, &irpSp, NULL);
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
VOID
|
|
ChannelQueryTransferModeInterface (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
IO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlZeroMemory (&irpSp, sizeof(irpSp));
|
|
|
|
irpSp.Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCIIDE_XFER_MODE_INTERFACE;
|
|
irpSp.Parameters.QueryInterface.Version = 1;
|
|
irpSp.Parameters.QueryInterface.Size = sizeof (FdoExtension->TransferModeInterface);
|
|
irpSp.Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->TransferModeInterface;
|
|
irpSp.Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
|
|
|
irpSp.MajorFunction = IRP_MJ_PNP;
|
|
irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
status = IdePortSyncSendIrp (FdoExtension->AttacheeDeviceObject, &irpSp, NULL);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
if (FdoExtension->TransferModeInterface.SupportLevel
|
|
!= PciIdeFullXferModeSupport) {
|
|
|
|
//
|
|
// We got the sfer mode interface from our parent,
|
|
// but it has only the basic functionality. It
|
|
// just relies on the BIOS to program its timing
|
|
// registers during POST. It doesn't really know
|
|
// how to program its timing registers.
|
|
//
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
if (FdoExtension->AcpiTimingSettings.Speed[i].Pio != ACPI_XFER_MODE_NOT_SUPPORT) {
|
|
|
|
//
|
|
// looks like ACPI is present and it knows how to program
|
|
// ide timing registers. Let's forget our parent xfer mode
|
|
// interface and go with the ACPI xfer mode interface
|
|
//
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT (FdoExtension->TransferModeInterface.TransferModeTimingTable);
|
|
}
|
|
|
|
#ifdef ALWAYS_USE_APCI_IF_AVAILABLE
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
if (FdoExtension->AcpiTimingSettings.Speed[i].Pio != ACPI_XFER_MODE_NOT_SUPPORT) {
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
#endif // ALWAYS_USE_APCI_IF_AVAILABLE
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
PULONG transferModeTimingTable = FdoExtension->TransferModeInterface.TransferModeTimingTable;
|
|
//
|
|
// if we can't get the TransferModeInterface,
|
|
// we will default to the ACPI TransferModeInterface
|
|
//
|
|
if ((FdoExtension->AcpiTimingSettings.Speed[0].Pio != ACPI_XFER_MODE_NOT_SUPPORT) ||
|
|
(FdoExtension->AcpiTimingSettings.Speed[1].Pio != ACPI_XFER_MODE_NOT_SUPPORT)) {
|
|
|
|
FdoExtension->TransferModeInterface.SupportLevel = PciIdeFullXferModeSupport;
|
|
|
|
} else {
|
|
|
|
FdoExtension->TransferModeInterface.SupportLevel = PciIdeBasicXferModeSupport;
|
|
}
|
|
FdoExtension->TransferModeInterface.Context = FdoExtension;
|
|
FdoExtension->TransferModeInterface.TransferModeSelect = ChannelAcpiTransferModeSelect;
|
|
|
|
//
|
|
// Fill up the timingTable with the default cycle times.
|
|
//
|
|
if (transferModeTimingTable == NULL) {
|
|
FdoExtension->TransferModeInterface.TransferModeTimingTable = FdoExtension->
|
|
DefaultTransferModeTimingTable;
|
|
FdoExtension->TransferModeInterface.TransferModeTableLength = MAX_XFER_MODE;
|
|
}
|
|
}
|
|
|
|
if (FdoExtension->TransferModeInterface.SupportLevel ==
|
|
PciIdeBasicXferModeSupport) {
|
|
|
|
//
|
|
// we don't really have code to set the correct
|
|
// xfer mode timing on the controller.
|
|
// our TransferModeInterface is really picking
|
|
// whatever mode set by the bios. and since there
|
|
// is no way to figure what the current PIO mode
|
|
// the drive is in, we are setting a flag in
|
|
// the HwDeviceExtension so that we won't try
|
|
// to change the pio transfer mode
|
|
//
|
|
FdoExtension->HwDeviceExtension->NoPioSetTransferMode = TRUE;
|
|
}
|
|
|
|
ASSERT (FdoExtension->TransferModeInterface.TransferModeSelect);
|
|
ASSERT (FdoExtension->TransferModeInterface.TransferModeTimingTable);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ChannelUnbindBusMasterParent (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
// ISSUE: 08/30/2000 implement me!!!
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
ChannelQuerySyncAccessInterface (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
IO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
|
|
RtlZeroMemory (&irpSp, sizeof(irpSp));
|
|
RtlZeroMemory (
|
|
&FdoExtension->SyncAccessInterface,
|
|
sizeof (FdoExtension->SyncAccessInterface)
|
|
);
|
|
|
|
irpSp.Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCIIDE_SYNC_ACCESS_INTERFACE;
|
|
irpSp.Parameters.QueryInterface.Version = 1;
|
|
irpSp.Parameters.QueryInterface.Size = sizeof (FdoExtension->SyncAccessInterface);
|
|
irpSp.Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->SyncAccessInterface;
|
|
irpSp.Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
|
|
|
irpSp.MajorFunction = IRP_MJ_PNP;
|
|
irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
status = IdePortSyncSendIrp (FdoExtension->AttacheeDeviceObject, &irpSp, NULL);
|
|
|
|
//
|
|
// parent doesn't support access token,
|
|
//
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
FdoExtension->SyncAccessInterface.AllocateAccessToken = 0;
|
|
FdoExtension->SyncAccessInterface.Token = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ChannelQueryRequestProperResourceInterface (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
IO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
|
|
RtlZeroMemory (&irpSp, sizeof(irpSp));
|
|
RtlZeroMemory (
|
|
&FdoExtension->RequestProperResourceInterface,
|
|
sizeof (FdoExtension->RequestProperResourceInterface)
|
|
);
|
|
|
|
irpSp.Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCIIDE_REQUEST_PROPER_RESOURCES;
|
|
irpSp.Parameters.QueryInterface.Version = 1;
|
|
irpSp.Parameters.QueryInterface.Size = sizeof (FdoExtension->RequestProperResourceInterface);
|
|
irpSp.Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->RequestProperResourceInterface;
|
|
irpSp.Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
|
|
|
irpSp.MajorFunction = IRP_MJ_PNP;
|
|
irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
status = IdePortSyncSendIrp (FdoExtension->AttacheeDeviceObject, &irpSp, NULL);
|
|
return;
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
ChannelEnableInterrupt (
|
|
IN PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
for (i=0; i<(FdoExtension->HwDeviceExtension->MaxIdeDevice/MAX_IDE_DEVICE);i++) {
|
|
|
|
SelectIdeLine(&FdoExtension->HwDeviceExtension->BaseIoAddress1,i);
|
|
|
|
IdePortOutPortByte (
|
|
FdoExtension->HwDeviceExtension->BaseIoAddress2.DeviceControl,
|
|
IDE_DC_REENABLE_CONTROLLER
|
|
);
|
|
}
|
|
}
|
|
|
|
__inline
|
|
VOID
|
|
ChannelDisableInterrupt (
|
|
IN PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
for (i=0; i<(FdoExtension->HwDeviceExtension->MaxIdeDevice/MAX_IDE_DEVICE);i++) {
|
|
|
|
SelectIdeLine(&FdoExtension->HwDeviceExtension->BaseIoAddress1,i);
|
|
|
|
IdePortOutPortByte (
|
|
FdoExtension->HwDeviceExtension->BaseIoAddress2.DeviceControl,
|
|
IDE_DC_DISABLE_INTERRUPTS
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ChannelAcpiTransferModeSelect (
|
|
IN PVOID Context,
|
|
PPCIIDE_TRANSFER_MODE_SELECT XferMode
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension = Context;
|
|
ULONG i;
|
|
BOOLEAN useUdmaMode[MAX_IDE_DEVICE];
|
|
BOOLEAN dmaMode;
|
|
PIDENTIFY_DATA ataIdentifyData[MAX_IDE_DEVICE];
|
|
NTSTATUS status;
|
|
ULONG numDevices;
|
|
ULONG timingMode[MAX_IDE_DEVICE];
|
|
ULONG cycleTime[MAX_IDE_DEVICE];
|
|
ULONG dmaTiming;
|
|
PACPI_IDE_TIMING acpiTimingSettings;
|
|
ACPI_IDE_TIMING newAcpiTimingSettings;
|
|
PULONG transferModeTimingTable=XferMode->TransferModeTimingTable;
|
|
|
|
ASSERT(transferModeTimingTable);
|
|
|
|
|
|
ASSERT (IsNEC_98 == FALSE);
|
|
|
|
if (fdoExtension->DeviceChanged) {
|
|
DebugPrint((DBG_XFERMODE, "Updating boot acpi timing settings\n"));
|
|
RtlCopyMemory (&fdoExtension->BootAcpiTimingSettings,
|
|
&fdoExtension->AcpiTimingSettings,
|
|
sizeof(newAcpiTimingSettings)
|
|
);
|
|
}
|
|
acpiTimingSettings = &fdoExtension->BootAcpiTimingSettings;
|
|
|
|
RtlZeroMemory (&newAcpiTimingSettings, sizeof(newAcpiTimingSettings));
|
|
newAcpiTimingSettings.Flags.b.IndependentTiming =
|
|
acpiTimingSettings->Flags.b.IndependentTiming;
|
|
|
|
//
|
|
// how many devices do we have?
|
|
//
|
|
for (i=numDevices=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
if (XferMode->DevicePresent[i]) {
|
|
numDevices++;
|
|
}
|
|
}
|
|
ASSERT (numDevices);
|
|
|
|
//
|
|
// pick the device pio timing
|
|
//
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
ULONG mode;
|
|
|
|
if (!XferMode->DevicePresent[i]) {
|
|
continue;
|
|
}
|
|
|
|
GetHighestPIOTransferMode(XferMode->DeviceTransferModeSupported[i], mode);
|
|
|
|
timingMode[i] = 1<<mode;
|
|
cycleTime[i] = XferMode->BestPioCycleTime[i];
|
|
}
|
|
|
|
if ((numDevices > 1) && !acpiTimingSettings->Flags.b.IndependentTiming) {
|
|
|
|
//
|
|
// pick the slower of the two timings
|
|
// (the smaller timing mode value, the slower it is)
|
|
//
|
|
|
|
if (timingMode[0] < timingMode[1]) {
|
|
|
|
cycleTime[1] = cycleTime[0];
|
|
timingMode[1] = timingMode[0];
|
|
|
|
} else {
|
|
|
|
cycleTime[0] = cycleTime[1];
|
|
timingMode[0] = timingMode[1];
|
|
}
|
|
}
|
|
|
|
//
|
|
// store the pio mode selected
|
|
//
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
if (XferMode->DevicePresent[i]) {
|
|
XferMode->DeviceTransferModeSelected[i] = timingMode[i];
|
|
newAcpiTimingSettings.Speed[i].Pio = cycleTime[i];
|
|
|
|
if (i == 0) {
|
|
newAcpiTimingSettings.Flags.b.IoChannelReady0 = XferMode->IoReadySupported[i];
|
|
} else {
|
|
newAcpiTimingSettings.Flags.b.IoChannelReady1 = XferMode->IoReadySupported[i];
|
|
}
|
|
|
|
} else {
|
|
XferMode->DeviceTransferModeSelected[i] = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// pick the device dma timing
|
|
//
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
ULONG mode;
|
|
BOOLEAN useDma = TRUE;
|
|
|
|
timingMode[i] = 0;
|
|
cycleTime[i]= ACPI_XFER_MODE_NOT_SUPPORT;
|
|
|
|
if (!XferMode->DevicePresent[i]) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// check the acpi flag for ultra dma
|
|
//
|
|
if (i == 0) {
|
|
|
|
useUdmaMode[i] = acpiTimingSettings->Flags.b.UltraDma0 ? TRUE: FALSE;
|
|
|
|
} else {
|
|
|
|
ASSERT (i==1);
|
|
useUdmaMode[i] = acpiTimingSettings->Flags.b.UltraDma1 ? TRUE: FALSE;
|
|
}
|
|
|
|
//
|
|
// get the dma timing specified in _GTM
|
|
//
|
|
dmaTiming = acpiTimingSettings->Speed[i].Dma;
|
|
|
|
//
|
|
// if dma is not supported, don't do anything, We have already set the PIO mode.
|
|
//
|
|
if (dmaTiming == ACPI_XFER_MODE_NOT_SUPPORT) {
|
|
useUdmaMode[i]=0;
|
|
useDma = FALSE;
|
|
mode = PIO0;
|
|
}
|
|
|
|
|
|
//
|
|
// Find the highest UDMA mode
|
|
//
|
|
if (useUdmaMode[i]) {
|
|
|
|
GetHighestDMATransferMode(XferMode->DeviceTransferModeSupported[i], mode);
|
|
|
|
while (mode>= UDMA0) {
|
|
if ((dmaTiming <= transferModeTimingTable[mode]) &&
|
|
(XferMode->DeviceTransferModeSupported[i] & (1<<mode))) {
|
|
|
|
timingMode[i] = 1<<mode;
|
|
cycleTime[i] = transferModeTimingTable[mode];
|
|
ASSERT(cycleTime[i]);
|
|
|
|
// we got a udma mode. so don't try to find a dma mode.
|
|
useDma = FALSE;
|
|
break;
|
|
}
|
|
mode--;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// highest DMA mode
|
|
// useDma is false only when either dma is not supported or an udma mode is
|
|
// already selected.
|
|
//
|
|
if (useDma) {
|
|
|
|
ULONG tempMode;
|
|
|
|
// we shouldn't be using UDMA now.
|
|
// this will set the flags for STM correctly.
|
|
useUdmaMode[i]=FALSE;
|
|
|
|
// mask out UDMA and MWDMA0
|
|
tempMode = XferMode->
|
|
DeviceTransferModeSupported[i] & (SWDMA_SUPPORT | MWDMA_SUPPORT);
|
|
tempMode &= (~MWDMA_MODE0);
|
|
|
|
GetHighestDMATransferMode(tempMode, mode);
|
|
|
|
if (mode >= MWDMA1) {
|
|
timingMode[i] = 1<<mode;
|
|
cycleTime[i] = XferMode->BestMwDmaCycleTime[i];
|
|
ASSERT(cycleTime[i]);
|
|
} else if (mode == SWDMA2) {
|
|
timingMode[i] = 1<<mode;
|
|
cycleTime[i] = XferMode->BestSwDmaCycleTime[i];
|
|
ASSERT(cycleTime[i]);
|
|
}
|
|
// else don't do anything. PIO is already set
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((numDevices > 1) && !acpiTimingSettings->Flags.b.IndependentTiming) {
|
|
|
|
//
|
|
// pick the slower of the two timings
|
|
// (the smaller timing mode value, the slower it is)
|
|
//
|
|
|
|
if (timingMode[0] < timingMode[1]) {
|
|
|
|
cycleTime[1] = cycleTime[0];
|
|
timingMode[1] = timingMode[0];
|
|
|
|
} else {
|
|
|
|
cycleTime[0] = cycleTime[1];
|
|
timingMode[0] = timingMode[1];
|
|
}
|
|
|
|
//
|
|
// both dma mode have to be the same
|
|
//
|
|
if (useUdmaMode[0] != useUdmaMode[1]) {
|
|
useUdmaMode[0] = 0;
|
|
useUdmaMode[1] = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// store the dma mode selected
|
|
//
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
if (XferMode->DevicePresent[i]) {
|
|
|
|
XferMode->DeviceTransferModeSelected[i] |= timingMode[i];
|
|
newAcpiTimingSettings.Speed[i].Dma = cycleTime[i];
|
|
|
|
if (i==0) {
|
|
newAcpiTimingSettings.Flags.b.UltraDma0 = useUdmaMode[i];
|
|
} else {
|
|
newAcpiTimingSettings.Flags.b.UltraDma1 = useUdmaMode[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fdoExtension->DmaDetectionLevel == DdlPioOnly) {
|
|
|
|
//
|
|
// remove all DMA modes
|
|
//
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
XferMode->DeviceTransferModeSelected[i] &= PIO_SUPPORT;
|
|
}
|
|
}
|
|
|
|
if ((acpiTimingSettings->Speed[0].Pio != ACPI_XFER_MODE_NOT_SUPPORT) ||
|
|
(acpiTimingSettings->Speed[1].Pio != ACPI_XFER_MODE_NOT_SUPPORT)) {
|
|
|
|
//
|
|
// looks like we are on an ACPI machine and
|
|
// it supports IDE timing control method (_STM)
|
|
//
|
|
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
if (XferMode->DevicePresent[i]) {
|
|
|
|
ataIdentifyData[i] = fdoExtension->HwDeviceExtension->IdentifyData + i;
|
|
} else {
|
|
|
|
ataIdentifyData[i] = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// save the new timing settings
|
|
//
|
|
RtlCopyMemory (
|
|
&fdoExtension->AcpiTimingSettings,
|
|
&newAcpiTimingSettings,
|
|
sizeof(newAcpiTimingSettings));
|
|
|
|
//
|
|
// call ACPI to program the timing registers
|
|
//
|
|
status = ChannelSyncSetACPITimingSettings (
|
|
fdoExtension,
|
|
&newAcpiTimingSettings,
|
|
ataIdentifyData
|
|
);
|
|
} else {
|
|
|
|
//
|
|
// legacy controller
|
|
//
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
XferMode->DeviceTransferModeSelected[i] &= PIO_SUPPORT;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ChannelRestoreTiming (
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN PSET_ACPI_TIMING_COMPLETION_ROUTINE CallerCompletionRoutine,
|
|
IN PVOID CallerContext
|
|
)
|
|
{
|
|
ULONG i;
|
|
PIDENTIFY_DATA ataIdentifyData[MAX_IDE_DEVICE];
|
|
NTSTATUS status;
|
|
|
|
PACPI_IDE_TIMING acpiTimingSettings;
|
|
|
|
acpiTimingSettings = &FdoExtension->AcpiTimingSettings;
|
|
|
|
if (FdoExtension->NumberOfLogicalUnits &&
|
|
((acpiTimingSettings->Speed[0].Pio != ACPI_XFER_MODE_NOT_SUPPORT) ||
|
|
(acpiTimingSettings->Speed[1].Pio != ACPI_XFER_MODE_NOT_SUPPORT))) {
|
|
|
|
//
|
|
// looks like we are on an ACPI machine and
|
|
// it supports IDE timing control method (_STM)
|
|
//
|
|
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
if (FdoExtension->HwDeviceExtension->DeviceFlags[i] &
|
|
DFLAGS_DEVICE_PRESENT) {
|
|
|
|
ataIdentifyData[i] = FdoExtension->HwDeviceExtension->IdentifyData + i;
|
|
} else {
|
|
|
|
ataIdentifyData[i] = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// call ACPI to program the timing registers
|
|
//
|
|
status = ChannelSetACPITimingSettings (
|
|
FdoExtension,
|
|
acpiTimingSettings,
|
|
ataIdentifyData,
|
|
CallerCompletionRoutine,
|
|
CallerContext
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// non-acpi controller
|
|
//
|
|
|
|
if (FdoExtension->NumberOfLogicalUnits) {
|
|
AtapiSyncSelectTransferMode (
|
|
FdoExtension,
|
|
FdoExtension->HwDeviceExtension,
|
|
FdoExtension->TimingModeAllowed
|
|
);
|
|
}
|
|
|
|
(*CallerCompletionRoutine) (
|
|
FdoExtension->DeviceObject,
|
|
STATUS_SUCCESS,
|
|
CallerContext
|
|
);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ChannelRestoreTimingCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN NTSTATUS Status,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
PFDO_POWER_CONTEXT context = Context;
|
|
PIRP originalPowerIrp;
|
|
|
|
context->TimingRestored = TRUE;
|
|
|
|
originalPowerIrp = context->OriginalPowerIrp;
|
|
originalPowerIrp->IoStatus.Status = Status;
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation(originalPowerIrp);
|
|
|
|
//
|
|
// finish off the original power irp
|
|
//
|
|
FdoPowerCompletionRoutine (
|
|
thisIrpSp->DeviceObject,
|
|
originalPowerIrp,
|
|
Context
|
|
);
|
|
|
|
//
|
|
// continue with the irp completion
|
|
//
|
|
IoCompleteRequest (originalPowerIrp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ChannelFilterResourceRequirements (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PFDO_EXTENSION fdoExtension;
|
|
ULONG i, j, k;
|
|
IO_STACK_LOCATION irpSp;
|
|
PCIIDE_XFER_MODE_INTERFACE xferModeInterface;
|
|
|
|
PIO_RESOURCE_REQUIREMENTS_LIST requirementsListIn;
|
|
PIO_RESOURCE_LIST resourceListIn;
|
|
PIO_RESOURCE_DESCRIPTOR resourceDescriptorIn;
|
|
|
|
PIO_RESOURCE_DESCRIPTOR cmdRegResourceDescriptor;
|
|
PIO_RESOURCE_DESCRIPTOR ctrlRegResourceDescriptor;
|
|
PIO_RESOURCE_DESCRIPTOR intRegResourceDescriptor;
|
|
|
|
PIO_RESOURCE_REQUIREMENTS_LIST requirementsListOut;
|
|
ULONG requirementsListSizeOut;
|
|
PIO_RESOURCE_LIST resourceListOut;
|
|
PIO_RESOURCE_DESCRIPTOR resourceDescriptorOut;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// the value will stay NULL if no filtering required
|
|
//
|
|
requirementsListOut = NULL;
|
|
|
|
#ifdef IDE_FILTER_PROMISE_TECH_RESOURCES
|
|
if (NT_SUCCESS(ChannelFilterPromiseTechResourceRequirements (DeviceObject, Irp))) {
|
|
goto getout;
|
|
}
|
|
#endif // IDE_FILTER_PROMISE_TECH_RESOURCES
|
|
|
|
//
|
|
// do a simple test to check if we have a pciidex parent
|
|
//
|
|
RtlZeroMemory (&irpSp, sizeof(irpSp));
|
|
|
|
irpSp.Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCIIDE_XFER_MODE_INTERFACE;
|
|
irpSp.Parameters.QueryInterface.Version = 1;
|
|
irpSp.Parameters.QueryInterface.Size = sizeof (xferModeInterface);
|
|
irpSp.Parameters.QueryInterface.Interface = (PINTERFACE) &xferModeInterface;
|
|
irpSp.Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
|
irpSp.MajorFunction = IRP_MJ_PNP;
|
|
irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
|
|
fdoExtension = (PFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
status = IdePortSyncSendIrp (fdoExtension->AttacheeDeviceObject, &irpSp, NULL);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// we have a pciidex as a parent. it would
|
|
// take care of the resource requirement
|
|
// no need to filter
|
|
//
|
|
goto getout;
|
|
}
|
|
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
ASSERT (Irp->IoStatus.Information);
|
|
requirementsListIn = (PIO_RESOURCE_REQUIREMENTS_LIST) Irp->IoStatus.Information;
|
|
|
|
} else {
|
|
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
requirementsListIn = thisIrpSp->Parameters.FilterResourceRequirements.IoResourceRequirementList;
|
|
}
|
|
|
|
if (requirementsListIn == NULL) {
|
|
goto getout;
|
|
}
|
|
|
|
if (requirementsListIn->AlternativeLists == 0) {
|
|
goto getout;
|
|
}
|
|
|
|
requirementsListSizeOut = requirementsListIn->ListSize +
|
|
requirementsListIn->AlternativeLists *
|
|
sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
|
|
requirementsListOut = ExAllocatePool (PagedPool, requirementsListSizeOut);
|
|
if (requirementsListOut == NULL) {
|
|
goto getout;
|
|
}
|
|
|
|
*requirementsListOut = *requirementsListIn;
|
|
requirementsListOut->ListSize = requirementsListSizeOut;
|
|
|
|
//
|
|
// some init.
|
|
//
|
|
resourceListIn = requirementsListIn->List;
|
|
resourceListOut = requirementsListOut->List;
|
|
for (j=0; j<requirementsListIn->AlternativeLists; j++) {
|
|
|
|
resourceDescriptorIn = resourceListIn->Descriptors;
|
|
|
|
//
|
|
// analyze what resources we are getting
|
|
//
|
|
cmdRegResourceDescriptor = NULL;
|
|
ctrlRegResourceDescriptor = NULL;
|
|
intRegResourceDescriptor = NULL;
|
|
for (i=0; i<resourceListIn->Count; i++) {
|
|
|
|
switch (resourceDescriptorIn[i].Type) {
|
|
case CmResourceTypePort: {
|
|
|
|
if ((resourceDescriptorIn[i].u.Port.Length == 8) &&
|
|
(cmdRegResourceDescriptor == NULL)) {
|
|
|
|
cmdRegResourceDescriptor = resourceDescriptorIn + i;
|
|
|
|
} else if (((resourceDescriptorIn[i].u.Port.Length == 1) ||
|
|
(resourceDescriptorIn[i].u.Port.Length == 2) ||
|
|
(resourceDescriptorIn[i].u.Port.Length == 4)) &&
|
|
(ctrlRegResourceDescriptor == NULL)) {
|
|
|
|
ctrlRegResourceDescriptor = resourceDescriptorIn + i;
|
|
|
|
} else if ((resourceDescriptorIn[i].u.Port.Length >= 0x10) &&
|
|
(cmdRegResourceDescriptor == NULL) &&
|
|
(ctrlRegResourceDescriptor == NULL)) {
|
|
|
|
//
|
|
// probably pcmcia device. it likes to combine
|
|
// both io ranges into 1.
|
|
//
|
|
cmdRegResourceDescriptor = resourceDescriptorIn + i;
|
|
ctrlRegResourceDescriptor = resourceDescriptorIn + i;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt: {
|
|
|
|
if (intRegResourceDescriptor == NULL) {
|
|
|
|
intRegResourceDescriptor = resourceDescriptorIn + i;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// making a new copy
|
|
//
|
|
*resourceListOut = *resourceListIn;
|
|
|
|
//
|
|
// figure out what is missing
|
|
//
|
|
if (cmdRegResourceDescriptor &&
|
|
((cmdRegResourceDescriptor->u.Port.MaximumAddress.QuadPart -
|
|
cmdRegResourceDescriptor->u.Port.MinimumAddress.QuadPart + 1) == 8) &&
|
|
(ctrlRegResourceDescriptor == NULL)) {
|
|
|
|
//
|
|
// missing controller register resource descriptor.
|
|
//
|
|
|
|
resourceDescriptorOut = resourceListOut->Descriptors;
|
|
for (i=0; i<resourceListOut->Count; i++) {
|
|
|
|
*resourceDescriptorOut = resourceDescriptorIn[i];
|
|
resourceDescriptorOut++;
|
|
|
|
if ((resourceDescriptorIn + i) == cmdRegResourceDescriptor) {
|
|
|
|
//
|
|
// add the control register resource
|
|
//
|
|
*resourceDescriptorOut = resourceDescriptorIn[i];
|
|
resourceDescriptorOut->u.Port.Length = 1;
|
|
resourceDescriptorOut->u.Port.Alignment = 1;
|
|
resourceDescriptorOut->u.Port.MinimumAddress.QuadPart =
|
|
resourceDescriptorOut->u.Port.MaximumAddress.QuadPart =
|
|
cmdRegResourceDescriptor->u.Port.MinimumAddress.QuadPart + 0x206;
|
|
|
|
resourceDescriptorOut++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// account for the new control register resource
|
|
//
|
|
resourceListOut->Count++;
|
|
|
|
} else {
|
|
|
|
resourceDescriptorOut = resourceListOut->Descriptors;
|
|
k = resourceListOut->Count;
|
|
for (i = 0; i < k; i++) {
|
|
|
|
if (IsNEC_98) {
|
|
//
|
|
// NEC98 DevNode includes the ide rom memory resource.
|
|
// But it should be gotten by NTDETECT.COM&HAL.DLL, so ignore it here.
|
|
//
|
|
if ((resourceDescriptorIn[i].Type == CmResourceTypeMemory) &&
|
|
(resourceDescriptorIn[i].u.Memory.MinimumAddress.QuadPart == 0xd8000) &&
|
|
(resourceDescriptorIn[i].u.Memory.Length == 0x4000)) {
|
|
|
|
resourceListOut->Count--;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
*resourceDescriptorOut = resourceDescriptorIn[i];
|
|
resourceDescriptorOut++;
|
|
}
|
|
}
|
|
|
|
resourceListIn = (PIO_RESOURCE_LIST) (resourceDescriptorIn + resourceListIn->Count);
|
|
resourceListOut = (PIO_RESOURCE_LIST) resourceDescriptorOut;
|
|
}
|
|
|
|
|
|
getout:
|
|
if (requirementsListOut) {
|
|
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
ExFreePool ((PVOID) Irp->IoStatus.Information);
|
|
|
|
} else {
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
}
|
|
Irp->IoStatus.Information = (ULONG_PTR) requirementsListOut;
|
|
}
|
|
|
|
return IdePortPassDownToNextDriver (DeviceObject, Irp);
|
|
}
|
|
|
|
static PCWSTR PcmciaIdeChannelDeviceId = L"PCMCIA\\*PNP0600";
|
|
|
|
BOOLEAN
|
|
ChannelQueryPcmciaParent (
|
|
PFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
BOOLEAN foundIt = FALSE;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
IO_STACK_LOCATION irpSp;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// do a simple test to check if we have a pciidex parent
|
|
//
|
|
RtlZeroMemory (&irpSp, sizeof(irpSp));
|
|
|
|
irpSp.Parameters.QueryId.IdType = BusQueryHardwareIDs;
|
|
irpSp.MajorFunction = IRP_MJ_PNP;
|
|
irpSp.MinorFunction = IRP_MN_QUERY_ID;
|
|
|
|
ioStatus.Status = STATUS_NOT_SUPPORTED;
|
|
status = IdePortSyncSendIrp (FdoExtension->AttacheeDeviceObject, &irpSp, &ioStatus);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
PWSTR wstr;
|
|
UNICODE_STRING hwId;
|
|
UNICODE_STRING targetId;
|
|
|
|
RtlInitUnicodeString(
|
|
&targetId,
|
|
PcmciaIdeChannelDeviceId);
|
|
|
|
wstr = (PWSTR) ioStatus.Information;
|
|
while (*wstr) {
|
|
|
|
RtlInitUnicodeString(&hwId, wstr);
|
|
|
|
if (!RtlCompareUnicodeString(
|
|
&hwId,
|
|
&targetId,
|
|
FALSE)) {
|
|
|
|
ExFreePool ((PVOID) ioStatus.Information);
|
|
DebugPrint ((DBG_PNP, "ATAPI: pcmcia parent\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
wstr += hwId.Length / sizeof(WCHAR);
|
|
wstr++; // NULL character
|
|
}
|
|
ExFreePool ((PVOID) ioStatus.Information);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef IDE_FILTER_PROMISE_TECH_RESOURCES
|
|
|
|
static PCWSTR PromiseTechDeviceId[] = {
|
|
L"ISAPNP\\BJB1000"
|
|
};
|
|
#define NUM_PROMISE_TECH_ID (sizeof(PromiseTechDeviceId)/sizeof(PCWSTR))
|
|
|
|
NTSTATUS
|
|
ChannelFilterPromiseTechResourceRequirements (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
BOOLEAN foundIt = FALSE;
|
|
BOOLEAN firstIrq = FALSE;
|
|
ULONG numExtraIoResDescriptor = 0;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
PFDO_EXTENSION fdoExtension;
|
|
ULONG i, j, k;
|
|
IO_STACK_LOCATION irpSp;
|
|
PCIIDE_XFER_MODE_INTERFACE xferModeInterface;
|
|
|
|
PIO_RESOURCE_REQUIREMENTS_LIST requirementsListIn;
|
|
PIO_RESOURCE_LIST resourceListIn;
|
|
PIO_RESOURCE_DESCRIPTOR resourceDescriptorIn;
|
|
PIO_RESOURCE_DESCRIPTOR brokenResourceDescriptor;
|
|
|
|
PIO_RESOURCE_DESCRIPTOR cmdRegResourceDescriptor;
|
|
PIO_RESOURCE_DESCRIPTOR ctrlRegResourceDescriptor;
|
|
PIO_RESOURCE_DESCRIPTOR intRegResourceDescriptor;
|
|
|
|
PIO_RESOURCE_REQUIREMENTS_LIST requirementsListOut;
|
|
ULONG requirementsListSizeOut;
|
|
PIO_RESOURCE_LIST resourceListOut;
|
|
PIO_RESOURCE_DESCRIPTOR resourceDescriptorOut;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// the value will stay NULL if no filtering required
|
|
//
|
|
requirementsListOut = NULL;
|
|
|
|
//
|
|
// do a simple test to check if we have a pciidex parent
|
|
//
|
|
RtlZeroMemory (&irpSp, sizeof(irpSp));
|
|
|
|
irpSp.Parameters.QueryId.IdType = BusQueryDeviceID;
|
|
irpSp.MajorFunction = IRP_MJ_PNP;
|
|
irpSp.MinorFunction = IRP_MN_QUERY_ID;
|
|
|
|
fdoExtension = (PFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
ioStatus.Status = STATUS_NOT_SUPPORTED;
|
|
status = IdePortSyncSendIrp (fdoExtension->AttacheeDeviceObject, &irpSp, &ioStatus);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
UNICODE_STRING deviceId;
|
|
UNICODE_STRING promiseTechDeviceId;
|
|
|
|
RtlInitUnicodeString(
|
|
&deviceId,
|
|
(PCWSTR) ioStatus.Information);
|
|
|
|
for (i=0; i<NUM_PROMISE_TECH_ID && !foundIt; i++) {
|
|
|
|
RtlInitUnicodeString(
|
|
&promiseTechDeviceId,
|
|
PromiseTechDeviceId[i]);
|
|
|
|
if (deviceId.Length >= promiseTechDeviceId.Length) {
|
|
deviceId.Length = promiseTechDeviceId.Length;
|
|
if (!RtlCompareUnicodeString(
|
|
&promiseTechDeviceId,
|
|
&deviceId,
|
|
FALSE)) {
|
|
|
|
foundIt = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
ExFreePool ((PVOID) ioStatus.Information);
|
|
}
|
|
|
|
if (!foundIt) {
|
|
goto getout;
|
|
}
|
|
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
ASSERT (Irp->IoStatus.Information);
|
|
requirementsListIn = (PIO_RESOURCE_REQUIREMENTS_LIST) Irp->IoStatus.Information;
|
|
|
|
} else {
|
|
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
requirementsListIn = thisIrpSp->Parameters.FilterResourceRequirements.IoResourceRequirementList;
|
|
}
|
|
|
|
if (requirementsListIn == NULL) {
|
|
goto getout;
|
|
}
|
|
|
|
if (requirementsListIn->AlternativeLists == 0) {
|
|
goto getout;
|
|
}
|
|
|
|
//
|
|
// look for the bad resource descriptior
|
|
//
|
|
resourceListIn = requirementsListIn->List;
|
|
brokenResourceDescriptor = NULL;
|
|
for (j=0; j<requirementsListIn->AlternativeLists; j++) {
|
|
|
|
resourceDescriptorIn = resourceListIn->Descriptors;
|
|
|
|
//
|
|
// analyze what resources we are getting
|
|
//
|
|
for (i=0; i<resourceListIn->Count; i++) {
|
|
|
|
switch (resourceDescriptorIn[i].Type) {
|
|
case CmResourceTypePort: {
|
|
|
|
ULONG alignmentMask;
|
|
|
|
alignmentMask = resourceDescriptorIn[i].u.Port.Alignment - 1;
|
|
|
|
if (resourceDescriptorIn[i].u.Port.MinimumAddress.LowPart & alignmentMask) {
|
|
|
|
//
|
|
// broken resource requirement;
|
|
//
|
|
brokenResourceDescriptor = resourceDescriptorIn + i;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (brokenResourceDescriptor) {
|
|
|
|
ULONG alignmentMask;
|
|
PHYSICAL_ADDRESS minAddress;
|
|
PHYSICAL_ADDRESS addressRange;
|
|
|
|
alignmentMask = brokenResourceDescriptor->u.Port.Alignment - 1;
|
|
alignmentMask = ~alignmentMask;
|
|
|
|
minAddress = brokenResourceDescriptor->u.Port.MinimumAddress;
|
|
minAddress.LowPart &= alignmentMask;
|
|
|
|
addressRange.QuadPart = (brokenResourceDescriptor->u.Port.MaximumAddress.QuadPart - minAddress.QuadPart);
|
|
numExtraIoResDescriptor = (ULONG) (addressRange.QuadPart / brokenResourceDescriptor->u.Port.Alignment);
|
|
}
|
|
|
|
requirementsListSizeOut = requirementsListIn->ListSize +
|
|
numExtraIoResDescriptor *
|
|
sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
|
|
requirementsListOut = ExAllocatePool (PagedPool, requirementsListSizeOut);
|
|
if (requirementsListOut == NULL) {
|
|
goto getout;
|
|
}
|
|
|
|
*requirementsListOut = *requirementsListIn;
|
|
requirementsListOut->ListSize = requirementsListSizeOut;
|
|
|
|
//
|
|
// some init.
|
|
//
|
|
resourceListIn = requirementsListIn->List;
|
|
resourceListOut = requirementsListOut->List;
|
|
for (j=0; j<requirementsListIn->AlternativeLists; j++) {
|
|
|
|
resourceDescriptorIn = resourceListIn->Descriptors;
|
|
|
|
//
|
|
// making a new copy
|
|
//
|
|
*resourceListOut = *resourceListIn;
|
|
resourceListOut->Count = 0;
|
|
|
|
//
|
|
// analyze what resources we are getting
|
|
//
|
|
resourceDescriptorOut = resourceListOut->Descriptors;
|
|
firstIrq = TRUE;
|
|
for (i=0; i<resourceListIn->Count; i++) {
|
|
|
|
switch (resourceDescriptorIn[i].Type) {
|
|
case CmResourceTypePort: {
|
|
|
|
if ((resourceDescriptorIn + i == brokenResourceDescriptor) &&
|
|
(numExtraIoResDescriptor)) {
|
|
|
|
for (k=0; k<numExtraIoResDescriptor; k++) {
|
|
|
|
*resourceDescriptorOut = resourceDescriptorIn[i];
|
|
|
|
if (k != 0) {
|
|
|
|
resourceDescriptorOut->Option = IO_RESOURCE_ALTERNATIVE;
|
|
|
|
}
|
|
|
|
resourceDescriptorOut->u.Port.Alignment = 1;
|
|
resourceDescriptorOut->u.Port.MinimumAddress.QuadPart =
|
|
brokenResourceDescriptor->u.Port.MinimumAddress.QuadPart +
|
|
k * brokenResourceDescriptor->u.Port.Alignment;
|
|
resourceDescriptorOut->u.Port.MaximumAddress.QuadPart =
|
|
resourceDescriptorOut->u.Port.MinimumAddress.QuadPart +
|
|
resourceDescriptorOut->u.Port.Length - 1;
|
|
|
|
resourceDescriptorOut++;
|
|
resourceListOut->Count++;
|
|
}
|
|
|
|
} else {
|
|
|
|
*resourceDescriptorOut = resourceDescriptorIn[i];
|
|
resourceDescriptorOut++;
|
|
resourceListOut->Count++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt: {
|
|
|
|
//
|
|
// keep all irqs except 9 which doesn't really work
|
|
//
|
|
if (!((resourceDescriptorIn[i].u.Interrupt.MinimumVector == 0x9) &&
|
|
(resourceDescriptorIn[i].u.Interrupt.MaximumVector == 0x9))) {
|
|
|
|
*resourceDescriptorOut = resourceDescriptorIn[i];
|
|
|
|
if (firstIrq) {
|
|
resourceDescriptorOut->Option = 0;
|
|
firstIrq = FALSE;
|
|
} else {
|
|
resourceDescriptorOut->Option = IO_RESOURCE_ALTERNATIVE;
|
|
}
|
|
|
|
resourceDescriptorOut++;
|
|
resourceListOut->Count++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
*resourceDescriptorOut = resourceDescriptorIn[i];
|
|
resourceDescriptorOut++;
|
|
resourceListOut->Count++;
|
|
break;
|
|
}
|
|
}
|
|
resourceListIn = (PIO_RESOURCE_LIST) (resourceDescriptorIn + resourceListIn->Count);
|
|
resourceListOut = (PIO_RESOURCE_LIST) resourceDescriptorOut;
|
|
}
|
|
|
|
|
|
getout:
|
|
if (requirementsListOut) {
|
|
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
ExFreePool ((PVOID) Irp->IoStatus.Information);
|
|
|
|
} else {
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
}
|
|
Irp->IoStatus.Information = (ULONG_PTR) requirementsListOut;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
#endif // IDE_FILTER_PROMISE_TECH_RESOURCES
|
|
|
|
NTSTATUS
|
|
ChannelQueryPnPDeviceState (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension;
|
|
PPNP_DEVICE_STATE deviceState;
|
|
|
|
fdoExtension = (PFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
DebugPrint((DBG_PNP, "QUERY_DEVICE_STATE for FDOE 0x%x\n", fdoExtension));
|
|
|
|
if(fdoExtension->PagingPathCount != 0) {
|
|
deviceState = (PPNP_DEVICE_STATE) &(Irp->IoStatus.Information);
|
|
SETMASK((*deviceState), PNP_DEVICE_NOT_DISABLEABLE);
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
IoSkipCurrentIrpStackLocation (Irp);
|
|
return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
}
|
|
|