📄 resource.c
字号:
break;
case CmResourceTypeMemory:
//
// Verify that we haven't exceeded the maximum resources for a
// PCI device.
//
if (rangeCount < PCI_TYPE0_ADDRESSES) {
DebugPrint((3,
" Memory range: Base = %08x : %08x Length = %08x \n",
partialData->u.Port.Start.HighPart,
partialData->u.Port.Start.LowPart,
partialData->u.Port.Length
));
//
// This driver will only look at read/write memory.
//
if (CM_RESOURCE_MEMORY_READ_WRITE == partialData->Flags) {
//
// Save memory resource information.
//
baseAddress->RangeStart = partialData->u.Port.Start;
baseAddress->RangeLength = partialData->u.Port.Length;
baseAddress->RangeInMemory = TRUE;
baseAddress->ResourceMapped = FALSE;
//
// Bump up the count of memory and I/O resources.
//
rangeCount++;
//
// Point to the next base address storage area.
//
baseAddress++;
} else {
DebugPrint((3,
" ** Ignoring memory: flags = %08x \n",
partialData->Flags
));
}
}
break;
case CmResourceTypeDma:
//
// Don't do anything with DMA type resources. This doesn't
// really make sense for a PCI busmaster device.
//
DebugPrint((3, "CmResourceTypeDma not supported \n"));
break;
default:
//
// Skip unknown resource types.
//
DebugPrint((3, "Unknown resource type \n"));
break;
} // switch
}
//
// Save the count of the number of resources found.
//
DeviceExtension->AddressCount = rangeCount;
} // ParseResourceList
VOID
ReleaseDeviceAddresses(
IN PBASE_ADDRESS BaseAddress,
IN ULONG AddressCount
)
/*++
Routine Description:
Unmap any physical addresses previously mapped.
Arguments:
BaseAddress - Array holding information about I/O and memory resources.
AddressCount - Indicates the total number of I/O and memory resources
available for this adapter.
Return Value:
None.
--*/
{
ULONG i;
//
// Loop through each of the raw I/O ports and memory ranges.
//
for (i = 0; i < AddressCount; i++, BaseAddress++) {
if (BaseAddress->ResourceMapped) {
MmUnmapIoSpace(BaseAddress->MappedRangeStart,
BaseAddress->RangeLength
);
}
}
} // ReleaseDeviceAddresses
BOOLEAN
SetBaseAddress(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Choose one of the address spaces to be the base address for the device.
All device accesses will be an offset from this base address.
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:
TRUE
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PBASE_ADDRESS baseAddress = deviceExtension->BaseAddress;
ULONG i;
BOOLEAN status = FALSE;
///////////////////////////////////////////////////////////////
//
// VENDOR_UNIQUE -- Vendor unique code -- START
//
///////////////////////////////////////////////////////////////
#ifdef VENDORID_1000_DEVICEID_0004
//
// For this sample, simply pick the first memory or I/O range and use
// this as the device base.
//
// Note that if this sample is changed to use I/O ports rather than
// memory mapped registers, all the APIs to access the adapter registers
// must also be changed.
//
for (i = 0; i < deviceExtension->AddressCount; i++ ) {
#ifdef USE_MEMORY_MAPPED_REGISTERS
if (baseAddress->MappedRangeInMemory) {
#else
if (!baseAddress->MappedRangeInMemory) {
#endif
deviceExtension->RegisterBase = baseAddress->MappedRangeStart;
status = TRUE;
DebugPrint((3,
"RegisterBase %x \n",
deviceExtension->RegisterBase
));
break;
}
baseAddress++;
}
//
// If unable to set base address, free resources and return.
//
if (FALSE == status) {
FreeDeviceResources(DriverObject,
DeviceObject
);
}
#endif
///////////////////////////////////////////////////////////////
//
// VENDOR_UNIQUE -- Vendor unique code -- END
//
///////////////////////////////////////////////////////////////
return status;
} // SetBaseAddress
NTSTATUS
SetupIsrAndDpc(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Initialize the DPC and ISR. Allocate any storage needed by the DPC
routine to maintain context.
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;
ULONG vector;
KIRQL irql;
KAFFINITY affinity;
//
// Register the DPC routine.
//
IoInitializeDpcRequest(DeviceObject,
PciDmaDpc
);
//
// Allocate storage for the DPC context if needed. This sample
// allocates storage, but does not use anything for the DPC. This code
// can be removed in a real driver if the DPC context is unused. If
// removed here, remove the corresponding code from FreeDeviceResources().
//
deviceExtension->DpcContext = ExAllocatePoolWithTag(NonPagedPool,
sizeof(DPC_CONTEXT),
EX_POOL_TAG_VALUE
);
if (!deviceExtension->DpcContext) {
DebugPrint((1, "Unable to allocate DpcContext \n"));
FreeDeviceResources(DriverObject,
DeviceObject
);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Set up the device interrupt. Need to set up the interrupt after
// setting up the memory and I/O resources in case the card suddenly
// generates an interrupt and the driver's ISR is called. If this
// happens, the device registers will be properly mapped so we can
// safely clear the interrupt.
//
if (deviceExtension->InterruptLevel || deviceExtension->InterruptVector) {
vector = HalGetInterruptVector(deviceExtension->InterfaceType,
deviceExtension->BusNumber,
deviceExtension->InterruptLevel,
deviceExtension->InterruptVector,
&irql,
&affinity
);
status = IoConnectInterrupt(&deviceExtension->InterruptObject,
(PKSERVICE_ROUTINE)PciDmaISR,
DeviceObject, // Context passed to ISR
NULL, // Single vector supported
vector,
irql,
irql, // Synchronization IRQL
deviceExtension->InterruptMode,
TRUE, // Shareable interrupts
affinity,
FALSE // Don't save FP stack
);
if (!NT_SUCCESS(status)) {
DebugPrint((1, "Unable to connect interrupt. Status = %x \n",
status
));
deviceExtension->InterruptObject = NULL;
FreeDeviceResources(DriverObject,
DeviceObject
);
return status;
}
DebugPrint((2, "Interrupt connected \n"));
}
return STATUS_SUCCESS;
} // SetupIsrAndDpc
NTSTATUS
SetupPciDevice(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath,
IN ULONG BusNumber,
IN ULONG SlotNumber,
IN USHORT DeviceNumber
)
/*++
Routine Description:
Sets up a PCI device for use. Creates a device object, claims the
resources, maps the I/O and memory ranges, prepares the interrupt, and
stores any adapter-specific information in the adapter's device extension.
Arguments:
DriverObject - Pointer to the driver object created by the I/O manager.
RegistryPath - Pointer to the registry path for this driver object.
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.
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension = NULL;
PDEVICE_OBJECT deviceObject = NULL;
NTSTATUS status;
DebugPrint((3, "SetupPciDevice \n"));
//
// Create device object and fill in device extension.
//
status = CreateDeviceObject(DriverObject,
RegistryPath,
BusNumber,
SlotNumber,
DeviceNumber,
&deviceObject
);
if (!NT_SUCCESS(status) || !(deviceObject)) {
return status;
}
//
// Get the device extension from the newly created device object.
//
deviceExtension = deviceObject->DeviceExtension;
ASSERT(deviceExtension != NULL);
//
// Get the PCI device resources.
//
status = GetPciResources(DriverObject,
deviceObject,
RegistryPath
);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Get the adapter object and setup DMA information.
//
status = GetAdapterInfo(DriverObject,
deviceObject
);
if (!NT_SUCCESS(status)) {
return status;
}
//
// Map the memory and/or I/O spaces.
//
if (!GetDeviceAddresses(deviceExtension->BaseAddress,
deviceExtension->AddressCount,
deviceExtension->InterfaceType,
deviceExtension->BusNumber
)) {
DebugPrint((1, "Unable to map memory and I/O resources \n"));
FreeDeviceResources(DriverObject,
deviceObject
);
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
//
// Set the base registers for the chip, usually either I/O or memory
// mapped, not both. Note that there are different APIs for I/O versus
// memory access, so if the base registers are changed from I/O to memory
// mapped, the corresponding access API must also be changed.
//
if (!SetBaseAddress(DriverObject, deviceObject)) {
DebugPrint((1, "Unable to set base address register \n"));
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
status = SetupIsrAndDpc(DriverObject,
deviceObject
);
if (!NT_SUCCESS(status)) {
return status;
}
//
// If we're all the way to the end of this routine, we've successfully
// configured one PCI device. Indicate this fact.
//
InterlockedIncrement(&deviceExtension->DeviceConfigured);
DebugPrint((1, "Device #%d created and configured \n", DeviceNumber));
///////////////////////////////////////////////////////////////
//
// VENDOR_UNIQUE -- Vendor unique code -- START
//
///////////////////////////////////////////////////////////////
#ifdef VENDORID_1000_DEVICEID_0004
//
// Vendor may have to program the device to prepare it for I/O requests.
//
KeSynchronizeExecution(deviceExtension->InterruptObject,
InitializePciHw,
deviceExtension
);
#endif
///////////////////////////////////////////////////////////////
//
// VENDOR_UNIQUE -- Vendor unique code -- END
//
///////////////////////////////////////////////////////////////
return STATUS_SUCCESS;
} // SetupPciDevice
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -