You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1178 lines
36 KiB
1178 lines
36 KiB
/*++
|
|
|
|
Copyright (c) 1997-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fdopnp.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that handles PNP irps for sd bus driver
|
|
targeted towards the FDO's (for the sd controller object)
|
|
|
|
Author:
|
|
|
|
Neil Sandlin (neilsa) Jan 1 2002
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
//
|
|
// Internal References
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
SdbusGetPciControllerType(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PDEVICE_OBJECT Fdo
|
|
);
|
|
|
|
NTSTATUS
|
|
SdbusFdoStartDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SdbusFdoStopDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SdbusFdoRemoveDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SdbusFdoDeviceCapabilities(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
SdbusDeviceRelations(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp,
|
|
IN DEVICE_RELATION_TYPE RelationType,
|
|
OUT PDEVICE_RELATIONS *DeviceRelations
|
|
);
|
|
|
|
PUNICODE_STRING DriverRegistryPath;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, SdbusFdoPnpDispatch)
|
|
#pragma alloc_text(PAGE, SdbusFdoStartDevice)
|
|
#pragma alloc_text(PAGE, SdbusFdoStopDevice)
|
|
#pragma alloc_text(PAGE, SdbusFdoRemoveDevice)
|
|
#pragma alloc_text(PAGE, SdbusFdoDeviceCapabilities)
|
|
#pragma alloc_text(PAGE, SdbusAddDevice)
|
|
#pragma alloc_text(PAGE, SdbusGetPciControllerType)
|
|
#pragma alloc_text(PAGE, SdbusDeviceRelations)
|
|
#endif
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusFdoPnpDispatch (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
PNP/Power IRPs dispatch routine for the sd bus controller
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
Irp - Pointer to the IRP
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
|
|
PIO_STACK_LOCATION nextIrpStack;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
NTSTATUS status = Irp->IoStatus.Status;
|
|
|
|
PAGED_CODE();
|
|
ASSERT (fdoExtension->LowerDevice != NULL);
|
|
|
|
#if DBG
|
|
if (irpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
|
|
DebugPrint((SDBUS_DEBUG_PNP, "fdo %08x irp %08x - Unknown PNP irp\n",
|
|
DeviceObject, irpStack->MinorFunction));
|
|
} else {
|
|
DebugPrint((SDBUS_DEBUG_PNP, "fdo %08x irp %08x --> %s\n",
|
|
DeviceObject, Irp, PNP_IRP_STRING(irpStack->MinorFunction)));
|
|
}
|
|
#endif
|
|
|
|
switch (irpStack->MinorFunction) {
|
|
|
|
case IRP_MN_START_DEVICE: {
|
|
status = SdbusFdoStartDevice(DeviceObject, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_STOP_DEVICE: {
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_CANCEL_STOP_DEVICE: {
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_STOP_DEVICE: {
|
|
status = SdbusFdoStopDevice(DeviceObject, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS: {
|
|
|
|
//
|
|
// Return the list of devices on the bus
|
|
//
|
|
|
|
status = SdbusDeviceRelations(DeviceObject,
|
|
Irp,
|
|
irpStack->Parameters.QueryDeviceRelations.Type,
|
|
(PDEVICE_RELATIONS *) &Irp->IoStatus.Information);
|
|
|
|
Irp->IoStatus.Status = status;
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE: {
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE: {
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_REMOVE_DEVICE:{
|
|
status = SdbusFdoRemoveDevice(DeviceObject, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL: {
|
|
SdbusFdoStopDevice(DeviceObject, NULL);
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES: {
|
|
status = SdbusFdoDeviceCapabilities(DeviceObject, Irp);
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
DebugPrint((SDBUS_DEBUG_PNP, "fdo %08x irp %08x - Skipping unsupported irp\n", DeviceObject, Irp));
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Set the IRP status only if we set it to something other than
|
|
// STATUS_NOT_SUPPORTED.
|
|
//
|
|
if (status != STATUS_NOT_SUPPORTED) {
|
|
|
|
Irp->IoStatus.Status = status ;
|
|
}
|
|
|
|
status = Irp->IoStatus.Status;
|
|
DebugPrint((SDBUS_DEBUG_PNP, "fdo %08x irp %08x comp %s %08x\n",
|
|
DeviceObject, Irp, STATUS_STRING(status), status));
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT Pdo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates functional device objects for each SD controller in the
|
|
system and attaches them to the physical device objects for the controllers
|
|
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the object for this driver
|
|
PhysicalDeviceObject - a pointer to the physical object we need to attach to
|
|
|
|
Return Value:
|
|
|
|
Status from device creation and initialization
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_OBJECT fdo = NULL;
|
|
PDEVICE_OBJECT lowerDevice = NULL;
|
|
|
|
PFDO_EXTENSION deviceExtension;
|
|
ULONG resultLength;
|
|
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugPrint((SDBUS_DEBUG_PNP, "AddDevice Entered with pdo %x\n", Pdo));
|
|
|
|
if (Pdo == NULL) {
|
|
|
|
//
|
|
// Have we been asked to do detection on our own?
|
|
// if so just return no more devices
|
|
//
|
|
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "SdbusAddDevice - asked to do detection\n"));
|
|
return STATUS_NO_MORE_ENTRIES;
|
|
}
|
|
|
|
//
|
|
// create and initialize the new functional device object
|
|
//
|
|
|
|
status = IoCreateDevice(DriverObject,
|
|
sizeof(FDO_EXTENSION),
|
|
NULL,
|
|
FILE_DEVICE_CONTROLLER,
|
|
0L,
|
|
FALSE,
|
|
&fdo);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "SdbusAddDevice - error creating Fdo [%#08lx]\n", status));
|
|
return status;
|
|
}
|
|
|
|
try {
|
|
|
|
deviceExtension = fdo->DeviceExtension;
|
|
RtlZeroMemory(deviceExtension, sizeof(FDO_EXTENSION));
|
|
//
|
|
// Set up the device extension.
|
|
//
|
|
deviceExtension->Signature = SDBUS_FDO_EXTENSION_SIGNATURE;
|
|
deviceExtension->DeviceObject = fdo;
|
|
deviceExtension->RegistryPath = DriverRegistryPath;
|
|
deviceExtension->DriverObject = DriverObject;
|
|
deviceExtension->Flags = SDBUS_FDO_OFFLINE;
|
|
deviceExtension->WaitWakeState= WAKESTATE_DISARMED;
|
|
|
|
KeInitializeTimer(&deviceExtension->WorkerTimer);
|
|
KeInitializeDpc(&deviceExtension->WorkerTimeoutDpc, SdbusWorkerTimeoutDpc, deviceExtension);
|
|
KeInitializeDpc(&deviceExtension->WorkerDpc, SdbusWorkerDpc, deviceExtension);
|
|
KeInitializeSpinLock(&deviceExtension->WorkerSpinLock);
|
|
|
|
InitializeListHead(&deviceExtension->IoWorkPacketQueue);
|
|
InitializeListHead(&deviceExtension->SystemWorkPacketQueue);
|
|
|
|
IoInitializeRemoveLock(&deviceExtension->RemoveLock, 'Sdbu', 1, 100);
|
|
//
|
|
// card events we are interested in
|
|
//
|
|
deviceExtension->CardEvents = SDBUS_EVENT_CARD_RW_END |
|
|
SDBUS_EVENT_BUFFER_EMPTY |
|
|
SDBUS_EVENT_BUFFER_FULL |
|
|
SDBUS_EVENT_CARD_RESPONSE;
|
|
|
|
//
|
|
// Layer our FDO on top of the PDO
|
|
//
|
|
//
|
|
|
|
lowerDevice = IoAttachDeviceToDeviceStack(fdo,Pdo);
|
|
|
|
//
|
|
// No status. Do the best we can.
|
|
//
|
|
if (lowerDevice == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
leave;
|
|
};
|
|
|
|
deviceExtension->LowerDevice = lowerDevice;
|
|
deviceExtension->Pdo = Pdo;
|
|
|
|
status = IoGetDeviceProperty(Pdo,
|
|
DevicePropertyLegacyBusType,
|
|
sizeof(INTERFACE_TYPE),
|
|
(PVOID)&deviceExtension->InterfaceType,
|
|
&resultLength);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Get our controller type
|
|
//
|
|
|
|
status = SdbusGetPciControllerType(Pdo, fdo);
|
|
if (!NT_SUCCESS(status)) {
|
|
leave;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the pci interface for reading/writing to config header space
|
|
//
|
|
status = SdbusGetInterface(Pdo,
|
|
&GUID_BUS_INTERFACE_STANDARD,
|
|
sizeof(BUS_INTERFACE_STANDARD),
|
|
(PINTERFACE) &deviceExtension->PciBusInterface);
|
|
if (!NT_SUCCESS(status)) {
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Link this fdo to the list of fdo's managed by the driver
|
|
//
|
|
|
|
DebugPrint((SDBUS_DEBUG_PNP, "FDO %08X now linked to fdolist by AddDevice\n", fdo));
|
|
deviceExtension->NextFdo = FdoList;
|
|
FdoList = fdo;
|
|
|
|
fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
} finally {
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
MarkDeviceDeleted(deviceExtension);
|
|
//
|
|
// Cannot support a controller without knowing its type etc.
|
|
//
|
|
|
|
if (deviceExtension->LowerDevice) {
|
|
IoDetachDevice(deviceExtension->LowerDevice);
|
|
}
|
|
|
|
IoDeleteDevice(fdo);
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusGetPciControllerType(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN PDEVICE_OBJECT Fdo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Look at the PCI hardware ID to see if it is already a device we know about. If so,
|
|
set the appropriate controller type in the fdoExtension.
|
|
|
|
Arguments:
|
|
Pdo - Physical Device object for the Sdbus controller owned by the PCI driver
|
|
Fdo - Functional Device object for the sd controller owned by this driver, whose
|
|
extension will store the relevant controller information upon exit from this routine.
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS Things are fine and information obtained
|
|
STATUS_NOT_SUPPORTED This is actually a healthy status for this routine: all it means
|
|
is that this PDO is not on a PCI bus, so no information needs to be
|
|
obtained anyways.
|
|
Any other status Failure. Caller probably needs to back out & not support this controller
|
|
--*/
|
|
{
|
|
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
PIRP irp;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PCI_COMMON_CONFIG pciConfig;
|
|
PPCI_CONTROLLER_INFORMATION id;
|
|
PPCI_VENDOR_INFORMATION vid;
|
|
KEVENT event;
|
|
NTSTATUS status;
|
|
BOOLEAN foundController = FALSE;
|
|
|
|
PAGED_CODE();
|
|
//
|
|
// Allocate & initialize an Irp (IRP_MN_READ_CONFIG) to be sent down
|
|
// to the PCI bus driver to get config. header for this controller
|
|
//
|
|
// Following is all standard stuff to send an IRP down - needs no documentation
|
|
|
|
//
|
|
// Fresh PDO. No need to jump through hoops to get attached devices
|
|
//
|
|
KeInitializeEvent (&event, NotificationEvent, FALSE);
|
|
irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
|
|
Pdo,
|
|
NULL,
|
|
0,
|
|
0,
|
|
&event,
|
|
&statusBlock
|
|
);
|
|
|
|
if (irp == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
irp->IoStatus.Information = 0;
|
|
|
|
irpSp = IoGetNextIrpStackLocation(irp);
|
|
|
|
irpSp->MinorFunction = IRP_MN_READ_CONFIG;
|
|
|
|
irpSp->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG;
|
|
irpSp->Parameters.ReadWriteConfig.Buffer = &pciConfig;
|
|
irpSp->Parameters.ReadWriteConfig.Offset = 0;
|
|
irpSp->Parameters.ReadWriteConfig.Length = sizeof(pciConfig);
|
|
|
|
|
|
status = IoCallDriver(Pdo, irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
status = statusBlock.Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
//
|
|
// Now weed out the critical information from the config header and
|
|
// store it away in the fdo's extension
|
|
//
|
|
|
|
//
|
|
// Look up the PCI device id in our table
|
|
//
|
|
#if 0
|
|
for (id = (PPCI_CONTROLLER_INFORMATION) PciControllerInformation;id->VendorID != PCI_INVALID_VENDORID; id++) {
|
|
if ((id->VendorID == pciConfig.VendorID) && (id->DeviceID == pciConfig.DeviceID)) {
|
|
|
|
SdbusSetControllerType(fdoExtension, id->ControllerType);
|
|
foundController = TRUE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Didn't find a specific vendor/device id, try to just base it on the vendor id
|
|
//
|
|
if (!foundController) {
|
|
for (vid = (PPCI_VENDOR_INFORMATION) PciVendorInformation;vid->VendorID != PCI_INVALID_VENDORID; vid++) {
|
|
if (vid->VendorID == pciConfig.VendorID) {
|
|
|
|
fdoExtension->FunctionBlock = vid->FunctionBlock;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusFdoDeviceCapabilities(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
Records the device capabilities of this sd controller,
|
|
so 1. they can be used in the power management for the controller
|
|
and 2. they can be used for determining the capabilities of the
|
|
child pc-card PDO's of this sd controller.
|
|
|
|
Arguments
|
|
|
|
Fdo - Pointer to functional device object of the sd
|
|
controller
|
|
Irp - Pointer to the i/o request packet
|
|
|
|
Return Value
|
|
|
|
STATUS_SUCCESS Capabilities returned
|
|
STATUS_INSUFFICIENT_RESOURCES Could not allocate memory to cache the capabilities
|
|
|
|
--*/
|
|
{
|
|
PFDO_EXTENSION fdoExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PDEVICE_CAPABILITIES capabilities;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
capabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
|
|
fdoExtension = Fdo->DeviceExtension;
|
|
|
|
//
|
|
// Send this down the stack to obtain the capabilities
|
|
//
|
|
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Cache the device capabilities in the device extension
|
|
// for this sd controller.
|
|
//
|
|
RtlCopyMemory(&fdoExtension->DeviceCapabilities,
|
|
capabilities,
|
|
sizeof(DEVICE_CAPABILITIES));
|
|
|
|
} else {
|
|
|
|
RtlZeroMemory(&fdoExtension->DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusFdoStartDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will start the sd controller with the supplied
|
|
resources. The IRP is sent down to the pdo first, so PCI
|
|
or whoever sits underneath gets a chance to program the controller
|
|
to decode the resources.
|
|
|
|
Arguments:
|
|
|
|
Fdo - Functional device object of the sd controller
|
|
Irp - Pointer to the i/o request packet
|
|
PassedDown - Contains FALSE on entry, which means caller must
|
|
complete or pass down irp based on status. If set
|
|
to TRUE, Irp may need to be re-completed...
|
|
NeedsRecompletion - ...In which case this parameter will be checked
|
|
|
|
Return value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
PAGED_CODE();
|
|
//
|
|
// Send this down to the PDO first
|
|
//
|
|
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Give the hardware some time to settle after returning from the pdo
|
|
//
|
|
SdbusWait(256);
|
|
|
|
try {
|
|
PCM_RESOURCE_LIST ResourceList = irpStack->Parameters.StartDevice.AllocatedResources;
|
|
PCM_RESOURCE_LIST TranslatedResourceList = irpStack->Parameters.StartDevice.AllocatedResourcesTranslated;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
|
|
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDesc;
|
|
ULONG i;
|
|
BOOLEAN sharedInterrupt;
|
|
KINTERRUPT_MODE interruptMode;
|
|
INTERFACE_TYPE interfaceType;
|
|
|
|
if (fdoExtension->Flags & SDBUS_DEVICE_STARTED) {
|
|
//
|
|
// Start to already started device
|
|
//
|
|
DebugPrint((SDBUS_DEBUG_INFO,"SdbusFdoStartDevice: Fdo %x already started\n", Fdo));
|
|
status = STATUS_SUCCESS;
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Parse AllocatedResources & get IoPort/AttributeMemoryBase/IRQ info.
|
|
//
|
|
|
|
if ((ResourceList == NULL) || (ResourceList->Count <=0) ) {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
leave;
|
|
}
|
|
|
|
fullResourceDesc=&TranslatedResourceList->List[0];
|
|
partialResourceList = &fullResourceDesc->PartialResourceList;
|
|
partialResourceDesc = partialResourceList->PartialDescriptors;
|
|
|
|
//
|
|
// The memory resource is the host register base.
|
|
//
|
|
for (i=0; (i < partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeMemory);
|
|
i++, partialResourceDesc++);
|
|
if (i >= partialResourceList->Count) {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
leave;
|
|
};
|
|
|
|
//
|
|
// This is memory. We need to map it
|
|
//
|
|
fdoExtension->HostRegisterBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
|
|
partialResourceDesc->u.Memory.Length,
|
|
FALSE);
|
|
fdoExtension->HostRegisterSize = partialResourceDesc->u.Memory.Length;
|
|
|
|
fdoExtension->Flags |= SDBUS_HOST_REGISTER_BASE_MAPPED;
|
|
|
|
DebugPrint((SDBUS_DEBUG_INFO, "SdbusGetAssignedResources: Host Register Base at %x, size %x\n",
|
|
fdoExtension->HostRegisterBase, fdoExtension->HostRegisterSize));
|
|
|
|
//
|
|
// Finally see if an IRQ is assigned
|
|
//
|
|
|
|
for (i = 0, partialResourceDesc = partialResourceList->PartialDescriptors;
|
|
(i < partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeInterrupt);
|
|
i++,partialResourceDesc++);
|
|
|
|
|
|
if (i < partialResourceList->Count) {
|
|
//
|
|
// We have an interrupt to used for CSC
|
|
//
|
|
DebugPrint((SDBUS_DEBUG_INFO, "SdbusGetAssignedResources: Interrupt resource assigned\n"));
|
|
fdoExtension->TranslatedInterrupt = *partialResourceDesc;
|
|
//
|
|
// Get the raw interrupt resource - needed to enable the interrupt on the controller
|
|
//
|
|
fullResourceDesc=&ResourceList->List[0];
|
|
partialResourceList = &fullResourceDesc->PartialResourceList;
|
|
partialResourceDesc = partialResourceList->PartialDescriptors;
|
|
for (i=0; (i< partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeInterrupt);
|
|
i++, partialResourceDesc++);
|
|
if (i < partialResourceList->Count) {
|
|
fdoExtension->Interrupt = *partialResourceDesc;
|
|
} else {
|
|
//
|
|
// Should not happen.. translated descriptor was present, but raw is missing!
|
|
// Just reset the translated interrupt and pretend no interrupt was assigned
|
|
//
|
|
RtlZeroMemory(&fdoExtension->TranslatedInterrupt, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
}
|
|
}
|
|
|
|
//
|
|
// do vendor-specific init of controller
|
|
//
|
|
|
|
(*(fdoExtension->FunctionBlock->InitController))(fdoExtension);
|
|
|
|
//
|
|
// Now the controller registers should be accessible
|
|
//
|
|
fdoExtension->Flags &= ~SDBUS_FDO_OFFLINE;
|
|
|
|
|
|
fdoExtension->SystemPowerState = PowerSystemWorking;
|
|
fdoExtension->DevicePowerState = PowerDeviceD0;
|
|
|
|
//
|
|
// Initialize our DpcForIsr
|
|
//
|
|
IoInitializeDpcRequest(Fdo, SdbusInterruptDpc);
|
|
|
|
if (fdoExtension->Interrupt.u.Interrupt.Level == 0) {
|
|
status = STATUS_UNSUCCESSFUL;
|
|
leave;
|
|
}
|
|
|
|
fdoExtension->IoWorkItem = IoAllocateWorkItem(Fdo);
|
|
|
|
//
|
|
// Hook up the controller interrupt for detecting pc-card plug ins/outs
|
|
//
|
|
interruptMode=((fdoExtension->Interrupt.Flags & CM_RESOURCE_INTERRUPT_LATCHED) == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched:LevelSensitive;
|
|
|
|
sharedInterrupt=(fdoExtension->Interrupt.ShareDisposition == CmResourceShareShared)?
|
|
TRUE:FALSE;
|
|
|
|
|
|
status = IoConnectInterrupt(&(fdoExtension->SdbusInterruptObject),
|
|
(PKSERVICE_ROUTINE) SdbusInterrupt,
|
|
(PVOID) Fdo,
|
|
NULL,
|
|
fdoExtension->TranslatedInterrupt.u.Interrupt.Vector,
|
|
(KIRQL) fdoExtension->TranslatedInterrupt.u.Interrupt.Level,
|
|
(KIRQL) fdoExtension->TranslatedInterrupt.u.Interrupt.Level,
|
|
interruptMode,
|
|
sharedInterrupt,
|
|
(KAFFINITY) fdoExtension->TranslatedInterrupt.u.Interrupt.Affinity,
|
|
FALSE);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "Unable to connect interrupt\n"));
|
|
leave;
|
|
}
|
|
|
|
(*(fdoExtension->FunctionBlock->EnableEvent))(fdoExtension, (SDBUS_EVENT_INSERTION | SDBUS_EVENT_REMOVAL));
|
|
|
|
|
|
//
|
|
// Activate socket will power up and ready the card
|
|
//
|
|
|
|
SdbusActivateSocket(Fdo, NULL, NULL);
|
|
|
|
} finally {
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
fdoExtension->Flags |= SDBUS_DEVICE_STARTED;
|
|
|
|
} else {
|
|
//
|
|
// Failure
|
|
//
|
|
if (fdoExtension->Flags & SDBUS_HOST_REGISTER_BASE_MAPPED) {
|
|
MmUnmapIoSpace(fdoExtension->HostRegisterBase,
|
|
fdoExtension->HostRegisterSize);
|
|
fdoExtension->Flags &= ~SDBUS_HOST_REGISTER_BASE_MAPPED;
|
|
fdoExtension->HostRegisterBase = 0;
|
|
fdoExtension->HostRegisterSize = 0;
|
|
}
|
|
|
|
if (fdoExtension->IoWorkItem) {
|
|
IoFreeWorkItem(fdoExtension->IoWorkItem);
|
|
fdoExtension->IoWorkItem = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusFdoStopDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IRP_MN_STOP_DEVICE handler for the given sd controller.
|
|
If Irp is present, it'll send it down first to the PDO.
|
|
Unhooks the interrupt/cancels poll timer etc.
|
|
|
|
Arguments:
|
|
|
|
Fdo - Pointer to functional device object for the sd
|
|
controller
|
|
Irp - If present it's the pointer to the stop Irp initiated
|
|
by PnP
|
|
|
|
Return value:
|
|
|
|
STATUS_SUCCESS - Sdbus controller successfully stopped
|
|
Other - Stop failed
|
|
|
|
--*/
|
|
{
|
|
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
NTSTATUS status;
|
|
|
|
|
|
SdbusFdoDisarmWake(fdoExtension);
|
|
|
|
//
|
|
// Disable the interrupt
|
|
//
|
|
|
|
(*(fdoExtension->FunctionBlock->DisableEvent))(fdoExtension, SDBUS_EVENT_ALL);
|
|
// (*(socket->SocketFnPtr->PCBEnableDisableWakeupEvent))(socket, NULL, FALSE);
|
|
|
|
//
|
|
// the bus driver below us will make us go offline
|
|
//
|
|
fdoExtension->Flags |= SDBUS_FDO_OFFLINE;
|
|
|
|
//
|
|
// clear pending event
|
|
// ISSUE: NEED TO IMPLEMENT : drain worker timer before OK'ing stop
|
|
KeCancelTimer(&fdoExtension->WorkerTimer);
|
|
|
|
//
|
|
// Send this down to the PDO
|
|
//
|
|
if (ARGUMENT_PRESENT(Irp)) {
|
|
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
if (!(fdoExtension->Flags & SDBUS_DEVICE_STARTED)) {
|
|
//
|
|
// Already stopped
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (fdoExtension->SdbusInterruptObject) {
|
|
//
|
|
// unhook the interrupt
|
|
//
|
|
IoDisconnectInterrupt(fdoExtension->SdbusInterruptObject);
|
|
fdoExtension->SdbusInterruptObject = NULL;
|
|
}
|
|
|
|
//
|
|
// Unmap any i/o space or memory we might have mapped
|
|
//
|
|
|
|
if (fdoExtension->Flags & SDBUS_HOST_REGISTER_BASE_MAPPED) {
|
|
MmUnmapIoSpace(fdoExtension->HostRegisterBase,
|
|
fdoExtension->HostRegisterSize);
|
|
fdoExtension->Flags &= ~SDBUS_HOST_REGISTER_BASE_MAPPED;
|
|
fdoExtension->HostRegisterBase = 0;
|
|
fdoExtension->HostRegisterSize = 0;
|
|
}
|
|
|
|
if (fdoExtension->IoWorkItem) {
|
|
IoFreeWorkItem(fdoExtension->IoWorkItem);
|
|
fdoExtension->IoWorkItem = NULL;
|
|
}
|
|
|
|
fdoExtension->Flags &= ~SDBUS_DEVICE_STARTED;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusFdoRemoveDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles IRP_MN_REMOVE for the sd controller.
|
|
Stops the adapter if it isn't already, sends the IRP
|
|
to the PDO first & cleans up the Fdo for this controller
|
|
and detaches & deletes the device object.
|
|
|
|
Arguments:
|
|
|
|
Fdo - Pointer to functional device object for the controller
|
|
to be removed
|
|
|
|
Return value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
PDEVICE_OBJECT pdo, nextPdo, fdo, prevFdo;
|
|
PPDO_EXTENSION pdoExtension;
|
|
NTSTATUS status;
|
|
|
|
if (fdoExtension->Flags & SDBUS_DEVICE_STARTED) {
|
|
//
|
|
// Stop the fdo first.
|
|
//
|
|
SdbusFdoStopDevice(Fdo, NULL);
|
|
}
|
|
|
|
//
|
|
// Send this down to the PDO
|
|
//
|
|
|
|
status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// If the PdoList in the fdoExtension is non-empty it means:
|
|
// that the PDOs in the list were not physically removed, but
|
|
// a soft REMOVE was issued, hence they are still hanging on
|
|
// and now this controller itself is being REMOVED.
|
|
// Hence we dispose of those PDOs now
|
|
//
|
|
|
|
for (pdo = fdoExtension->PdoList; pdo != NULL ; pdo = nextPdo) {
|
|
DebugPrint((SDBUS_DEBUG_INFO,
|
|
"RemoveDevice: pdo %x child of fdo %x was not removed before fdo\n",
|
|
pdo, Fdo));
|
|
|
|
pdoExtension = pdo->DeviceExtension;
|
|
|
|
ASSERT (!IsDevicePhysicallyRemoved(pdoExtension));
|
|
//
|
|
// It's possible for this bit to be on, if the device was added,
|
|
// but never started (because of some other error.
|
|
//ASSERT (!IsDeviceAlive(pdoExtension));
|
|
|
|
nextPdo = pdoExtension->NextPdoInFdoChain;
|
|
if (!IsDeviceDeleted(pdoExtension)) {
|
|
MarkDeviceDeleted(pdoExtension);
|
|
SdbusCleanupPdo(pdo);
|
|
IoDeleteDevice(pdo);
|
|
}
|
|
}
|
|
|
|
MarkDeviceDeleted(fdoExtension);
|
|
|
|
//
|
|
// Remove this from the fdo list..
|
|
//
|
|
prevFdo = NULL;
|
|
for (fdo = FdoList; fdo != NULL; prevFdo = fdo, fdo = fdoExtension->NextFdo) {
|
|
fdoExtension = fdo->DeviceExtension;
|
|
if (fdo == Fdo) {
|
|
if (prevFdo) {
|
|
//
|
|
// Delink this fdo
|
|
//
|
|
((PFDO_EXTENSION)prevFdo->DeviceExtension)->NextFdo
|
|
= fdoExtension->NextFdo;
|
|
} else {
|
|
FdoList = fdoExtension->NextFdo;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
DebugPrint((SDBUS_DEBUG_PNP, "fdo %08x Remove detach & delete\n", Fdo));
|
|
IoDetachDevice(((PFDO_EXTENSION)Fdo->DeviceExtension)->LowerDevice);
|
|
IoDeleteDevice(Fdo);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusDeviceRelations(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp,
|
|
IN DEVICE_RELATION_TYPE RelationType,
|
|
OUT PDEVICE_RELATIONS *DeviceRelations
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will force enumeration of the sd controller represented by Fdo,
|
|
allocate a device relations structure and fill in the count and object array with
|
|
referenced object pointers to the valid PDOs which are created during enumeration
|
|
|
|
Arguments:
|
|
|
|
Fdo - a pointer to the functional device object being enumerated
|
|
Irp - pointer to the Irp
|
|
RelationType - Type of relationship to be retrieved
|
|
DeviceRelations - Structure to store the device relations
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PDEVICE_OBJECT currentPdo;
|
|
PPDO_EXTENSION currentPdoExtension;
|
|
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
ULONG newRelationsSize, oldRelationsSize = 0;
|
|
PDEVICE_RELATIONS deviceRelations = NULL, oldDeviceRelations;
|
|
ULONG i;
|
|
ULONG count;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Handle only bus, ejection & removal relations for now
|
|
//
|
|
|
|
if (RelationType != BusRelations &&
|
|
RelationType != RemovalRelations) {
|
|
DebugPrint((SDBUS_DEBUG_INFO,
|
|
"SdbusDeviceRelations: RelationType %d, not handled\n",
|
|
(USHORT) RelationType));
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Need reenumeration only if bus relations are required
|
|
// We need to save the pointer to the old device relations
|
|
// before we call SdbusReenumerateDevices, as it might trample
|
|
// on it
|
|
//
|
|
oldDeviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
|
|
|
|
// I don't understand how this can be non-null, so I added this
|
|
// assert to find out.
|
|
ASSERT(oldDeviceRelations == NULL);
|
|
|
|
if (RelationType == BusRelations) {
|
|
status = SdbusEnumerateDevices(Fdo, Irp);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if ((fdoExtension->LivePdoCount == 0) ||
|
|
(RelationType == RemovalRelations)) {
|
|
//
|
|
// No PDO's to report, we can return early.
|
|
// If no device_relations structure has yet been allocated, however,
|
|
// we need to allocate one & set the count to zero. This will ensure
|
|
// that regardless of whether we pass this IRP down or not, the IO
|
|
// subsystem won't barf.
|
|
//
|
|
if (oldDeviceRelations == NULL) {
|
|
*DeviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
|
if (*DeviceRelations == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
(*DeviceRelations)->Count = 0;
|
|
(*DeviceRelations)->Objects[0] = NULL;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (!(oldDeviceRelations) || (oldDeviceRelations->Count == 0)) {
|
|
newRelationsSize = sizeof(DEVICE_RELATIONS)+(fdoExtension->LivePdoCount - 1)
|
|
* sizeof(PDEVICE_OBJECT);
|
|
} else {
|
|
oldRelationsSize = sizeof(DEVICE_RELATIONS) +
|
|
(oldDeviceRelations->Count-1) * sizeof(PDEVICE_OBJECT);
|
|
newRelationsSize = oldRelationsSize + fdoExtension->LivePdoCount
|
|
* sizeof(PDEVICE_OBJECT);
|
|
}
|
|
|
|
deviceRelations = ExAllocatePool(PagedPool, newRelationsSize);
|
|
|
|
if (deviceRelations == NULL) {
|
|
|
|
DebugPrint((SDBUS_DEBUG_FAIL,
|
|
"SdbusDeviceRelations: unable to allocate %d bytes for device relations\n",
|
|
newRelationsSize));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (oldDeviceRelations) {
|
|
if ((oldDeviceRelations)->Count > 0) {
|
|
RtlCopyMemory(deviceRelations, oldDeviceRelations, oldRelationsSize);
|
|
}
|
|
count = oldDeviceRelations->Count; // May be zero
|
|
ExFreePool (oldDeviceRelations);
|
|
} else {
|
|
count = 0;
|
|
}
|
|
//
|
|
// Copy the object pointers into the structure
|
|
//
|
|
for (currentPdo = fdoExtension->PdoList ;currentPdo != NULL;
|
|
currentPdo = currentPdoExtension->NextPdoInFdoChain) {
|
|
|
|
currentPdoExtension = currentPdo->DeviceExtension;
|
|
|
|
if (!IsDevicePhysicallyRemoved(currentPdoExtension)) {
|
|
//
|
|
// Devices have to be referenced by the bus driver
|
|
// before returning them to PNP
|
|
//
|
|
deviceRelations->Objects[count++] = currentPdo;
|
|
status = ObReferenceObjectByPointer(currentPdo,
|
|
0,
|
|
NULL,
|
|
KernelMode);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "SdbusDeviceRelations: status %#08lx "
|
|
"while referencing object %#08lx\n",
|
|
status,
|
|
currentPdo));
|
|
}
|
|
}
|
|
}
|
|
|
|
deviceRelations->Count = count;
|
|
*DeviceRelations = deviceRelations;
|
|
return STATUS_SUCCESS;
|
|
}
|