2482 lines
69 KiB
C
2482 lines
69 KiB
C
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// File: ctlrfdo.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "pciidex.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, ControllerAddDevice)
|
|
#pragma alloc_text(PAGE, ControllerStartDevice)
|
|
#pragma alloc_text(PAGE, ControllerStopDevice)
|
|
#pragma alloc_text(PAGE, ControllerStopController)
|
|
#pragma alloc_text(PAGE, ControllerSurpriseRemoveDevice)
|
|
#pragma alloc_text(PAGE, ControllerRemoveDevice)
|
|
#pragma alloc_text(PAGE, ControllerQueryDeviceRelations)
|
|
#pragma alloc_text(PAGE, ControllerQueryInterface)
|
|
#pragma alloc_text(PAGE, AnalyzeResourceList)
|
|
#pragma alloc_text(PAGE, ControllerOpMode)
|
|
#pragma alloc_text(PAGE, PciIdeChannelEnabled)
|
|
#pragma alloc_text(PAGE, PciIdeCreateTimingTable)
|
|
#pragma alloc_text(PAGE, PciIdeInitControllerProperties)
|
|
#pragma alloc_text(PAGE, ControllerUsageNotification)
|
|
#pragma alloc_text(PAGE, PciIdeGetBusStandardInterface)
|
|
#pragma alloc_text(PAGE, ControllerQueryPnPDeviceState)
|
|
|
|
#pragma alloc_text(NONPAGE, EnablePCIBusMastering)
|
|
#pragma alloc_text(NONPAGE, ControllerUsageNotificationCompletionRoutine)
|
|
#pragma alloc_text(NONPAGE, ControllerRemoveDeviceCompletionRoutine)
|
|
#pragma alloc_text(NONPAGE, ControllerStartDeviceCompletionRoutine)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
//
|
|
// Must match mshdc.inf
|
|
//
|
|
static PWCHAR ChannelEnableMaskName[MAX_IDE_CHANNEL] = {
|
|
L"MasterOnMask",
|
|
L"SlaveOnMask"
|
|
};
|
|
static PWCHAR ChannelEnablePciConfigOffsetName[MAX_IDE_CHANNEL] = {
|
|
L"MasterOnConfigOffset",
|
|
L"SlaveOnConfigOffset"
|
|
};
|
|
|
|
|
|
static ULONG PciIdeXNextControllerNumber = 0;
|
|
static ULONG PciIdeXNextChannelNumber = 0;
|
|
|
|
NTSTATUS
|
|
ControllerAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
{
|
|
PDEVICE_OBJECT deviceObject;
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
NTSTATUS status;
|
|
PDRIVER_OBJECT_EXTENSION driverObjectExtension;
|
|
ULONG deviceExtensionSize;
|
|
UNICODE_STRING deviceName;
|
|
WCHAR deviceNameBuffer[64];
|
|
ULONG controllerNumber;
|
|
|
|
PAGED_CODE();
|
|
|
|
driverObjectExtension =
|
|
(PDRIVER_OBJECT_EXTENSION) IoGetDriverObjectExtension(
|
|
DriverObject,
|
|
DRIVER_OBJECT_EXTENSION_ID
|
|
);
|
|
ASSERT (driverObjectExtension);
|
|
|
|
//
|
|
// devobj name
|
|
//
|
|
controllerNumber = InterlockedIncrement(&PciIdeXNextControllerNumber) - 1;
|
|
swprintf(deviceNameBuffer, DEVICE_OJBECT_BASE_NAME L"\\PciIde%d", controllerNumber);
|
|
RtlInitUnicodeString(&deviceName, deviceNameBuffer);
|
|
|
|
deviceExtensionSize = sizeof(CTRLFDO_EXTENSION) +
|
|
driverObjectExtension->ExtensionSize;
|
|
|
|
//
|
|
// We've been given the PhysicalDeviceObject for an IDE controller. Create the
|
|
// FunctionalDeviceObject. Our FDO will be nameless.
|
|
//
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject, // our driver object
|
|
deviceExtensionSize, // size of our extension
|
|
&deviceName, // our name
|
|
FILE_DEVICE_BUS_EXTENDER, // device type
|
|
FILE_DEVICE_SECURE_OPEN, // device characteristics
|
|
FALSE, // not exclusive
|
|
&deviceObject // store new device object here
|
|
);
|
|
|
|
if( !NT_SUCCESS( status )){
|
|
|
|
return status;
|
|
}
|
|
|
|
fdoExtension = (PCTRLFDO_EXTENSION)deviceObject->DeviceExtension;
|
|
RtlZeroMemory (fdoExtension, deviceExtensionSize);
|
|
|
|
//
|
|
// We have our FunctionalDeviceObject, initialize it.
|
|
//
|
|
|
|
fdoExtension->AttacheePdo = PhysicalDeviceObject;
|
|
fdoExtension->DeviceObject = deviceObject;
|
|
fdoExtension->DriverObject = DriverObject;
|
|
fdoExtension->ControllerNumber = controllerNumber;
|
|
fdoExtension->VendorSpecificDeviceEntension = fdoExtension + 1;
|
|
|
|
// Dispatch Table
|
|
fdoExtension->DefaultDispatch = PassDownToNextDriver;
|
|
fdoExtension->PnPDispatchTable = FdoPnpDispatchTable;
|
|
fdoExtension->PowerDispatchTable = FdoPowerDispatchTable;
|
|
fdoExtension->WmiDispatchTable = FdoWmiDispatchTable;
|
|
|
|
//
|
|
// Get the Device Control Flags out of the registry
|
|
//
|
|
fdoExtension->DeviceControlsFlags = 0;
|
|
status = PciIdeXGetDeviceParameter (
|
|
fdoExtension->AttacheePdo,
|
|
L"DeviceControlFlags",
|
|
&fdoExtension->DeviceControlsFlags
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DebugPrint ((1, "PciIdeX: Unable to get DeviceControlFlags from the registry\n"));
|
|
|
|
//
|
|
// this is not a serious error...continue to load
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Now attach to the PDO we were given.
|
|
//
|
|
fdoExtension->AttacheeDeviceObject = IoAttachDeviceToDeviceStack (
|
|
deviceObject,
|
|
PhysicalDeviceObject
|
|
);
|
|
|
|
if (fdoExtension->AttacheeDeviceObject == NULL){
|
|
|
|
//
|
|
// Couldn't attach. Delete the FDO.
|
|
//
|
|
|
|
IoDeleteDevice (deviceObject);
|
|
|
|
} else {
|
|
|
|
//
|
|
// fix up alignment requirement
|
|
//
|
|
deviceObject->AlignmentRequirement = fdoExtension->AttacheeDeviceObject->AlignmentRequirement;
|
|
if (deviceObject->AlignmentRequirement < 1) {
|
|
deviceObject->AlignmentRequirement = 1;
|
|
}
|
|
|
|
//
|
|
// get the standard bus interface
|
|
// (for READ_CONFIG/WRITE_CONFIG
|
|
//
|
|
status = PciIdeGetBusStandardInterface(fdoExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
IoDetachDevice (fdoExtension->AttacheeDeviceObject);
|
|
IoDeleteDevice (deviceObject);
|
|
|
|
return status;
|
|
}
|
|
//
|
|
// Init operating mode (native or legacy)
|
|
//
|
|
ControllerOpMode (fdoExtension);
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
if (IsNativeMode(fdoExtension)) {
|
|
|
|
NTSTATUS interfaceStatus = PciIdeGetNativeModeInterface(fdoExtension);
|
|
|
|
//
|
|
// bad pci.sys.
|
|
// we should still work. However, the window where an interrupt fires before
|
|
// we are ready to dismiss it would not be closed. Can't do much at this point.
|
|
//
|
|
|
|
//ASSERT(NT_SUCCESS(interfaceStatus));
|
|
}
|
|
#endif
|
|
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
}
|
|
|
|
return status;
|
|
} // ControllerAddDevice
|
|
|
|
|
|
NTSTATUS
|
|
ControllerStartDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
NTSTATUS status;
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
PCM_RESOURCE_LIST resourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR irqPartialDescriptors;
|
|
ULONG i;
|
|
|
|
KEVENT event;
|
|
|
|
POWER_STATE powerState;
|
|
|
|
PAGED_CODE();
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
resourceList = thisIrpSp->Parameters.StartDevice.AllocatedResourcesTranslated;
|
|
|
|
if (!resourceList) {
|
|
|
|
DebugPrint ((1, "PciIde: Starting with no resource\n"));
|
|
}
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
|
|
//
|
|
// Let PCI know that we will manage the decodes
|
|
//
|
|
if (IsNativeMode(fdoExtension)) {
|
|
ControllerDisableInterrupt(fdoExtension);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Call the lower level drivers with a the Irp
|
|
//
|
|
KeInitializeEvent(&event,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
ControllerStartDeviceCompletionRoutine,
|
|
&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)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
powerState.SystemState = PowerSystemWorking;
|
|
status = PciIdeIssueSetPowerState (
|
|
fdoExtension,
|
|
SystemPowerState,
|
|
powerState,
|
|
TRUE
|
|
);
|
|
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;
|
|
}
|
|
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
status= PciIdeIssueSetPowerState (
|
|
fdoExtension,
|
|
DevicePowerState,
|
|
powerState,
|
|
TRUE
|
|
);
|
|
if (status == STATUS_INVALID_DEVICE_REQUEST) {
|
|
|
|
//
|
|
// The DeviceObject Below us does not support power irp,
|
|
// pretend we are powered up
|
|
//
|
|
fdoExtension->DevicePowerState = PowerDeviceD0;
|
|
|
|
} else if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
if (!IsNativeMode(fdoExtension)) {
|
|
#endif
|
|
|
|
//
|
|
// Turn on PCI busmastering
|
|
//
|
|
EnablePCIBusMastering (
|
|
fdoExtension
|
|
);
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
}
|
|
#endif
|
|
//
|
|
// Initialize a fast mutex for later use
|
|
//
|
|
KeInitializeSpinLock(
|
|
&fdoExtension->PciConfigDataLock
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// Analyze the resources
|
|
//
|
|
status = AnalyzeResourceList (fdoExtension, resourceList);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// Initialize controller properties. We need the resources
|
|
// at this point for Native mode IDE controllers
|
|
//
|
|
PciIdeInitControllerProperties (
|
|
fdoExtension
|
|
);
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
if (IsNativeMode(fdoExtension)) {
|
|
|
|
IDE_CHANNEL_STATE channelState;
|
|
|
|
#if DBG
|
|
{
|
|
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
|
|
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
|
|
ULONG resourceListSize;
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
fullResourceList = resourceList->List;
|
|
resourceListSize = 0;
|
|
|
|
DebugPrint ((1, "Pciidex: Starting native mode 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, "pciidex: 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, "pciidex: Int Level = 0x%x. Int Vector = 0x%x\n", partialDescriptors[j].u.Interrupt.Level, partialDescriptors[j].u.Interrupt.Vector));
|
|
} else {
|
|
DebugPrint ((1, "pciidex: Unknown resource\n"));
|
|
}
|
|
}
|
|
fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + j);
|
|
}
|
|
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
|
|
fdoExtension->ControllerIsrInstalled = FALSE;
|
|
|
|
for (i=0; i< MAX_IDE_CHANNEL; i++) {
|
|
|
|
|
|
//
|
|
// Analyze the resources we are getting
|
|
//
|
|
status = DigestResourceList(
|
|
&fdoExtension->IdeResource,
|
|
fdoExtension->PdoResourceList[i],
|
|
&fdoExtension->IrqPartialDescriptors[i]
|
|
);
|
|
|
|
if (!NT_SUCCESS(status) ) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
if (!fdoExtension->IrqPartialDescriptors[i]) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
DebugPrint((1,
|
|
"Pciidex: Connecting interrupt for channel %x interrupt vector 0x%x\n",
|
|
i,
|
|
fdoExtension->IrqPartialDescriptors[i]->u.Interrupt.Vector
|
|
));
|
|
|
|
channelState = PciIdeChannelEnabled (fdoExtension, i);
|
|
|
|
if (channelState != ChannelDisabled) {
|
|
|
|
//
|
|
// Build io address structure.
|
|
//
|
|
AtapiBuildIoAddress(
|
|
fdoExtension->IdeResource.TranslatedCommandBaseAddress,
|
|
fdoExtension->IdeResource.TranslatedControlBaseAddress,
|
|
&fdoExtension->BaseIoAddress1[i],
|
|
&fdoExtension->BaseIoAddress2[i],
|
|
&fdoExtension->BaseIoAddress1Length[i],
|
|
&fdoExtension->BaseIoAddress2Length[i],
|
|
&fdoExtension->MaxIdeDevice[i],
|
|
NULL);
|
|
|
|
//
|
|
// Install the ISR
|
|
//
|
|
status = ControllerInterruptControl(fdoExtension, i, 0);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
//
|
|
// This flag is needed for the ISR to enable interrupts.
|
|
//
|
|
fdoExtension->ControllerIsrInstalled = TRUE;
|
|
|
|
//
|
|
// Enable the interrupt in both the channels
|
|
//
|
|
ControllerEnableInterrupt(fdoExtension);
|
|
|
|
fdoExtension->NativeInterruptEnabled = TRUE;
|
|
|
|
//
|
|
// See the comments in the ISR regarding these flags
|
|
//
|
|
ASSERT(fdoExtension->ControllerIsrInstalled == TRUE);
|
|
ASSERT(fdoExtension->NativeInterruptEnabled == TRUE);
|
|
|
|
//
|
|
// Turn on PCI busmastering
|
|
//
|
|
EnablePCIBusMastering (
|
|
fdoExtension
|
|
);
|
|
|
|
for (i=0; i< MAX_IDE_CHANNEL; i++) {
|
|
|
|
PIDE_BUS_MASTER_REGISTERS bmRegister;
|
|
|
|
//
|
|
// Check the bus master registers
|
|
//
|
|
bmRegister = (PIDE_BUS_MASTER_REGISTERS)(((PUCHAR)fdoExtension->TranslatedBusMasterBaseAddress) + i*8);
|
|
|
|
if (READ_PORT_UCHAR (&bmRegister->Status) & BUSMASTER_ZERO_BITS) {
|
|
fdoExtension->NoBusMaster[i] = TRUE;
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
status = PciIdeCreateSyncChildAccess (fdoExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
status = PciIdeCreateTimingTable(fdoExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto GetOut;
|
|
}
|
|
|
|
GetOut:
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
#if DBG
|
|
{
|
|
PCM_RESOURCE_LIST resourceList;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
|
|
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
|
|
ULONG i;
|
|
ULONG j;
|
|
ULONG k;
|
|
|
|
DebugPrint ((1, "PciIdeX: Starting device:\n"));
|
|
|
|
for (k=0; k <MAX_IDE_CHANNEL + 1; k++) {
|
|
|
|
if (k == MAX_IDE_CHANNEL) {
|
|
|
|
DebugPrint ((1, "PciIdeX: Busmaster resources:\n"));
|
|
|
|
resourceList = fdoExtension->BmResourceList;
|
|
} else {
|
|
|
|
DebugPrint ((1, "PciIdeX: PDO %d resources:\n", k));
|
|
resourceList = fdoExtension->PdoResourceList[k];
|
|
}
|
|
|
|
if (resourceList) {
|
|
|
|
fullResourceList = resourceList->List;
|
|
|
|
|
|
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 == CmResourceTypeMemory) {
|
|
DebugPrint ((1, "IdePort: Memory Port = 0x%x. Lenght = 0x%x\n", partialDescriptors[j].u.Memory.Start.LowPart, partialDescriptors[j].u.Memory.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
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
|
|
return status;
|
|
} // ControllerStartDevice
|
|
|
|
NTSTATUS
|
|
ControllerStartDeviceCompletionRoutine(
|
|
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;
|
|
} // ControllerStartDeviceCompletionRoutine
|
|
|
|
NTSTATUS
|
|
ControllerStopDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PCTRLFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
status = ControllerStopController (
|
|
fdoExtension
|
|
);
|
|
ASSERT (NT_SUCCESS(status));
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
} // ControllerStopDevice
|
|
|
|
|
|
NTSTATUS
|
|
ControllerStopController (
|
|
IN PCTRLFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (FdoExtension->BmResourceList) {
|
|
ExFreePool (FdoExtension->BmResourceList);
|
|
FdoExtension->BmResourceList = NULL;
|
|
}
|
|
|
|
for (i=0; i<MAX_IDE_CHANNEL; i++) {
|
|
if (FdoExtension->PdoResourceList[i]) {
|
|
ExFreePool (FdoExtension->PdoResourceList[i]);
|
|
FdoExtension->PdoResourceList[i] = NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
|
|
//
|
|
// We need to reset the flags in this order. Otherwise an interrupt would
|
|
// result in the decodes to be enabled by the ISR. See the comments in the ISR
|
|
//
|
|
FdoExtension->ControllerIsrInstalled = FALSE;
|
|
ControllerDisableInterrupt(FdoExtension);
|
|
FdoExtension->NativeInterruptEnabled = FALSE;
|
|
|
|
for (i=0; i< MAX_IDE_CHANNEL; i++) {
|
|
|
|
NTSTATUS status;
|
|
DebugPrint((1, "Pciidex: DisConnecting interrupt for channel %x\n", i));
|
|
|
|
//
|
|
// Disconnect the ISR
|
|
//
|
|
status = ControllerInterruptControl(FdoExtension, i, 1 );
|
|
|
|
ASSERT(NT_SUCCESS(status));
|
|
|
|
}
|
|
|
|
ASSERT(FdoExtension->ControllerIsrInstalled == FALSE);
|
|
ASSERT(FdoExtension->NativeInterruptEnabled == FALSE);
|
|
|
|
#endif
|
|
|
|
PciIdeDeleteSyncChildAccess (FdoExtension);
|
|
|
|
return STATUS_SUCCESS;
|
|
} // ControllerStopController
|
|
|
|
|
|
NTSTATUS
|
|
ControllerSurpriseRemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PCTRLFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
NTSTATUS status;
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
#if DBG
|
|
//
|
|
// make sure all the children are removed or surprise removed
|
|
//
|
|
for (i=0; i<MAX_IDE_CHANNEL; i++) {
|
|
|
|
PCHANPDO_EXTENSION pdoExtension;
|
|
|
|
pdoExtension = fdoExtension->ChildDeviceExtension[i];
|
|
|
|
if (pdoExtension) {
|
|
|
|
ASSERT (pdoExtension->PdoState & (PDOS_SURPRISE_REMOVED | PDOS_REMOVED));
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
status = ControllerStopController (fdoExtension);
|
|
ASSERT (NT_SUCCESS(status));
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation ( Irp );
|
|
return IoCallDriver(fdoExtension->AttacheeDeviceObject, Irp);
|
|
|
|
} // ControllerSurpriseRemoveDevice
|
|
|
|
|
|
NTSTATUS
|
|
ControllerRemoveDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PCTRLFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
NTSTATUS status;
|
|
KEVENT event;
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Kill all the children if any
|
|
//
|
|
for (i=0; i<MAX_IDE_CHANNEL; i++) {
|
|
|
|
PCHANPDO_EXTENSION pdoExtension;
|
|
|
|
pdoExtension = fdoExtension->ChildDeviceExtension[i];
|
|
|
|
if (pdoExtension) {
|
|
|
|
status = ChannelStopChannel (pdoExtension);
|
|
ASSERT (NT_SUCCESS(status));
|
|
|
|
//
|
|
// mark this device invalid
|
|
//
|
|
ChannelUpdatePdoState (
|
|
pdoExtension,
|
|
PDOS_DEADMEAT | PDOS_REMOVED,
|
|
0
|
|
);
|
|
|
|
IoDeleteDevice (pdoExtension->DeviceObject);
|
|
fdoExtension->ChildDeviceExtension[i] = NULL;
|
|
}
|
|
}
|
|
|
|
status = ControllerStopController (fdoExtension);
|
|
ASSERT (NT_SUCCESS(status));
|
|
|
|
if (fdoExtension->TransferModeTimingTable) {
|
|
ExFreePool(fdoExtension->TransferModeTimingTable);
|
|
fdoExtension->TransferModeTimingTable = NULL;
|
|
fdoExtension->TransferModeTableLength = 0;
|
|
}
|
|
|
|
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
IoSetCompletionRoutine(
|
|
Irp,
|
|
ControllerRemoveDeviceCompletionRoutine,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
status = IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
}
|
|
|
|
IoDetachDevice (fdoExtension->AttacheeDeviceObject);
|
|
|
|
IoDeleteDevice (DeviceObject);
|
|
|
|
//return STATUS_SUCCESS;
|
|
return status;
|
|
} // ControllerRemoveDevice
|
|
|
|
|
|
NTSTATUS
|
|
ControllerRemoveDeviceCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PKEVENT event = Context;
|
|
|
|
KeSetEvent(event, 0, FALSE);
|
|
|
|
return STATUS_SUCCESS;
|
|
} // ControllerRemoveDeviceCompletionRoutine
|
|
|
|
NTSTATUS
|
|
ControllerQueryDeviceRelations (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
NTSTATUS status;
|
|
ULONG deviceRelationsSize;
|
|
ULONG channel;
|
|
PCONFIGURATION_INFORMATION configurationInformation = IoGetConfigurationInformation();
|
|
ULONG nextUniqueNumber;
|
|
|
|
PAGED_CODE();
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
status = STATUS_SUCCESS;
|
|
|
|
switch (thisIrpSp->Parameters.QueryDeviceRelations.Type) {
|
|
case BusRelations:
|
|
DebugPrint ((3, "ControllerQueryDeviceRelations: bus relations\n"));
|
|
|
|
deviceRelationsSize = FIELD_OFFSET (DEVICE_RELATIONS, Objects) +
|
|
MAX_IDE_CHANNEL * sizeof(PDEVICE_OBJECT);
|
|
|
|
deviceRelations = ExAllocatePool (PagedPool, deviceRelationsSize);
|
|
|
|
if(!deviceRelations) {
|
|
|
|
DebugPrint ((1,
|
|
"IdeQueryDeviceRelations: Unable to allocate DeviceRelations structures\n"));
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
LARGE_INTEGER tickCount;
|
|
ULONG newBusScanTime;
|
|
ULONG newBusScanTimeDelta;
|
|
BOOLEAN reportUnknownAsNewChild;
|
|
|
|
//
|
|
// determine if we should return unknown child as new child
|
|
// unknown child is IDE channel which we don't know
|
|
// it is enabled or not unless we pnp start the channel
|
|
// and poke at it to find out.
|
|
//
|
|
// since we don't want to go into an infinite cycle of
|
|
// starting and failing start on a unknown child, we will
|
|
// limit our frequency
|
|
//
|
|
KeQueryTickCount(&tickCount);
|
|
newBusScanTime = (ULONG) ((tickCount.QuadPart *
|
|
((ULONGLONG) KeQueryTimeIncrement())) / ((ULONGLONG) 10000000));
|
|
newBusScanTimeDelta = newBusScanTime - fdoExtension->LastBusScanTime;
|
|
DebugPrint ((1, "PCIIDEX: Last rescan was %d seconds ago.\n", newBusScanTimeDelta));
|
|
|
|
if ((newBusScanTimeDelta < MIN_BUS_SCAN_PERIOD_IN_SEC) &&
|
|
(fdoExtension->LastBusScanTime != 0)) {
|
|
|
|
reportUnknownAsNewChild = FALSE;
|
|
|
|
} else {
|
|
|
|
reportUnknownAsNewChild = TRUE;
|
|
}
|
|
fdoExtension->LastBusScanTime = newBusScanTime;
|
|
|
|
RtlZeroMemory (deviceRelations, deviceRelationsSize);
|
|
|
|
for (channel = 0; channel < MAX_IDE_CHANNEL; channel++) {
|
|
|
|
PDEVICE_OBJECT deviceObject;
|
|
PCHANPDO_EXTENSION pdoExtension;
|
|
UNICODE_STRING deviceName;
|
|
WCHAR deviceNameBuffer[256];
|
|
PDEVICE_OBJECT deviceObjectToReturn;
|
|
IDE_CHANNEL_STATE channelState;
|
|
|
|
deviceObjectToReturn = NULL;
|
|
|
|
pdoExtension = fdoExtension->ChildDeviceExtension[channel];
|
|
channelState = PciIdeChannelEnabled (fdoExtension, channel);
|
|
|
|
if (pdoExtension) {
|
|
|
|
//
|
|
// already got a DeviceObject for this channel
|
|
//
|
|
if (channelState == ChannelDisabled) {
|
|
|
|
ULONG pdoState;
|
|
|
|
pdoState = ChannelUpdatePdoState (
|
|
pdoExtension,
|
|
PDOS_DEADMEAT,
|
|
0
|
|
);
|
|
} else {
|
|
|
|
deviceObjectToReturn = pdoExtension->DeviceObject;
|
|
}
|
|
|
|
} else if ((channelState == ChannelEnabled) ||
|
|
((channelState == ChannelStateUnknown) && reportUnknownAsNewChild)) {
|
|
|
|
if (!fdoExtension->NativeMode[channel]) {
|
|
|
|
if (channel == 0) {
|
|
|
|
configurationInformation->AtDiskPrimaryAddressClaimed = TRUE;
|
|
|
|
} else {
|
|
|
|
configurationInformation->AtDiskSecondaryAddressClaimed = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remove this when pnp mgr can deal with pdo with no names
|
|
//
|
|
nextUniqueNumber = InterlockedIncrement(&PciIdeXNextChannelNumber) - 1;
|
|
swprintf(deviceNameBuffer, DEVICE_OJBECT_BASE_NAME L"\\PciIde%dChannel%d-%x", fdoExtension->ControllerNumber, channel, nextUniqueNumber);
|
|
RtlInitUnicodeString (&deviceName, deviceNameBuffer);
|
|
|
|
status = IoCreateDevice(
|
|
fdoExtension->DriverObject, // our driver object
|
|
sizeof(CHANPDO_EXTENSION), // size of our extension
|
|
&deviceName, // our name
|
|
FILE_DEVICE_CONTROLLER, // device type
|
|
FILE_DEVICE_SECURE_OPEN, // device characteristics
|
|
FALSE, // not exclusive
|
|
&deviceObject // store new device object here
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
pdoExtension = (PCHANPDO_EXTENSION) deviceObject->DeviceExtension;
|
|
RtlZeroMemory (pdoExtension, sizeof(CHANPDO_EXTENSION));
|
|
|
|
pdoExtension->DeviceObject = deviceObject;
|
|
pdoExtension->DriverObject = fdoExtension->DriverObject;
|
|
pdoExtension->ParentDeviceExtension = fdoExtension;
|
|
pdoExtension->ChannelNumber = channel;
|
|
|
|
//
|
|
// Dispatch Table
|
|
//
|
|
pdoExtension->DefaultDispatch = NoSupportIrp;
|
|
pdoExtension->PnPDispatchTable = PdoPnpDispatchTable;
|
|
pdoExtension->PowerDispatchTable = PdoPowerDispatchTable;
|
|
pdoExtension->WmiDispatchTable = PdoWmiDispatchTable;
|
|
|
|
KeInitializeSpinLock(&pdoExtension->SpinLock);
|
|
|
|
fdoExtension->ChildDeviceExtension[channel] = pdoExtension;
|
|
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
fdoExtension->NumberOfChildren++;
|
|
|
|
InterlockedIncrement(&fdoExtension->NumberOfChildrenPowerUp);
|
|
|
|
//
|
|
// fix up alignment requirement
|
|
// check with the miniport also
|
|
//
|
|
deviceObject->AlignmentRequirement = fdoExtension->ControllerProperties.AlignmentRequirement;
|
|
if (deviceObject->AlignmentRequirement < fdoExtension->AttacheeDeviceObject->AlignmentRequirement) {
|
|
deviceObject->AlignmentRequirement =
|
|
fdoExtension->DeviceObject->AlignmentRequirement;
|
|
}
|
|
|
|
if (deviceObject->AlignmentRequirement < 1) {
|
|
deviceObject->AlignmentRequirement = 1;
|
|
}
|
|
|
|
|
|
//
|
|
// return this new DeviceObject
|
|
//
|
|
deviceObjectToReturn = deviceObject;
|
|
}
|
|
}
|
|
|
|
if (deviceObjectToReturn) {
|
|
|
|
deviceRelations->Objects[(deviceRelations)->Count] = deviceObjectToReturn;
|
|
|
|
ObReferenceObjectByPointer(deviceObjectToReturn,
|
|
0,
|
|
0,
|
|
KernelMode);
|
|
|
|
deviceRelations->Count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
|
Irp->IoStatus.Status = status;
|
|
break;
|
|
|
|
default:
|
|
status=STATUS_SUCCESS;
|
|
DebugPrint ((1, "PciIdeQueryDeviceRelations: Unsupported device relation\n"));
|
|
break;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
IoSkipCurrentIrpStackLocation ( Irp );
|
|
return IoCallDriver(fdoExtension->AttacheeDeviceObject, Irp);
|
|
|
|
} else {
|
|
|
|
//
|
|
//Complete the request
|
|
//
|
|
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
|
return status;
|
|
}
|
|
} // ControllerQueryDeviceRelations
|
|
|
|
NTSTATUS
|
|
ControllerQueryInterface (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PIO_STACK_LOCATION thisIrpSp;
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
NTSTATUS status;
|
|
PTRANSLATOR_INTERFACE translator;
|
|
ULONG busNumber;
|
|
|
|
PAGED_CODE();
|
|
|
|
thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
status = Irp->IoStatus.Status;
|
|
|
|
if (RtlEqualMemory(&GUID_TRANSLATOR_INTERFACE_STANDARD,
|
|
thisIrpSp->Parameters.QueryInterface.InterfaceType,
|
|
sizeof(GUID))
|
|
&& (thisIrpSp->Parameters.QueryInterface.Size >=
|
|
sizeof(TRANSLATOR_INTERFACE))
|
|
&& (PtrToUlong(thisIrpSp->Parameters.QueryInterface.InterfaceSpecificData) ==
|
|
CmResourceTypeInterrupt)) {
|
|
|
|
if (!fdoExtension->NativeMode[0] && !fdoExtension->NativeMode[1]) {
|
|
|
|
//
|
|
// we only return a translator only if we are legacy controller
|
|
//
|
|
status = HalGetInterruptTranslator(
|
|
PCIBus,
|
|
0,
|
|
InterfaceTypeUndefined, // special "IDE" cookie
|
|
thisIrpSp->Parameters.QueryInterface.Size,
|
|
thisIrpSp->Parameters.QueryInterface.Version,
|
|
(PTRANSLATOR_INTERFACE) thisIrpSp->Parameters.QueryInterface.Interface,
|
|
&busNumber
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pass down.
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
IoSkipCurrentIrpStackLocation ( Irp );
|
|
return IoCallDriver(fdoExtension->AttacheeDeviceObject, Irp);
|
|
} // ControllerQueryInterface
|
|
|
|
//
|
|
// initialize PCTRLFDO_EXTENSION->PCM_PARTIAL_RESOURCE_DESCRIPTOR(s)
|
|
//
|
|
NTSTATUS
|
|
AnalyzeResourceList (
|
|
PCTRLFDO_EXTENSION FdoExtension,
|
|
PCM_RESOURCE_LIST ResourceList
|
|
)
|
|
{
|
|
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
|
|
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
|
|
ULONG i;
|
|
ULONG j;
|
|
ULONG k;
|
|
ULONG cmdChannel;
|
|
ULONG ctrlChannel;
|
|
ULONG intrChannel;
|
|
ULONG bmAddr;
|
|
|
|
ULONG pdoResourceListSize;
|
|
PCM_RESOURCE_LIST pdoResourceList[MAX_IDE_CHANNEL];
|
|
PCM_FULL_RESOURCE_DESCRIPTOR pdoFullResourceList[MAX_IDE_CHANNEL];
|
|
PCM_PARTIAL_RESOURCE_LIST pdoPartialResourceList[MAX_IDE_CHANNEL];
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR pdoPartialDescriptors[MAX_IDE_CHANNEL];
|
|
|
|
ULONG bmResourceListSize;
|
|
PCM_RESOURCE_LIST bmResourceList;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR bmFullResourceList;
|
|
PCM_PARTIAL_RESOURCE_LIST bmPartialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR bmPartialDescriptors;
|
|
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (!ResourceList) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
bmResourceListSize =
|
|
sizeof (CM_RESOURCE_LIST) * ResourceList->Count; // This will have one CM_PARTIAL_RESOURCE_LIST
|
|
|
|
bmResourceList = (PCM_RESOURCE_LIST) ExAllocatePool (NonPagedPool, bmResourceListSize);
|
|
if (bmResourceList == NULL) {
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
RtlZeroMemory (bmResourceList, bmResourceListSize);
|
|
|
|
pdoResourceListSize =
|
|
sizeof (CM_RESOURCE_LIST) * ResourceList->Count + // This will have one CM_PARTIAL_RESOURCE_LIST
|
|
sizeof (CM_PARTIAL_RESOURCE_LIST) * 2;
|
|
|
|
for (i=0; i<MAX_IDE_CHANNEL; i++) {
|
|
|
|
pdoResourceList[i] = (PCM_RESOURCE_LIST) ExAllocatePool (NonPagedPool, pdoResourceListSize);
|
|
|
|
if (pdoResourceList[i] == NULL) {
|
|
|
|
DebugPrint ((0, "Unable to allocate resourceList for PDOs\n"));
|
|
|
|
for (j=0; j<i; j++) {
|
|
|
|
ExFreePool (pdoResourceList[j]);
|
|
}
|
|
|
|
ExFreePool (bmResourceList);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
RtlZeroMemory (pdoResourceList[i], pdoResourceListSize);
|
|
}
|
|
|
|
fullResourceList = ResourceList->List;
|
|
|
|
bmResourceList->Count = 0;
|
|
bmFullResourceList = bmResourceList->List;
|
|
|
|
for (k=0; k<MAX_IDE_CHANNEL; k++) {
|
|
|
|
pdoResourceList[k]->Count = 0;
|
|
pdoFullResourceList[k] = pdoResourceList[k]->List;
|
|
}
|
|
|
|
cmdChannel = ctrlChannel = intrChannel = bmAddr = 0;
|
|
for (j=0; j<ResourceList->Count; j++) {
|
|
|
|
partialResourceList = &(fullResourceList->PartialResourceList);
|
|
partialDescriptors = partialResourceList->PartialDescriptors;
|
|
|
|
RtlCopyMemory (
|
|
bmFullResourceList,
|
|
fullResourceList,
|
|
FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
|
|
);
|
|
|
|
bmPartialResourceList = &(bmFullResourceList->PartialResourceList);
|
|
bmPartialResourceList->Count = 0;
|
|
bmPartialDescriptors = bmPartialResourceList->PartialDescriptors;
|
|
|
|
for (k=0; k<MAX_IDE_CHANNEL; k++) {
|
|
|
|
RtlCopyMemory (
|
|
pdoFullResourceList[k],
|
|
fullResourceList,
|
|
FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
|
|
);
|
|
|
|
pdoPartialResourceList[k] = &(pdoFullResourceList[k]->PartialResourceList);
|
|
pdoPartialResourceList[k]->Count = 0;
|
|
pdoPartialDescriptors[k] = pdoPartialResourceList[k]->PartialDescriptors;
|
|
|
|
}
|
|
|
|
for (i=0; i<partialResourceList->Count; i++) {
|
|
|
|
if (((partialDescriptors[j].Type == CmResourceTypePort) ||
|
|
(partialDescriptors[j].Type == CmResourceTypeMemory)) &&
|
|
(partialDescriptors[i].u.Port.Length == 8) &&
|
|
(cmdChannel < MAX_IDE_CHANNEL)) {
|
|
|
|
ASSERT (cmdChannel < MAX_IDE_CHANNEL);
|
|
|
|
RtlCopyMemory (
|
|
pdoPartialDescriptors[cmdChannel] + pdoPartialResourceList[cmdChannel]->Count,
|
|
partialDescriptors + i,
|
|
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
);
|
|
|
|
pdoPartialResourceList[cmdChannel]->Count++;
|
|
|
|
cmdChannel++;
|
|
|
|
} else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
|
|
(partialDescriptors[j].Type == CmResourceTypeMemory)) &&
|
|
(partialDescriptors[i].u.Port.Length == 4) &&
|
|
(ctrlChannel < MAX_IDE_CHANNEL)) {
|
|
|
|
ASSERT (ctrlChannel < MAX_IDE_CHANNEL);
|
|
|
|
RtlCopyMemory (
|
|
pdoPartialDescriptors[ctrlChannel] + pdoPartialResourceList[ctrlChannel]->Count,
|
|
partialDescriptors + i,
|
|
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
);
|
|
|
|
pdoPartialResourceList[ctrlChannel]->Count++;
|
|
|
|
ctrlChannel++;
|
|
|
|
} else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
|
|
(partialDescriptors[j].Type == CmResourceTypeMemory)) &&
|
|
(partialDescriptors[i].u.Port.Length == 16) &&
|
|
(bmAddr < 1)) {
|
|
|
|
ASSERT (bmAddr < 1);
|
|
|
|
RtlCopyMemory (
|
|
bmPartialDescriptors + bmPartialResourceList->Count,
|
|
partialDescriptors + i,
|
|
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
);
|
|
|
|
bmPartialResourceList->Count++;
|
|
|
|
bmAddr++;
|
|
|
|
} else if ((partialDescriptors[i].Type == CmResourceTypeInterrupt) &&
|
|
(intrChannel < MAX_IDE_CHANNEL)) {
|
|
|
|
ASSERT (intrChannel < MAX_IDE_CHANNEL);
|
|
|
|
RtlCopyMemory (
|
|
pdoPartialDescriptors[intrChannel] + pdoPartialResourceList[intrChannel]->Count,
|
|
partialDescriptors + i,
|
|
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
);
|
|
|
|
pdoPartialResourceList[intrChannel]->Count++;
|
|
|
|
if (intrChannel == 0) {
|
|
|
|
if (FdoExtension->NativeMode[1]) {
|
|
|
|
intrChannel++;
|
|
|
|
//
|
|
// ISSUE: 08/30/2000
|
|
// do I need to mark it sharable?
|
|
// this needs to be revisited. (there are more issues)
|
|
//
|
|
RtlCopyMemory (
|
|
pdoPartialDescriptors[intrChannel] + pdoPartialResourceList[intrChannel]->Count,
|
|
partialDescriptors + i,
|
|
sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
);
|
|
|
|
pdoPartialResourceList[intrChannel]->Count++;
|
|
}
|
|
}
|
|
|
|
intrChannel++;
|
|
|
|
} else if (partialDescriptors[i].Type == CmResourceTypeDeviceSpecific) {
|
|
|
|
partialDescriptors += partialDescriptors[i].u.DeviceSpecificData.DataSize;
|
|
}
|
|
}
|
|
|
|
if (bmPartialResourceList->Count) {
|
|
|
|
bmResourceList->Count++;
|
|
bmFullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR)
|
|
(bmPartialDescriptors + bmPartialResourceList->Count);
|
|
|
|
}
|
|
|
|
for (k=0; k<MAX_IDE_CHANNEL; k++) {
|
|
|
|
if (pdoPartialResourceList[k]->Count) {
|
|
|
|
pdoResourceList[k]->Count++;
|
|
pdoFullResourceList[k] = (PCM_FULL_RESOURCE_DESCRIPTOR)
|
|
(pdoPartialDescriptors[k] + pdoPartialResourceList[k]->Count);
|
|
}
|
|
}
|
|
|
|
fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + i);
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
for (k=0; k<MAX_IDE_CHANNEL; k++) {
|
|
|
|
if (FdoExtension->NativeMode[k]) {
|
|
|
|
//
|
|
// If the controller is in native mode, we should have all the resources
|
|
//
|
|
|
|
if ((k < cmdChannel) &&
|
|
(k < ctrlChannel) &&
|
|
(k < intrChannel)) {
|
|
|
|
//
|
|
// This is good
|
|
//
|
|
|
|
} else {
|
|
|
|
cmdChannel = 0;
|
|
ctrlChannel = 0;
|
|
intrChannel = 0;
|
|
bmAddr = 0;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If the controller is in legacy mode, we should not have any resources
|
|
//
|
|
if (!FdoExtension->NativeMode[0] && !FdoExtension->NativeMode[1]) {
|
|
|
|
//
|
|
// both channels in legacy mode
|
|
//
|
|
cmdChannel = 0;
|
|
ctrlChannel = 0;
|
|
intrChannel = 0;
|
|
}
|
|
|
|
|
|
FdoExtension->TranslatedBusMasterBaseAddress = NULL;
|
|
if (0 < bmAddr) {
|
|
|
|
FdoExtension->BmResourceList = bmResourceList;
|
|
FdoExtension->BmResourceListSize = (ULONG)(((PUCHAR)bmFullResourceList) - ((PUCHAR)bmResourceList));
|
|
|
|
if (FdoExtension->BmResourceList->List[0].PartialResourceList.PartialDescriptors->Type == CmResourceTypePort) {
|
|
|
|
//
|
|
// address is in i/o space
|
|
//
|
|
FdoExtension->TranslatedBusMasterBaseAddress =
|
|
(PIDE_BUS_MASTER_REGISTERS) (ULONG_PTR)FdoExtension->BmResourceList->List[0].PartialResourceList.PartialDescriptors->u.Port.Start.QuadPart;
|
|
FdoExtension->BusMasterBaseAddressSpace = IO_SPACE;
|
|
|
|
} else if (FdoExtension->BmResourceList->List[0].PartialResourceList.PartialDescriptors->Type == CmResourceTypeMemory) {
|
|
|
|
//
|
|
// address is in memory space
|
|
//
|
|
FdoExtension->TranslatedBusMasterBaseAddress =
|
|
(PIDE_BUS_MASTER_REGISTERS) MmMapIoSpace(
|
|
FdoExtension->BmResourceList->List[0].PartialResourceList.PartialDescriptors->u.Port.Start,
|
|
16,
|
|
FALSE);
|
|
ASSERT (FdoExtension->TranslatedBusMasterBaseAddress);
|
|
|
|
// free mapped io resouces in stop/remove device
|
|
// unmapiospace doesn't do anything. it is ok not to call it
|
|
|
|
FdoExtension->BusMasterBaseAddressSpace = MEMORY_SPACE;
|
|
|
|
} else {
|
|
|
|
FdoExtension->TranslatedBusMasterBaseAddress = NULL;
|
|
ASSERT (FALSE);
|
|
}
|
|
}
|
|
|
|
if (FdoExtension->TranslatedBusMasterBaseAddress == NULL) {
|
|
|
|
ExFreePool (bmResourceList);
|
|
FdoExtension->BmResourceList = bmResourceList = NULL;
|
|
}
|
|
|
|
for (k=0; k<MAX_IDE_CHANNEL; k++) {
|
|
|
|
if ((k < cmdChannel) ||
|
|
(k < ctrlChannel) ||
|
|
(k < intrChannel)) {
|
|
|
|
FdoExtension->PdoResourceList[k] = pdoResourceList[k];
|
|
FdoExtension->PdoResourceListSize[k] = (ULONG)(((PUCHAR)pdoFullResourceList[k]) - ((PUCHAR)pdoResourceList[k]));
|
|
|
|
if (k < cmdChannel) {
|
|
|
|
FdoExtension->PdoCmdRegResourceFound[k] = TRUE;
|
|
}
|
|
|
|
if (k < ctrlChannel) {
|
|
|
|
FdoExtension->PdoCtrlRegResourceFound[k] = TRUE;
|
|
}
|
|
|
|
if (k < intrChannel) {
|
|
|
|
FdoExtension->PdoInterruptResourceFound[k] = TRUE;
|
|
}
|
|
|
|
} else {
|
|
|
|
ExFreePool (pdoResourceList[k]);
|
|
FdoExtension->PdoResourceList[k] =
|
|
pdoResourceList[k] = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
|
} // AnalyzeResourceList
|
|
|
|
VOID
|
|
ControllerOpMode (
|
|
IN PCTRLFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PCIIDE_CONFIG_HEADER pciIdeConfigHeader;
|
|
|
|
PAGED_CODE();
|
|
|
|
status = PciIdeBusData(
|
|
FdoExtension,
|
|
&pciIdeConfigHeader,
|
|
0,
|
|
sizeof (pciIdeConfigHeader),
|
|
TRUE
|
|
);
|
|
|
|
FdoExtension->NativeMode[0] = FALSE;
|
|
FdoExtension->NativeMode[1] = FALSE;
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// ISSUE: 02/05/01: This should be removed. In pci we check for sublclass = 0x1
|
|
//
|
|
if ((pciIdeConfigHeader.BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
|
|
(pciIdeConfigHeader.SubClass == PCI_SUBCLASS_MSC_RAID_CTLR)) {
|
|
|
|
//
|
|
// We have a Promise Technology IDE "raid" controller
|
|
//
|
|
FdoExtension->NativeMode[0] = TRUE;
|
|
FdoExtension->NativeMode[1] = TRUE;
|
|
|
|
} else {
|
|
|
|
if ((pciIdeConfigHeader.Chan0OpMode) &&
|
|
(pciIdeConfigHeader.Chan1OpMode)) {
|
|
|
|
//
|
|
// we can't support a channel being legacy
|
|
// and the other is in native because
|
|
// we don't know what irq is for the native
|
|
// channel
|
|
//
|
|
FdoExtension->NativeMode[0] = TRUE;
|
|
FdoExtension->NativeMode[1] = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Have to be both TRUE or both FALSE
|
|
//
|
|
ASSERT ((FdoExtension->NativeMode[0] == FALSE) == (FdoExtension->NativeMode[1] == FALSE));
|
|
}
|
|
|
|
return;
|
|
} // ControllerOpMode
|
|
|
|
VOID
|
|
EnablePCIBusMastering (
|
|
IN PCTRLFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PCIIDE_CONFIG_HEADER pciIdeConfigHeader;
|
|
|
|
status = PciIdeBusData(
|
|
FdoExtension,
|
|
&pciIdeConfigHeader,
|
|
0,
|
|
sizeof (PCIIDE_CONFIG_HEADER),
|
|
TRUE
|
|
);
|
|
|
|
//
|
|
// pci bus master disabled?
|
|
//
|
|
if (NT_SUCCESS(status) &&
|
|
pciIdeConfigHeader.MasterIde &&
|
|
!pciIdeConfigHeader.Command.b.MasterEnable) {
|
|
|
|
//
|
|
// Try to turn on pci bus mastering
|
|
//
|
|
pciIdeConfigHeader.Command.b.MasterEnable = 1;
|
|
|
|
status = PciIdeBusData(
|
|
FdoExtension,
|
|
&pciIdeConfigHeader.Command.w,
|
|
FIELD_OFFSET (PCIIDE_CONFIG_HEADER, Command),
|
|
sizeof (pciIdeConfigHeader.Command.w),
|
|
FALSE
|
|
);
|
|
}
|
|
return;
|
|
} // EnablePCIBusMastering
|
|
|
|
|
|
#ifdef DBG
|
|
ULONG PciIdeXDebugFakeMissingChild = 0;
|
|
#endif // DBG
|
|
|
|
IDE_CHANNEL_STATE
|
|
PciIdeChannelEnabled (
|
|
IN PCTRLFDO_EXTENSION FdoExtension,
|
|
IN ULONG Channel
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
ULONG longMask;
|
|
|
|
UCHAR channelEnableMask;
|
|
ULONG channelEnablePciConfigOffset;
|
|
UCHAR pciConfigData;
|
|
|
|
PAGED_CODE();
|
|
|
|
#if DBG
|
|
if (PciIdeXDebugFakeMissingChild & 0xff000000) {
|
|
|
|
DebugPrint ((0, "PciIdeXDebugFakeMissingChild: fake missing channel 0x%x\n", Channel));
|
|
|
|
if ((PciIdeXDebugFakeMissingChild & 0x0000ff) == Channel) {
|
|
|
|
PciIdeXDebugFakeMissingChild = 0;
|
|
return ChannelDisabled;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
longMask = 0;
|
|
status = PciIdeXGetDeviceParameter (
|
|
FdoExtension->AttacheePdo,
|
|
ChannelEnableMaskName[Channel],
|
|
&longMask
|
|
);
|
|
channelEnableMask = (UCHAR) longMask;
|
|
|
|
#if defined(_AMD64_SIMULATOR_)
|
|
|
|
//
|
|
// Use default values for an Intel controller which
|
|
// is what the simulator is providing.
|
|
//
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
channelEnableMask = 0x80;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DebugPrint ((1, "PciIdeX: Unable to get ChannelEnableMask from the registry\n"));
|
|
|
|
} else {
|
|
|
|
channelEnablePciConfigOffset = 0;
|
|
status = PciIdeXGetDeviceParameter (
|
|
FdoExtension->AttacheePdo,
|
|
ChannelEnablePciConfigOffsetName[Channel],
|
|
&channelEnablePciConfigOffset
|
|
);
|
|
|
|
#if defined(_AMD64_SIMULATOR_)
|
|
|
|
//
|
|
// See above
|
|
//
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
if (Channel == 0) {
|
|
channelEnablePciConfigOffset = 0x41;
|
|
} else {
|
|
channelEnablePciConfigOffset = 0x43;
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DebugPrint ((1, "PciIdeX: Unable to get ChannelEnablePciConfigOffset from the registry\n"));
|
|
|
|
} else {
|
|
|
|
status = PciIdeBusData(
|
|
FdoExtension,
|
|
&pciConfigData,
|
|
channelEnablePciConfigOffset,
|
|
sizeof (pciConfigData),
|
|
TRUE // Read
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
return (pciConfigData & channelEnableMask) ? ChannelEnabled : ChannelDisabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// couldn't figure out whether is channel enabled
|
|
// try the miniport port
|
|
//
|
|
if (FdoExtension->ControllerProperties.PciIdeChannelEnabled) {
|
|
|
|
return FdoExtension->ControllerProperties.PciIdeChannelEnabled (
|
|
FdoExtension->VendorSpecificDeviceEntension,
|
|
Channel
|
|
);
|
|
}
|
|
|
|
return ChannelStateUnknown;
|
|
} // PciIdeChannelEnabled
|
|
|
|
NTSTATUS
|
|
PciIdeCreateTimingTable (
|
|
IN PCTRLFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
PULONG timingTable;
|
|
PWSTR regTimingList = NULL;
|
|
ULONG i;
|
|
ULONG temp;
|
|
ULONG length = 0;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Try to procure the timing table from the registry
|
|
//
|
|
status = PciIdeXGetDeviceParameterEx (
|
|
FdoExtension->AttacheePdo,
|
|
L"TransferModeTiming",
|
|
&(regTimingList)
|
|
);
|
|
|
|
//
|
|
// Fill in the table entries
|
|
//
|
|
if (NT_SUCCESS(status) && regTimingList) {
|
|
|
|
PWSTR string = regTimingList;
|
|
UNICODE_STRING unicodeString;
|
|
|
|
i=0;
|
|
|
|
while (string[0]) {
|
|
|
|
RtlInitUnicodeString(
|
|
&unicodeString,
|
|
string
|
|
);
|
|
|
|
RtlUnicodeStringToInteger(&unicodeString,10, &temp);
|
|
|
|
//
|
|
// The first entry is the length of the table
|
|
//
|
|
if (i==0) {
|
|
|
|
length = temp;
|
|
ASSERT(length <=31);
|
|
|
|
if (length > 31) {
|
|
length=temp=31;
|
|
}
|
|
|
|
//
|
|
// The table should atleast be MAX_XFER_MODE long.
|
|
// if not fill it up with 0s
|
|
//
|
|
if (temp < MAX_XFER_MODE) {
|
|
temp=MAX_XFER_MODE;
|
|
}
|
|
|
|
timingTable = ExAllocatePool(NonPagedPool, temp*sizeof(ULONG));
|
|
if (timingTable == NULL) {
|
|
|
|
length = 0;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
|
|
} else {
|
|
|
|
ULONG j;
|
|
//
|
|
// Initialize the known xferModes (default)
|
|
//
|
|
SetDefaultTiming(timingTable, j);
|
|
|
|
for (j=MAX_XFER_MODE; j<temp;j++) {
|
|
timingTable[j]=timingTable[MAX_XFER_MODE-1];
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
if (i > length) {
|
|
DebugPrint((0, "Pciidex: Timing table overflow\n"));
|
|
break;
|
|
}
|
|
//
|
|
// The timings (PIO0-...)
|
|
// Use the default values if the cycletime is 0.
|
|
//
|
|
if (temp) {
|
|
timingTable[i-1]=temp;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
string += (unicodeString.Length / sizeof(WCHAR)) + 1;
|
|
}
|
|
|
|
if (length < MAX_XFER_MODE) {
|
|
length = MAX_XFER_MODE;
|
|
}
|
|
|
|
ExFreePool(regTimingList);
|
|
|
|
} else {
|
|
DebugPrint((1, "Pciidex: Unsuccessful regop status %x, regTimingList %x\n",
|
|
status, regTimingList));
|
|
|
|
//
|
|
// Nothing in the registry. Fill in the table with known transfer mode
|
|
// timings.
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
timingTable=ExAllocatePool(NonPagedPool, MAX_XFER_MODE*sizeof(ULONG));
|
|
|
|
if (timingTable == NULL) {
|
|
length =0;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
SetDefaultTiming(timingTable, length);
|
|
}
|
|
}
|
|
|
|
FdoExtension->TransferModeTimingTable=timingTable;
|
|
FdoExtension->TransferModeTableLength= length;
|
|
|
|
/*
|
|
for (i=0;i<FdoExtension->TransferModeTableLength;i++) {
|
|
DebugPrint((0, "Table[%d]=%d\n",
|
|
i,
|
|
FdoExtension->TransferModeTimingTable[i]));
|
|
}
|
|
*/
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
PciIdeInitControllerProperties (
|
|
IN PCTRLFDO_EXTENSION FdoExtension
|
|
)
|
|
{
|
|
#if 1
|
|
NTSTATUS status;
|
|
PDRIVER_OBJECT_EXTENSION driverObjectExtension;
|
|
ULONG i, j;
|
|
|
|
PAGED_CODE();
|
|
|
|
driverObjectExtension =
|
|
(PDRIVER_OBJECT_EXTENSION) IoGetDriverObjectExtension(
|
|
FdoExtension->DriverObject,
|
|
DRIVER_OBJECT_EXTENSION_ID
|
|
);
|
|
ASSERT (driverObjectExtension);
|
|
|
|
FdoExtension->ControllerProperties.Size = sizeof (IDE_CONTROLLER_PROPERTIES);
|
|
|
|
FdoExtension->ControllerProperties.DefaultPIO = 0;
|
|
status = (*driverObjectExtension->PciIdeGetControllerProperties) (
|
|
FdoExtension->VendorSpecificDeviceEntension,
|
|
&FdoExtension->ControllerProperties
|
|
);
|
|
|
|
//
|
|
// Look in the registry to determine whether
|
|
// UDMA 66 should be enabled for INTEL chipsets
|
|
//
|
|
FdoExtension->EnableUDMA66 = 0;
|
|
status = PciIdeXGetDeviceParameter (
|
|
FdoExtension->AttacheePdo,
|
|
L"EnableUDMA66",
|
|
&(FdoExtension->EnableUDMA66)
|
|
);
|
|
|
|
#else
|
|
|
|
NTSTATUS status;
|
|
PCIIDE_CONFIG_HEADER pciHeader;
|
|
ULONG ultraDmaSupport;
|
|
ULONG xferMode;
|
|
ULONG i;
|
|
ULONG j;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// grab ultra dma flag from the registry
|
|
//
|
|
ultraDmaSupport = 0;
|
|
status = PciIdeXGetDeviceParameter (
|
|
FdoExtension,
|
|
UltraDmaSupport,
|
|
&ultraDmaSupport
|
|
);
|
|
|
|
//
|
|
// grab ultra dma flag from the registry
|
|
//
|
|
status = PciIdeXGetBusData (
|
|
FdoExtension,
|
|
&pciHeader,
|
|
0,
|
|
sizeof (pciHeader)
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// could get the pci config data, fake it
|
|
//
|
|
pciHeader.MasterIde = 0;
|
|
pciHeader.Command.b.MasterEnable = 0;
|
|
}
|
|
|
|
xferMode = PIO_SUPPORT;
|
|
if (pciHeader.MasterIde && pciHeader.Command.b.MasterEnable) {
|
|
|
|
xferMode |= SWDMA_SUPPORT | MWDMA_SUPPORT;
|
|
|
|
if (ultraDmaSupport) {
|
|
|
|
xferMode |= UDMA_SUPPORT;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<MAX_IDE_CHANNEL; i++) {
|
|
for (i=0; i<MAX_IDE_DEVICE; i++) {
|
|
|
|
FdoExtension->ControllerProperties.SupportedTransferMode[i][j] = xferMode;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
} // PciIdeInitControllerProperties
|
|
|
|
NTSTATUS
|
|
ControllerUsageNotification (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PULONG deviceUsageCount;
|
|
|
|
ASSERT (DeviceObject);
|
|
ASSERT (Irp);
|
|
PAGED_CODE();
|
|
|
|
fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
ASSERT (fdoExtension);
|
|
|
|
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 ((0,
|
|
"PCIIDEX: Unknown IRP_MN_DEVICE_USAGE_NOTIFICATION type: 0x%x\n",
|
|
irpSp->Parameters.UsageNotification.Type));
|
|
}
|
|
|
|
IoCopyCurrentIrpStackLocationToNext (Irp);
|
|
|
|
IoSetCompletionRoutine (
|
|
Irp,
|
|
ControllerUsageNotificationCompletionRoutine,
|
|
deviceUsageCount,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
ASSERT(fdoExtension->AttacheeDeviceObject);
|
|
return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
|
|
|
|
} // ControllerUsageNotification
|
|
|
|
NTSTATUS
|
|
ControllerUsageNotificationCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PULONG deviceUsageCount = Context;
|
|
|
|
fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
ASSERT (fdoExtension);
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
|
|
|
if (deviceUsageCount) {
|
|
|
|
IoAdjustPagingPathCount (
|
|
deviceUsageCount,
|
|
irpSp->Parameters.UsageNotification.InPath
|
|
);
|
|
}
|
|
}
|
|
|
|
return Irp->IoStatus.Status;
|
|
} // ControllerUsageNotificationCompletionRoutine
|
|
|
|
|
|
NTSTATUS
|
|
PciIdeGetBusStandardInterface(
|
|
IN PCTRLFDO_EXTENSION FdoExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the bus iterface standard information from the PDO.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
{
|
|
KEVENT event;
|
|
NTSTATUS status;
|
|
PIRP irp;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
KeInitializeEvent( &event, NotificationEvent, FALSE );
|
|
|
|
irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
|
|
FdoExtension->AttacheeDeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&event,
|
|
&ioStatusBlock );
|
|
|
|
if (irp == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
irpStack = IoGetNextIrpStackLocation( irp );
|
|
irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_BUS_INTERFACE_STANDARD;
|
|
irpStack->Parameters.QueryInterface.Size = sizeof( BUS_INTERFACE_STANDARD );
|
|
irpStack->Parameters.QueryInterface.Version = 1;
|
|
irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->BusInterface;
|
|
irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
|
|
|
//
|
|
// Initialize the status to error in case the ACPI driver decides not to
|
|
// set it correctly.
|
|
//
|
|
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
status = IoCallDriver(FdoExtension->AttacheeDeviceObject, irp);
|
|
|
|
if (!NT_SUCCESS( status)) {
|
|
|
|
return status;
|
|
}
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
|
|
}
|
|
|
|
if (NT_SUCCESS(ioStatusBlock.Status)) {
|
|
|
|
ASSERT (FdoExtension->BusInterface.SetBusData);
|
|
ASSERT (FdoExtension->BusInterface.GetBusData);
|
|
}
|
|
|
|
return ioStatusBlock.Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ControllerQueryPnPDeviceState (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PCTRLFDO_EXTENSION fdoExtension;
|
|
PPNP_DEVICE_STATE deviceState;
|
|
|
|
fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
DebugPrint((2, "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);
|
|
} // ControllerQueryPnPDeviceState
|
|
|
|
#ifdef ENABLE_NATIVE_MODE
|
|
NTSTATUS
|
|
ControllerInterruptControl (
|
|
IN PCTRLFDO_EXTENSION FdoExtension,
|
|
IN ULONG Channel,
|
|
IN ULONG Disconnect
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR irqPartialDescriptors;
|
|
PCM_RESOURCE_LIST resourceListForKeep = NULL;
|
|
ULONG i;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
|
if (Disconnect) {
|
|
|
|
DebugPrint((1, "PciIdex: Interrupt control for %x - disconnect\n", Channel));
|
|
|
|
//
|
|
// Disconnect the ISR
|
|
//
|
|
if ( (FdoExtension->InterruptObject[Channel])) {
|
|
|
|
IoDisconnectInterrupt (
|
|
FdoExtension->InterruptObject[Channel]
|
|
);
|
|
|
|
FdoExtension->InterruptObject[Channel] = 0;
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
// connect the ISR
|
|
//
|
|
|
|
PPCIIDE_INTERRUPT_CONTEXT context;
|
|
|
|
DebugPrint((1, "PciIdex: Interrupt control for %x - reconnect\n", Channel));
|
|
|
|
irqPartialDescriptors = FdoExtension->IrqPartialDescriptors[Channel];
|
|
|
|
if (!irqPartialDescriptors) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Fill in the context
|
|
//
|
|
context = (PPCIIDE_INTERRUPT_CONTEXT) &(FdoExtension->InterruptContext[Channel]);
|
|
context->DeviceExtension = (PVOID)FdoExtension;
|
|
context->ChannelNumber = Channel;
|
|
|
|
status = IoConnectInterrupt(&FdoExtension->InterruptObject[Channel],
|
|
(PKSERVICE_ROUTINE) ControllerInterrupt,
|
|
(PVOID) context,
|
|
(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((1,
|
|
"PciIde: Can't connect interrupt %d\n",
|
|
irqPartialDescriptors->u.Interrupt.Vector));
|
|
|
|
FdoExtension->InterruptObject[Channel] = NULL;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
#define SelectDevice(BaseIoAddress, deviceNumber, additional) \
|
|
WRITE_PORT_UCHAR ((BaseIoAddress)->DriveSelect, (UCHAR)((((deviceNumber) & 0x1) << 4) | 0xA0 | additional))
|
|
|
|
BOOLEAN
|
|
ControllerInterrupt(
|
|
IN PKINTERRUPT Interrupt,
|
|
PVOID Context
|
|
)
|
|
{
|
|
UCHAR statusByte;
|
|
PPCIIDE_INTERRUPT_CONTEXT context = Context;
|
|
PCTRLFDO_EXTENSION fdoExtension = context->DeviceExtension;
|
|
ULONG channel = context->ChannelNumber;
|
|
PIDE_REGISTERS_1 baseIoAddress1 = &(fdoExtension->BaseIoAddress1[channel]);
|
|
BOOLEAN interruptCleared = FALSE;
|
|
|
|
DebugPrint((1, "Pciidex: ISR called for channel %d\n", channel));
|
|
|
|
//
|
|
// Check if the interrupts are enabled.
|
|
// Don't enable the interrupts if both the isrs are not installed
|
|
//
|
|
if (!fdoExtension->NativeInterruptEnabled) {
|
|
|
|
if (fdoExtension->ControllerIsrInstalled) {
|
|
|
|
//
|
|
// we have just connected the ISRs. At this point we don't know whether
|
|
// we actually enabled the decodes or not. So enable the decodes and set the
|
|
// flag
|
|
//
|
|
//
|
|
// if this fails we already bugchecked.
|
|
//
|
|
ControllerEnableInterrupt(fdoExtension);
|
|
|
|
fdoExtension->NativeInterruptEnabled = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// cannot be us
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!fdoExtension->ControllerIsrInstalled) {
|
|
|
|
//
|
|
// At this point we don't know whether the decodes are disabled or not. We should
|
|
// enable them.
|
|
//
|
|
//
|
|
// if this fails we already bugchecked.
|
|
//
|
|
ControllerEnableInterrupt(fdoExtension);
|
|
|
|
//
|
|
// Now fall thru and determine whether it is our interrupt.
|
|
// we will disable the decodes after that.
|
|
//
|
|
} else {
|
|
|
|
//
|
|
// all is well. Go process the interrupt.
|
|
//
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Both the ISRs should be installed and the interrupts should
|
|
// be enabled at this point
|
|
//
|
|
ASSERT(fdoExtension->NativeInterruptEnabled);
|
|
|
|
// ControllerIsrInstalled need not be set.
|
|
// if we get called, then it means that we are still connected
|
|
// however, if the flag ControllerIsrInstalled is not set, then it is
|
|
// safe to assume that we are in the process of stopping the controller.
|
|
// Just dismiss the interrupt, the normal way. We are yet to turn off the decodes.
|
|
//
|
|
|
|
//
|
|
// Clear interrupt by reading status.
|
|
//
|
|
GetStatus(baseIoAddress1, statusByte);
|
|
|
|
//
|
|
// Check the Bus master registers
|
|
//
|
|
if (!fdoExtension->NoBusMaster[channel]) {
|
|
|
|
BMSTATUS bmStatus;
|
|
PIDE_BUS_MASTER_REGISTERS bmRegister;
|
|
|
|
//
|
|
// Get the correct bus master register
|
|
//
|
|
bmRegister = (PIDE_BUS_MASTER_REGISTERS)(((PUCHAR)fdoExtension->TranslatedBusMasterBaseAddress) + channel*8);
|
|
|
|
bmStatus = READ_PORT_UCHAR (&bmRegister->Status);
|
|
|
|
DebugPrint((1, "BmStatus = 0x%x\n", bmStatus));
|
|
|
|
//
|
|
// is Interrupt bit set?
|
|
//
|
|
if (bmStatus & BMSTATUS_INTERRUPT) {
|
|
WRITE_PORT_UCHAR (&bmRegister->Command, 0x0); // disable BM
|
|
WRITE_PORT_UCHAR (&bmRegister->Status, BUSMASTER_INTERRUPT); // clear interrupt BM
|
|
interruptCleared = TRUE;
|
|
}
|
|
}
|
|
|
|
DebugPrint((1, "ISR for %d returning %d\n", channel, interruptCleared?1:0));
|
|
|
|
//
|
|
// NativeInterruptEnabled should be set at this point
|
|
//
|
|
if (!fdoExtension->ControllerIsrInstalled) {
|
|
|
|
// we are in the stop or remove code path where this flag has been cleared and
|
|
// we are about to disconnect the ISR. Disable the decodes.
|
|
//
|
|
ControllerDisableInterrupt(fdoExtension);
|
|
|
|
//
|
|
// we have dismissed our interrupt. Now clear the interruptEnabled flag.
|
|
//
|
|
fdoExtension->NativeInterruptEnabled = FALSE;
|
|
|
|
//
|
|
// return InterruptCleared.
|
|
//
|
|
}
|
|
return interruptCleared;
|
|
}
|
|
|
|
/***
|
|
NTSTATUS
|
|
ControllerEnableDecode(
|
|
IN PCTRLFDO_EXTENSION FdoExtension,
|
|
IN BOOLEAN Enable
|
|
)
|
|
{
|
|
USHORT cmd;
|
|
NTSTATUS status;
|
|
PCIIDE_CONFIG_HEADER pciIdeConfigHeader;
|
|
|
|
status = PciIdeBusData(
|
|
FdoExtension,
|
|
&pciIdeConfigHeader,
|
|
0,
|
|
sizeof (PCIIDE_CONFIG_HEADER),
|
|
TRUE
|
|
);
|
|
|
|
//
|
|
// get pci command register
|
|
//
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
}
|
|
|
|
cmd = pciIdeConfigHeader.Command.w;
|
|
|
|
cmd &= ~(PCI_ENABLE_IO_SPACE |
|
|
PCI_ENABLE_MEMORY_SPACE |
|
|
PCI_ENABLE_BUS_MASTER);
|
|
|
|
if (Enable) {
|
|
|
|
//
|
|
// Set enables
|
|
//
|
|
|
|
cmd |= (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER);
|
|
}
|
|
|
|
//
|
|
// Set the new command register into the device.
|
|
//
|
|
status = PciIdeBusData(
|
|
FdoExtension,
|
|
&cmd,
|
|
FIELD_OFFSET (PCIIDE_CONFIG_HEADER, Command),
|
|
sizeof (pciIdeConfigHeader.Command.w),
|
|
FALSE
|
|
);
|
|
|
|
return status;
|
|
}
|
|
**/
|
|
|
|
NTSTATUS
|
|
PciIdeGetNativeModeInterface(
|
|
IN PCTRLFDO_EXTENSION FdoExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the native ide iterface information from the PDO.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
{
|
|
KEVENT event;
|
|
NTSTATUS status;
|
|
PIRP irp;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
KeInitializeEvent( &event, NotificationEvent, FALSE );
|
|
|
|
irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
|
|
FdoExtension->AttacheeDeviceObject,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&event,
|
|
&ioStatusBlock );
|
|
|
|
if (irp == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
irpStack = IoGetNextIrpStackLocation( irp );
|
|
irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
|
irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCI_NATIVE_IDE_INTERFACE;
|
|
irpStack->Parameters.QueryInterface.Size = sizeof( PCI_NATIVE_IDE_INTERFACE );
|
|
irpStack->Parameters.QueryInterface.Version = 1;
|
|
irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->NativeIdeInterface;
|
|
irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
|
|
|
//
|
|
// Initialize the status to error in case the ACPI driver decides not to
|
|
// set it correctly.
|
|
//
|
|
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
status = IoCallDriver(FdoExtension->AttacheeDeviceObject, irp);
|
|
|
|
if (!NT_SUCCESS( status)) {
|
|
|
|
return status;
|
|
}
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
|
|
}
|
|
|
|
if (NT_SUCCESS(ioStatusBlock.Status)) {
|
|
|
|
ASSERT (FdoExtension->NativeIdeInterface.InterruptControl);
|
|
}
|
|
|
|
return ioStatusBlock.Status;
|
|
}
|
|
#endif
|