📄 resource.c
字号:
/*++
Copyright (c) 1997-1998 Microsoft Corporation
Module Name:
resource.c
Abstract:
This file contains routines that will initialize and configure a PCI
device, including getting the PCI resources, parsing the PCI resources,
mapping memory and I/O spaces, connecting interrupts, initializing DPC
routines, and various memory allocations.
Author:
Steve Dziok (SteveDz)
Environment:
Kernel mode
Revision History:
--*/
#include <stdio.h> // Needed for sprintf() routine.
#include "pcidma.h"
//
// Make sure the initialization code is removed from memory after use.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, CreateDeviceObject)
#pragma alloc_text(INIT, GetAdapterInfo)
#pragma alloc_text(INIT, GetDeviceAddresses)
#pragma alloc_text(INIT, GetPciResources)
#pragma alloc_text(INIT, ParseResourceList)
#pragma alloc_text(INIT, SetBaseAddress)
#pragma alloc_text(INIT, SetupIsrAndDpc)
#pragma alloc_text(INIT, SetupPciDevice)
#endif
NTSTATUS
CreateDeviceObject(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath,
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN USHORT DeviceNumber,
OUT PDEVICE_OBJECT *NewDeviceObject
)
/*++
Routine Description:
Arguments:
DriverObject - Pointer to the driver object created by the I/O manager.
RegistryPath - Pointer to the driver specific key
\Registry
\Machine
\System
\CurrentControlSet
\Services
\<DriverName>
BusNumber - Zero-based system bus number for the PCI device.
SlotNumber - Logical slot number indicating the location of the PCI
device. See the PCI_SLOT_NUMBER for a description of
this value.
DeviceNumber - Zero-based device number. Used to create unique device
names.
DeviceObject - Pointer to the device object created by this routine if
successful.
Return Value:
NTSTATUS
--*/
{
PDEVICE_OBJECT deviceObject;
PDEVICE_EXTENSION deviceExtension;
NTSTATUS status;
UCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
UCHAR win32NameBuffer[MAXIMUM_FILENAME_LENGTH];
ANSI_STRING ntNameString;
ANSI_STRING win32NameString;
PUNICODE_STRING originalPath;
UNICODE_STRING ntUnicodeString;
//
// Create device object name for this device.
//
//
// Indicate we don't yet have a device object.
//
*NewDeviceObject = NULL;
sprintf(ntNameBuffer,
"\\Device\\"DRIVER_NAME"%d",
DeviceNumber
);
RtlInitAnsiString(&ntNameString,
ntNameBuffer
);
DebugPrint((2, "Creating device object %s \n", ntNameBuffer));
//
// Allocate buffer for Unicode string and convert ANSI string to Unicode.
//
status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
&ntNameString,
TRUE
);
if (!NT_SUCCESS(status)) {
DebugPrint((1, "Unable to convert ANSI string to UNICODE \n"));
return status;
}
//
// Create the device object.
//
status = IoCreateDevice(DriverObject,
sizeof(DEVICE_EXTENSION),
&ntUnicodeString,
FILE_DEVICE_UNKNOWN,
0, // No device-specific info
FALSE, // Not an exclusive device
&deviceObject
);
//
// Check whether IoCreateDevice was successful.
//
if (!NT_SUCCESS(status)) {
DebugPrint((1, "Unable to create device object. \n"));
RtlFreeUnicodeString(&ntUnicodeString);
return status;
}
DebugPrint((3, "Device object 0x%x \n", deviceObject));
//
// Indicate that IRPs should include MDLs for data transfers.
//
deviceObject->Flags |= DO_DIRECT_IO;
//
// Set up the device extension.
//
deviceExtension = deviceObject->DeviceExtension;
RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION));
deviceExtension->DeviceObject = deviceObject;
deviceExtension->BusNumber = BusNumber;
deviceExtension->SlotNumber = SlotNumber;
deviceExtension->ScatterGather = SCATTER_GATHER_SUPPORT;
deviceExtension->InterfaceType = PCIBus;
deviceExtension->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
//
// Set the maximum physical pages for now, but this value may change if
// the call to HalGetAdapter returns less pages.
//
deviceExtension->MaximumPhysicalPages = MAXIMUM_PHYSICAL_PAGES;
//
// Save a copy of the registry path for clean up purposes.
//
originalPath = &deviceExtension->RegistryPath;
RtlInitUnicodeString(originalPath,
NULL
);
originalPath->MaximumLength = RegistryPath->MaximumLength;
originalPath->Buffer = ExAllocatePoolWithTag(NonPagedPool,
originalPath->MaximumLength,
EX_POOL_TAG_VALUE
);
//
// If the buffer to create the registry path copy could not be created,
// cleanup and exit.
//
if (!originalPath->Buffer) {
DebugPrint((1, "Unable to create new registry path \n"));
FreeDeviceResources(DriverObject,
deviceObject
);
RtlFreeUnicodeString(&ntUnicodeString);
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
RtlCopyUnicodeString(originalPath,
RegistryPath
);
//
// Create a symbolic link so a Win32 application can communicate with
// this driver.
//
sprintf(win32NameBuffer,
"\\DosDevices\\"DRIVER_NAME"%d",
DeviceNumber
);
RtlInitAnsiString(&win32NameString,
win32NameBuffer
);
DebugPrint((2, "Creating symbolic link %s \n", win32NameBuffer));
//
// Allocate buffer for Unicode string and convert ANSI string to Unicode.
//
status = RtlAnsiStringToUnicodeString(&deviceExtension->Win32UnicodeString,
&win32NameString,
TRUE
);
//
// If we are unable to create the Win32 name, we will continue to set up
// the driver. If the driver needs to have the symbolic link, then the
// code can be changed to cleanup and exit.
//
if (NT_SUCCESS(status)) {
//
// Connect the symbolic link.
//
status = IoCreateSymbolicLink(&deviceExtension->Win32UnicodeString,
&ntUnicodeString
);
if (!NT_SUCCESS(status)) {
DebugPrint((1, "Unable to create symbolic link. Status = %x \n",
status
));
//
// On error, free the DosDevice name Unicode buffer.
//
RtlFreeUnicodeString(&deviceExtension->Win32UnicodeString);
//
// Don't leave this pointer once the buffer has been freed.
//
RtlInitUnicodeString(&deviceExtension->Win32UnicodeString,
NULL
);
} else {
deviceExtension->SymbolicLinkCreated = TRUE;
}
//
// Note that we fall through and continue even if the symbolic
// link failed.
//
}
//
// Release the NT device name Unicode buffer.
//
RtlFreeUnicodeString(&ntUnicodeString);
//
// Return the newly created device object.
//
*NewDeviceObject = deviceObject;
return status;
} // CreateDeviceObject
VOID
FreeDeviceResources(
PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Free all system objects and resources used by the specified device object.
Delete the device object after everything is freed.
Arguments:
DriverObject - Pointer to the driver object created by the I/O manager.
DeviceObject - Pointer to the device object for a specific adapter.
Return Value:
None
--*/
{
PCM_RESOURCE_LIST resourceList;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
//
// If no device extension, something bad happened. Just return.
//
if (!deviceExtension) {
DebugPrint((1, "FreeDeviceResources invalid DeviceExtension \n"));
DebugPrint((1, " *** WARNING: Unable to free resources *** \n"));
ASSERT(0);
return;
}
//
// If necessary, stop the PCI device from running before doing any
// cleanup. This may require stopping or resetting the PCI device.
//
//
// Indicate that the device should not be interrupting anymore.
//
InterlockedExchange(&deviceExtension->DeviceConfigured,
(LONG)0
);
//
// Disconnect any interrupts. This should be done first to insure that
// an interrupt doesn't occur and call into the driver's ISR.
//
if (deviceExtension->InterruptObject) {
IoDisconnectInterrupt(deviceExtension->InterruptObject);
}
//
// Delete the symbolic link.
//
if (deviceExtension->SymbolicLinkCreated) {
IoDeleteSymbolicLink(&deviceExtension->Win32UnicodeString);
//
// Free the Win32 Unicode buffer.
//
RtlFreeUnicodeString(&deviceExtension->Win32UnicodeString);
}
//
// Free any storage allocated.
//
if (deviceExtension->DpcContext) {
ExFreePool(deviceExtension->DpcContext);
}
if (deviceExtension->SGList) {
HalFreeCommonBuffer(deviceExtension->AdapterObject,
deviceExtension->SGListLength,
deviceExtension->SGListPA,
deviceExtension->SGList,
deviceExtension->SGListCached
);
}
//
// Unmap any memory or I/O resources.
//
ReleaseDeviceAddresses(deviceExtension->BaseAddress,
deviceExtension->AddressCount
);
//
// Free any resources claimed in the registry.
//
if (deviceExtension->RegistryPath.Buffer &&
deviceExtension->RegistryPath.Length) {
IoAssignResources(&deviceExtension->RegistryPath,
&deviceExtension->ClassUnicodeString,
DriverObject,
DeviceObject,
NULL,
&resourceList
);
//
// Free the registry path buffer.
//
ExFreePool(deviceExtension->RegistryPath.Buffer);
}
//
// Free the DriverClassName Unicode buffer.
//
if (deviceExtension->ClassUnicodeString.Length) {
RtlFreeUnicodeString(&deviceExtension->ClassUnicodeString);
}
//
// Finally, delete the device object.
//
IoDeleteDevice(DeviceObject);
} // FreeDeviceResources
NTSTATUS
GetAdapterInfo(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Get the adapter object required for busmaster DMA. Allocate a structure
for holding the scatter/gather lists.
Arguments:
DriverObject - Pointer to the driver object created by the I/O manager.
DeviceObject - Pointer to the device object for a specific adapter.
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
NTSTATUS status;
DEVICE_DESCRIPTION deviceDescription;
ULONG numberOfMapRegisters;
//
// Set up the adapter-specific information.
//
deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
deviceDescription.Master = TRUE;
deviceDescription.ScatterGather = deviceExtension->ScatterGather;
deviceDescription.BusNumber = deviceExtension->BusNumber;
deviceDescription.InterfaceType = deviceExtension->InterfaceType;
deviceDescription.MaximumLength = deviceExtension->MaximumTransferLength;
//
// The following adapter-specific information is not required.
//
// deviceDescription.DemandMode = FALSE;
// deviceDescription.AutoInitialize = FALSE;
// deviceDescription.Dma32BitAddresses = FALSE;
// deviceDescription.IgnoreCount = xxx;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -