📄 resource.c
字号:
// deviceDescription.DmaChannel = xxx;
// deviceDescription.DmaWidth = xxx;
// deviceDescription.DmaSpeed = xxx;
// deviceDescription.DmaPort = xxx;
//
// Get the adapter object.
//
deviceExtension->AdapterObject = HalGetAdapter(&deviceDescription,
&numberOfMapRegisters
);
//
// If we can't get the adapter object, clean up and exit.
//
if (deviceExtension->AdapterObject == NULL) {
DebugPrint((1, "HalGetAdapter failed\n"));
FreeDeviceResources(DriverObject,
DeviceObject
);
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
//
// The number of map registers will limit the number of physical pages
// the driver can support (i.e. how fragmented the user buffer can be).
// If we get less map registers than physical breaks we support, lower
// the maximum physical breaks value.
//
if (numberOfMapRegisters < deviceExtension->MaximumPhysicalPages) {
deviceExtension->MaximumPhysicalPages = numberOfMapRegisters;
}
DebugPrint((2,
"MaxTransferLength = 0x%08x MaxPhysicalPages = 0x%x \n",
deviceExtension->MaximumTransferLength,
deviceExtension->MaximumPhysicalPages
));
//
// Allocate storage for the scatter/gather list. Some adapters can DMA
// directly from this SG list, so this driver will allocate a buffer
// using HalAllocateCommonBuffer. If this requirement is not needed,
// one can use ExAllocatePool (NonPaged of course).
//
//
// Since this sample only supports one I/O on the device at a time, the
// SG list is stored in the device extension. If multiple I/O's are to
// be supported, there would have to be a SG list for each outstanding
// I/O and they would have to be stored and accessed differently.
//
deviceExtension->SGListLength = deviceExtension->MaximumPhysicalPages *
sizeof(SG_ENTRY);
deviceExtension->SGListCached = FALSE;
deviceExtension->SGList = HalAllocateCommonBuffer(deviceExtension->AdapterObject,
deviceExtension->SGListLength,
&deviceExtension->SGListPA,
deviceExtension->SGListCached
);
//
// Unable to get the SG list, cleanup and exit.
//
if (!deviceExtension->SGList) {
DebugPrint((1, "HalAllocateCommonBuffer failed \n"));
FreeDeviceResources(DriverObject,
DeviceObject
);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Indicate that the busmaster DMA information is ready to go.
//
return STATUS_SUCCESS;
} // GetAdapterInfo
BOOLEAN
GetDeviceAddresses(
IN PBASE_ADDRESS BaseAddress,
IN ULONG AddressCount,
IN INTERFACE_TYPE InterfaceType,
IN ULONG BusNumber
)
/*++
Routine Description:
Translates a bus-specific address into the corresponding system logical
address. Also, this will map a physical range to nonpaged system space if
required.
Most PCI devices respond to either an I/O range or a memory range, but
not both. For simplicity, this function simply maps all the resources
for a given PCI device. In reality, only one of the ranges might be
used, so some cleanup may be needed here.
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.
InterfaceType - Indicates the bus type for this adapter (PCI, ISA, EISA,
etc.).
BusNumber - Zero-based system bus number for the PCI device.
Return Value:
TRUE - At least one I/O or memory space has been translated and/or mapped.
FALSE - No I/O or memory spaces successfully translated or mapped.
--*/
{
ULONG i;
ULONG addressSpace;
PHYSICAL_ADDRESS cardAddress;
BOOLEAN mappedOne = FALSE;
//
// Loop through each of the raw I/O ports and memory ranges.
//
for (i = 0; i < AddressCount; i++, BaseAddress++) {
//
// Translate the bus-specific address to a system logical address.
//
addressSpace = !BaseAddress->RangeInMemory;
cardAddress = BaseAddress->RangeStart;
if (!HalTranslateBusAddress(InterfaceType,
BusNumber,
BaseAddress->RangeStart,
&addressSpace,
&cardAddress
)) {
DebugPrint((2,
"HalTranslateBusAddress failed for 0x%x \n",
BaseAddress->RangeStart
));
continue;
}
//
// Indicate that we mapped at least one range.
//
mappedOne = TRUE;
//
// Save the (possibly changed) I/O-memory indicator. Remember that
// zero indicates a memory address, and one indicates I/O space. On
// some RISC systems, there is no I/O space. So an AddressSpace
// indicating I/O space input to HalTranslateBusAddress may be
// changed to memory space on return.
//
BaseAddress->MappedRangeInMemory = (BOOLEAN)(addressSpace ? 0 : 1);
//
// Map the device base address into the virtual address space if the
// address is in memory space. Note that HalTranslateBusAddress may
// have changed the address space indicator on return.
//
if (!addressSpace) {
BaseAddress->MappedRangeStart = MmMapIoSpace(cardAddress,
BaseAddress->RangeLength,
FALSE
);
//
// Make sure we unmap this resource.
//
BaseAddress->ResourceMapped = TRUE;
} else {
BaseAddress->MappedRangeStart = (PVOID)cardAddress.LowPart;
}
}
//
// Indicate whether any address spaces were mapped.
//
return mappedOne;
} // GetDeviceAddresses
NTSTATUS
GetPciResources(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Retrieve the PCI resources from the HAL, parse the resource list, and
save the information in a driver-specific structure.
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;
PCM_RESOURCE_LIST resourceList;
NTSTATUS status;
ANSI_STRING classNameString;
//
// Set up a driver class name to put all the resources under. If we are
// unable to create a valid driver class name, we can assign the
// resources under the generic "Other" registry key.
//
RtlInitAnsiString(&classNameString,
DRIVER_NAME"Adapter"
);
status = RtlAnsiStringToUnicodeString(&deviceExtension->ClassUnicodeString,
&classNameString,
TRUE
);
//
// If the driver class name couldn't be created, just display a debug
// message and continue getting the PCI resources.
//
if (!NT_SUCCESS(status)) {
DebugPrint((1, "Unable to create class name. Status = %x \n",
status
));
RtlInitUnicodeString(&deviceExtension->ClassUnicodeString,
NULL
);
}
//
// Assign the PCI resources.
//
status = HalAssignSlotResources(RegistryPath,
&deviceExtension->ClassUnicodeString,
DriverObject,
DeviceObject,
deviceExtension->InterfaceType,
deviceExtension->BusNumber,
deviceExtension->SlotNumber,
&resourceList
);
//
// If the resources couldn't be acquired, cleanup and exit.
//
if (!NT_SUCCESS(status)) {
DebugPrint((1, "Unable to assign PCI resources. Status = %x \n",
status
));
FreeDeviceResources(DriverObject,
DeviceObject
);
return status;
}
//
// Parse the resource list and save the information.
//
ParseResourceList(deviceExtension,
resourceList->List
);
DebugPrint((2, "%d resource(s) found (I/O and memory) \n",
deviceExtension->AddressCount
));
return STATUS_SUCCESS;
} // GetPciResources
BOOLEAN
InitializePciHw(
IN PVOID Context
)
/*++
Routine Description:
SyncCriticalSection routine used to initialize the PCI device. Note that
this routine is run at DIRQL so the routines that can be called are
limited. This sample resets the PCI device and configures the device
to generate only one type of interrupt.
Arguments:
Context - Driver determined context information. For this driver,
the context is a pointer to the device extension.
Return Value:
TRUE
--*/
{
PDEVICE_EXTENSION deviceExtension = Context;
///////////////////////////////////////////////////////////////
//
// VENDOR_UNIQUE -- Vendor unique code -- START
//
///////////////////////////////////////////////////////////////
#ifdef VENDORID_1000_DEVICEID_0004
UCHAR byteValue;
//
// Do whatever is necessary to enable the device. This routine is run
// at DIRQL so as to not be preempted by the device interrupting.
// Please insure this routine runs as quickly as possible.
//
//
// Vendor specific code.
//
//
// Set the time value in the device extension. This value is between
// 0x01 and 0x0f.
//
deviceExtension->TimerPeriod = 0x03;
//
// Software reset.
//
byteValue = READ_UCHAR(INT_STATUS) | 0x40;
WRITE_UCHAR(INT_STATUS, byteValue);
//
// Clear the software reset.
//
byteValue = READ_UCHAR(INT_STATUS) & 0xbf;
WRITE_UCHAR(INT_STATUS, byteValue);
//
// Enable only one type of interrupt for this sample.
//
WRITE_UCHAR(INT_ENABLE1, 0x02);
#endif
///////////////////////////////////////////////////////////////
//
// VENDOR_UNIQUE -- Vendor unique code -- END
//
///////////////////////////////////////////////////////////////
return TRUE;
} // InitializePciHw
VOID
ParseResourceList(
IN PDEVICE_EXTENSION DeviceExtension,
IN PCM_FULL_RESOURCE_DESCRIPTOR AdapterResources
)
/*++
Routine Description:
Given a full resource description, store away the relevant information
for the adapter in the device extension.
Arguments:
DeviceExtension - Adapter-specific storage area.
AdapterResources - The CM_FULL_RESOURCE_DESCRIPTOR list for this adapter.
Return Value:
None.
--*/
{
PBASE_ADDRESS baseAddress = DeviceExtension->BaseAddress;
ULONG index;
ULONG rangeCount = 0;
BOOLEAN interruptSet = FALSE;
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialData;
DebugPrint((3, "ParseResourceList \n"));
for (index = 0; index < AdapterResources->PartialResourceList.Count; index++) {
partialData = &AdapterResources->PartialResourceList.PartialDescriptors[index];
switch (partialData->Type) {
case CmResourceTypePort:
//
// Verify that we haven't exceeded the maximum resources for a
// PCI device.
//
if (rangeCount < PCI_TYPE0_ADDRESSES) {
DebugPrint((3,
" I/O range: Base = %08x : %08x Length = %08x \n",
partialData->u.Port.Start.HighPart,
partialData->u.Port.Start.LowPart,
partialData->u.Port.Length
));
//
// Save I/O resource information.
//
baseAddress->RangeStart = partialData->u.Port.Start;
baseAddress->RangeLength = partialData->u.Port.Length;
baseAddress->RangeInMemory = FALSE;
baseAddress->ResourceMapped = FALSE;
//
// Bump up the count of memory and I/O resources.
//
rangeCount++;
//
// Point to the next base address storage area.
//
baseAddress++;
}
break;
case CmResourceTypeInterrupt:
DebugPrint((3,
" Interrupt: Level = %x Vector = %x Mode = %x \n",
partialData->u.Interrupt.Level,
partialData->u.Interrupt.Vector,
partialData->Flags
));
//
// Save interrupt information.
//
DeviceExtension->InterruptLevel = partialData->u.Interrupt.Level;
DeviceExtension->InterruptVector = partialData->u.Interrupt.Vector;
//
// Check interrupt mode.
//
DeviceExtension->InterruptMode = LevelSensitive;
if (CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE != partialData->Flags) {
DeviceExtension->InterruptMode = Latched;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -