2396 lines
65 KiB
C
2396 lines
65 KiB
C
/*++
|
||
|
||
Copyright (c) 1992-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
registry.c
|
||
|
||
Abstract:
|
||
|
||
Registry support for the video port driver.
|
||
|
||
Author:
|
||
|
||
Andre Vachon (andreva) 01-Mar-1992
|
||
|
||
Environment:
|
||
|
||
kernel mode only
|
||
|
||
Notes:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "videoprt.h"
|
||
|
||
|
||
//
|
||
// Local routines.
|
||
//
|
||
|
||
BOOLEAN
|
||
CheckIoEnabled(
|
||
PVOID HwDeviceExtension,
|
||
ULONG NumAccessRanges,
|
||
PVIDEO_ACCESS_RANGE AccessRanges
|
||
);
|
||
|
||
ULONG
|
||
GetCmResourceListSize(
|
||
PCM_RESOURCE_LIST CmResourceList
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,VpGetFlags)
|
||
#pragma alloc_text(PAGE,pOverrideConflict)
|
||
#pragma alloc_text(PAGE,VideoPortGetAccessRanges)
|
||
#pragma alloc_text(PAGE,pVideoPortReportResourceList)
|
||
#pragma alloc_text(PAGE,VideoPortVerifyAccessRanges)
|
||
#pragma alloc_text(PAGE,CheckIoEnabled)
|
||
#pragma alloc_text(PAGE,VpReleaseResources)
|
||
#pragma alloc_text(PAGE,VpIsResourceInList)
|
||
#pragma alloc_text(PAGE,VpAppendToRequirementsList)
|
||
#pragma alloc_text(PAGE,VpIsLegacyAccessRange)
|
||
#pragma alloc_text(PAGE,GetCmResourceListSize)
|
||
#pragma alloc_text(PAGE,VpRemoveFromResourceList)
|
||
#pragma alloc_text(PAGE,VpTranslateResource)
|
||
#pragma alloc_text(PAGE,VpIsVgaResource)
|
||
#endif
|
||
|
||
NTSTATUS
|
||
VpGetFlags(
|
||
PUNICODE_STRING RegistryPath,
|
||
PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
|
||
PULONG Flags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks for the existance of the PnP key/value in the device's
|
||
registry path.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the flag exists, FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PWSTR Path;
|
||
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
|
||
ULONG pnpEnabled = 0;
|
||
ULONG legacyDetect = 0;
|
||
ULONG defaultValue = 0;
|
||
ULONG bootDriver = 0;
|
||
ULONG reportDevice = 0;
|
||
PWSTR Table[] = {L"\\Vga", L"\\VgaSave", NULL};
|
||
PWSTR SubStr, *Item = Table;
|
||
ULONG Len;
|
||
|
||
|
||
RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
|
||
{NULL, RTL_QUERY_REGISTRY_DIRECT, L"LegacyDetect",
|
||
&legacyDetect, REG_DWORD, &defaultValue, 4},
|
||
{NULL, RTL_QUERY_REGISTRY_DIRECT, L"BootDriver",
|
||
&bootDriver, REG_DWORD, &defaultValue, 4},
|
||
{NULL, RTL_QUERY_REGISTRY_DIRECT, L"ReportDevice",
|
||
&reportDevice, REG_DWORD, &defaultValue, 4},
|
||
{NULL, 0, NULL}
|
||
};
|
||
|
||
*Flags = 0;
|
||
|
||
Path = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
|
||
RegistryPath->Length + sizeof(UNICODE_NULL),
|
||
VP_TAG);
|
||
|
||
if (Path)
|
||
{
|
||
RtlCopyMemory(Path,
|
||
RegistryPath->Buffer,
|
||
RegistryPath->Length);
|
||
|
||
*(Path + (RegistryPath->Length / sizeof(UNICODE_NULL))) = UNICODE_NULL;
|
||
|
||
pVideoDebugPrint((1, "PnP path: %ws\n", Path));
|
||
|
||
RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
||
Path,
|
||
&QueryTable[0],
|
||
NULL,
|
||
NULL);
|
||
|
||
//
|
||
// If the PnP Entry points are present, then we will treat this
|
||
// driver as a PnP driver.
|
||
//
|
||
|
||
if ( (HwInitializationData->HwInitDataSize >=
|
||
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwQueryInterface)) &&
|
||
(HwInitializationData->HwSetPowerState != NULL) &&
|
||
(HwInitializationData->HwGetPowerState != NULL) &&
|
||
(HwInitializationData->HwGetVideoChildDescriptor != NULL) )
|
||
{
|
||
pVideoDebugPrint((1, "videoprt: The miniport is a PnP miniport."));
|
||
|
||
pnpEnabled = TRUE;
|
||
}
|
||
|
||
//
|
||
// REPORT_DEVICE is only valid if PNP_ENABLED is true.
|
||
//
|
||
// We don't want to report a device to the PnP system if
|
||
// we don't have a PnP driver.
|
||
//
|
||
|
||
if (!pnpEnabled)
|
||
{
|
||
reportDevice = 0;
|
||
}
|
||
|
||
*Flags = (pnpEnabled ? PNP_ENABLED : 0) |
|
||
(legacyDetect ? LEGACY_DETECT : 0) |
|
||
(bootDriver ? BOOT_DRIVER : 0) |
|
||
(reportDevice ? REPORT_DEVICE : 0);
|
||
|
||
//
|
||
// Free the memory we allocated above.
|
||
//
|
||
|
||
ExFreePool(Path);
|
||
|
||
|
||
//
|
||
// Determine if the current miniport is the VGA miniport.
|
||
//
|
||
|
||
while (*Item) {
|
||
|
||
Len = wcslen(*Item);
|
||
|
||
SubStr = RegistryPath->Buffer + (RegistryPath->Length / 2) - Len;
|
||
|
||
if (!_wcsnicmp(SubStr, *Item, Len)) {
|
||
|
||
pVideoDebugPrint((1, "This IS the vga miniport\n"));
|
||
*Flags |= VGA_DRIVER;
|
||
break;
|
||
}
|
||
|
||
Item++;
|
||
}
|
||
|
||
pVideoDebugPrint((1, "Flags = %d\n", *Flags));
|
||
|
||
ntStatus = STATUS_SUCCESS;
|
||
}
|
||
|
||
return ntStatus;
|
||
}
|
||
|
||
BOOLEAN
|
||
IsMirrorDriver(
|
||
PFDO_EXTENSION fdoExtension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks if the driver is a mirror onr or not.
|
||
This function may be called ONLY after DriverRegistryPath was initialized.
|
||
That is, after VideoPortFindAdapter2 or VideoPortCreateSecondaryDisplay
|
||
were called.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the driver is a mirror one, FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG MirrorDriver = 0;
|
||
|
||
ASSERT ((fdoExtension != NULL) && IS_FDO(fdoExtension));
|
||
|
||
VideoPortGetRegistryParameters(fdoExtension->HwDeviceExtension,
|
||
L"MirrorDriver",
|
||
FALSE,
|
||
VpRegistryCallback,
|
||
&MirrorDriver);
|
||
|
||
return (MirrorDriver != 0);
|
||
}
|
||
|
||
BOOLEAN
|
||
pOverrideConflict(
|
||
PFDO_EXTENSION FdoExtension,
|
||
BOOLEAN bSetResources
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine if the port driver should override the conflict in the registry.
|
||
|
||
bSetResources determines if the routine is checking the state for setting
|
||
the resources in the registry, or for cleaning them.
|
||
|
||
For example, if we are running basevideo and there is a conflict with the
|
||
vga, we want to override the conflict, but not clear the contents of
|
||
the registry.
|
||
|
||
Return Value:
|
||
|
||
TRUE if it should, FALSE if it should not.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UNICODE_STRING unicodeString;
|
||
|
||
//
|
||
// Drivers being detected should not generate a conflict in the eventlog.
|
||
//
|
||
|
||
if (FdoExtension->Flags & LEGACY_DETECT)
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// \Driver\Vga is for backwards compatibility since we do not have it
|
||
// anymore. It has become \Driver\VgaSave.
|
||
//
|
||
|
||
RtlInitUnicodeString(&unicodeString, L"\\Driver\\Vga");
|
||
|
||
if (!RtlCompareUnicodeString(&(FdoExtension->FunctionalDeviceObject->DriverObject->DriverName),
|
||
&unicodeString,
|
||
TRUE)) {
|
||
|
||
//
|
||
// Strings were equal - return SUCCESS
|
||
//
|
||
|
||
pVideoDebugPrint((1, "pOverrideConflict: found Vga string\n"));
|
||
|
||
return TRUE;
|
||
|
||
} else {
|
||
|
||
RtlInitUnicodeString(&unicodeString, L"\\Driver\\VgaSave");
|
||
|
||
if (!RtlCompareUnicodeString(&(FdoExtension->FunctionalDeviceObject->DriverObject->DriverName),
|
||
&unicodeString,
|
||
TRUE)) {
|
||
//
|
||
// Return TRUE if we are just checking for confict (never want this
|
||
// driver to generate a conflict).
|
||
// We want to return TRUE only if we are not in basevideo since we
|
||
// only want to clear the resources if we are NOT in basevideo
|
||
// we are clearing the resources.
|
||
//
|
||
|
||
|
||
pVideoDebugPrint((1, "pOverrideConflict: found VgaSave string. Returning %d\n",
|
||
bSetResources));
|
||
|
||
return (bSetResources || (!VpBaseVideo));
|
||
|
||
|
||
} else {
|
||
|
||
//
|
||
// We failed all checks, so we will report a conflict
|
||
//
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
} // end pOverrideConflict()
|
||
|
||
BOOLEAN
|
||
CheckResourceList(
|
||
ULONG BusNumber,
|
||
ULONG Slot
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine remembers which bus numbers and slot numbers we've handed
|
||
out resources for. This will prevent us from handing out resources
|
||
to a legacy driver trying to control a device which a PnP driver
|
||
is already controlling.
|
||
|
||
Arguments:
|
||
|
||
BusNumber - The bus number on which the device resides.
|
||
|
||
Slot - The slot/function number of the device on the bus.
|
||
|
||
Returns:
|
||
|
||
TRUE if resources have already been handed out for the device,
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_ADDRESS DeviceAddress;
|
||
|
||
DeviceAddress = gDeviceAddressList;
|
||
|
||
while (DeviceAddress) {
|
||
|
||
if ((DeviceAddress->BusNumber == BusNumber) &&
|
||
(DeviceAddress->Slot == Slot)) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
DeviceAddress = DeviceAddress->Next;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
VOID
|
||
AddToResourceList(
|
||
ULONG BusNumber,
|
||
ULONG Slot
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks to see if resources have already been handed
|
||
out for the device on the given bus/slot.
|
||
|
||
Arguments:
|
||
|
||
BusNumber - The bus number on which the device resides.
|
||
|
||
Slot - The slot/function number of the device on the bus.
|
||
|
||
Returns:
|
||
|
||
none
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_ADDRESS DeviceAddress;
|
||
|
||
DeviceAddress = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
|
||
sizeof(DEVICE_ADDRESS),
|
||
VP_TAG);
|
||
|
||
if (DeviceAddress) {
|
||
|
||
DeviceAddress->BusNumber = BusNumber;
|
||
DeviceAddress->Slot = Slot;
|
||
|
||
DeviceAddress->Next = gDeviceAddressList;
|
||
gDeviceAddressList = DeviceAddress;
|
||
}
|
||
}
|
||
|
||
|
||
VIDEOPORT_API
|
||
VP_STATUS
|
||
VideoPortGetAccessRanges(
|
||
PVOID HwDeviceExtension,
|
||
ULONG NumRequestedResources,
|
||
PIO_RESOURCE_DESCRIPTOR RequestedResources OPTIONAL,
|
||
ULONG NumAccessRanges,
|
||
PVIDEO_ACCESS_RANGE AccessRanges,
|
||
PVOID VendorId,
|
||
PVOID DeviceId,
|
||
PULONG Slot
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Walk the appropriate bus to get device information.
|
||
Search for the appropriate device ID.
|
||
Appropriate resources will be returned and automatically stored in the
|
||
resourcemap.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - Points to the miniport driver's device extension.
|
||
|
||
NumRequestedResources - Number of entries in the RequestedResources array.
|
||
|
||
RequestedResources - Optional pointer to an array ofRequestedResources
|
||
the miniport driver wants to access.
|
||
|
||
NumAccessRanges - Maximum number of access ranges that can be returned
|
||
by the function.
|
||
|
||
AccessRanges - Array of access ranges that will be returned to the driver.
|
||
|
||
VendorId - Pointer to the vendor ID. On PCI, this is a pointer to a 16 bit
|
||
word.
|
||
|
||
DeviceId - Pointer to the Device ID. On PCI, this is a pointer to a 16 bit
|
||
word.
|
||
|
||
Slot - Pointer to the starting slot number for this search.
|
||
|
||
Return Value:
|
||
|
||
ERROR_MORE_DATA if the AccessRange structure is not large enough for the
|
||
PCI config info.
|
||
ERROR_DEV_NOT_EXIST is the card is not found.
|
||
|
||
NO_ERROR if the function succeded.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension;
|
||
PFDO_EXTENSION fdoExtension;
|
||
|
||
UNICODE_STRING unicodeString;
|
||
ULONG i;
|
||
ULONG j;
|
||
|
||
PCM_RESOURCE_LIST cmResourceList;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmResourceDescriptor;
|
||
|
||
|
||
VP_STATUS status;
|
||
UCHAR bShare;
|
||
|
||
PPCI_SLOT_NUMBER slotData = (PPCI_SLOT_NUMBER)Slot;
|
||
|
||
|
||
DoSpecificExtension = GET_DSP_EXT(HwDeviceExtension);
|
||
fdoExtension = DoSpecificExtension->pFdoExtension;
|
||
|
||
// Hack Add extra R so the Device0 key does not get created as volatile
|
||
// a mess up the subsequent driver install.
|
||
|
||
*(LPWSTR) (((PUCHAR)DoSpecificExtension->DriverRegistryPath) +
|
||
DoSpecificExtension->DriverRegistryPathLength) = L'R';
|
||
|
||
RtlInitUnicodeString(&unicodeString, DoSpecificExtension->DriverRegistryPath);
|
||
|
||
//
|
||
// Assert drivers do set those parameters properly
|
||
//
|
||
|
||
#if DBG
|
||
|
||
if ((NumRequestedResources == 0) != (RequestedResources == NULL)) {
|
||
|
||
pVideoDebugPrint((0, "VideoPortGetDeviceResources: Parameters for requested resource are inconsistent\n"));
|
||
|
||
}
|
||
|
||
#endif
|
||
|
||
//
|
||
// An empty requested resource list means we want to automatic behavoir.
|
||
// Just call the HAL to get all the information
|
||
//
|
||
|
||
if (NumRequestedResources == 0) {
|
||
|
||
if ((fdoExtension->Flags & LEGACY_DRIVER) != LEGACY_DRIVER) {
|
||
|
||
//
|
||
// If a PnP driver is requesting resources, then return what the
|
||
// system passed in to us.
|
||
//
|
||
|
||
cmResourceList = fdoExtension->AllocatedResources;
|
||
|
||
//
|
||
// Return the slot number to the device.
|
||
//
|
||
|
||
if (Slot) {
|
||
*Slot = fdoExtension->SlotNumber;
|
||
}
|
||
|
||
if (cmResourceList) {
|
||
#if DBG
|
||
DumpResourceList(cmResourceList);
|
||
#endif
|
||
status = NO_ERROR;
|
||
|
||
} else {
|
||
|
||
//
|
||
// The system should always pass us resources.
|
||
//
|
||
|
||
ASSERT(FALSE);
|
||
status = ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
} else {
|
||
|
||
#if defined(NO_LEGACY_DRIVERS)
|
||
pVideoDebugPrint((0, "VideoPortGetDeviceResources: Sorry, no legacy device support.\n"));
|
||
status = ERROR_INVALID_PARAMETER;
|
||
#else
|
||
|
||
//
|
||
// An empty requested resource list means we want to automatic behavoir.
|
||
// Just call the HAL to get all the information
|
||
//
|
||
|
||
PCI_COMMON_CONFIG pciBuffer;
|
||
PPCI_COMMON_CONFIG pciData;
|
||
|
||
//
|
||
//
|
||
// typedef struct _PCI_SLOT_NUMBER {
|
||
// union {
|
||
// struct {
|
||
// ULONG DeviceNumber:5;
|
||
// ULONG FunctionNumber:3;
|
||
// ULONG Reserved:24;
|
||
// } bits;
|
||
// ULONG AsULONG;
|
||
// } u;
|
||
// } PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
|
||
//
|
||
|
||
pciData = (PPCI_COMMON_CONFIG)&pciBuffer;
|
||
|
||
//
|
||
// Only PCI is supported for automatic querying
|
||
//
|
||
|
||
if (fdoExtension->AdapterInterfaceType == PCIBus) {
|
||
|
||
status = ERROR_DEV_NOT_EXIST;
|
||
|
||
//
|
||
// Look on each slot
|
||
//
|
||
|
||
do
|
||
{
|
||
//
|
||
// Look at each function.
|
||
//
|
||
|
||
do
|
||
{
|
||
if (HalGetBusData(PCIConfiguration,
|
||
fdoExtension->SystemIoBusNumber,
|
||
slotData->u.AsULONG,
|
||
pciData,
|
||
PCI_COMMON_HDR_LENGTH) == 0) {
|
||
|
||
//
|
||
// Out of functions. Go to next PCI bus.
|
||
//
|
||
|
||
continue;
|
||
|
||
}
|
||
|
||
if (pciData->VendorID != *((PUSHORT)VendorId) ||
|
||
pciData->DeviceID != *((PUSHORT)DeviceId)) {
|
||
|
||
//
|
||
// Not our PCI device. Try next device/function
|
||
//
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Check to see if resources have already been
|
||
// assigned for this bus/slot.
|
||
//
|
||
|
||
if (CheckResourceList(fdoExtension->SystemIoBusNumber,
|
||
slotData->u.AsULONG) == FALSE)
|
||
{
|
||
if (NT_SUCCESS(HalAssignSlotResources(&unicodeString,
|
||
&VideoClassName,
|
||
fdoExtension->FunctionalDeviceObject->DriverObject,
|
||
fdoExtension->FunctionalDeviceObject,
|
||
PCIBus,
|
||
fdoExtension->SystemIoBusNumber,
|
||
slotData->u.AsULONG,
|
||
&cmResourceList))) {
|
||
|
||
status = NO_ERROR;
|
||
|
||
AddToResourceList(fdoExtension->SystemIoBusNumber,
|
||
slotData->u.AsULONG);
|
||
|
||
break;
|
||
|
||
} else {
|
||
|
||
//
|
||
// ToDo: Log this error.
|
||
//
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Resources already assigned for this device.
|
||
//
|
||
|
||
pVideoDebugPrint((0, "VIDEOPRT: Another driver is already "
|
||
"controlling this device.\n"));
|
||
ASSERT(FALSE);
|
||
|
||
status = ERROR_DEV_NOT_EXIST;
|
||
}
|
||
|
||
} while (++slotData->u.bits.FunctionNumber != 0);
|
||
|
||
//
|
||
// break if we found the device already.
|
||
//
|
||
|
||
if (status != ERROR_DEV_NOT_EXIST) {
|
||
|
||
break;
|
||
}
|
||
|
||
} while (++slotData->u.bits.DeviceNumber != 0);
|
||
|
||
} else {
|
||
|
||
//
|
||
// This is not a supported bus type.
|
||
//
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
|
||
}
|
||
#endif // NO_LEGACY_DRIVERS
|
||
}
|
||
|
||
} else {
|
||
|
||
PIO_RESOURCE_REQUIREMENTS_LIST requestedResources;
|
||
ULONG requestedResourceSize;
|
||
NTSTATUS ntStatus;
|
||
|
||
status = NO_ERROR;
|
||
|
||
//
|
||
// The caller has specified some resources.
|
||
// Lets call IoAssignResources with that and see what comes back.
|
||
//
|
||
|
||
requestedResourceSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
|
||
((NumRequestedResources - 1) *
|
||
sizeof(IO_RESOURCE_DESCRIPTOR));
|
||
|
||
requestedResources = ExAllocatePoolWithTag(PagedPool,
|
||
requestedResourceSize,
|
||
VP_TAG);
|
||
|
||
if (requestedResources) {
|
||
|
||
RtlZeroMemory(requestedResources, requestedResourceSize);
|
||
|
||
requestedResources->ListSize = requestedResourceSize;
|
||
requestedResources->InterfaceType = fdoExtension->AdapterInterfaceType;
|
||
requestedResources->BusNumber = fdoExtension->SystemIoBusNumber;
|
||
requestedResources->SlotNumber = slotData->u.bits.DeviceNumber;
|
||
requestedResources->AlternativeLists = 1;
|
||
|
||
requestedResources->List[0].Version = 1;
|
||
requestedResources->List[0].Revision = 1;
|
||
requestedResources->List[0].Count = NumRequestedResources;
|
||
|
||
RtlMoveMemory(&(requestedResources->List[0].Descriptors[0]),
|
||
RequestedResources,
|
||
NumRequestedResources * sizeof(IO_RESOURCE_DESCRIPTOR));
|
||
|
||
ntStatus = IoAssignResources(&unicodeString,
|
||
&VideoClassName,
|
||
fdoExtension->FunctionalDeviceObject->DriverObject,
|
||
fdoExtension->FunctionalDeviceObject,
|
||
requestedResources,
|
||
&cmResourceList);
|
||
|
||
ExFreePool(requestedResources);
|
||
|
||
if (!NT_SUCCESS(ntStatus)) {
|
||
|
||
status = ERROR_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (status == NO_ERROR) {
|
||
|
||
VIDEO_ACCESS_RANGE TempRange;
|
||
|
||
//
|
||
// We now have a valid cmResourceList.
|
||
// Lets translate it back to access ranges so the driver
|
||
// only has to deal with one type of list.
|
||
//
|
||
|
||
//
|
||
// NOTE: The resources have already been reported at this point in
|
||
// time.
|
||
//
|
||
|
||
//
|
||
// Walk resource list to update configuration information.
|
||
//
|
||
|
||
for (i = 0, j = 0;
|
||
(i < cmResourceList->List->PartialResourceList.Count) &&
|
||
(status == NO_ERROR);
|
||
i++) {
|
||
|
||
//
|
||
// Get resource descriptor.
|
||
//
|
||
|
||
cmResourceDescriptor =
|
||
&cmResourceList->List->PartialResourceList.PartialDescriptors[i];
|
||
|
||
//
|
||
// Get the share disposition
|
||
//
|
||
|
||
if (cmResourceDescriptor->ShareDisposition == CmResourceShareShared) {
|
||
|
||
bShare = 1;
|
||
|
||
} else {
|
||
|
||
bShare = 0;
|
||
|
||
}
|
||
|
||
switch (cmResourceDescriptor->Type) {
|
||
|
||
case CmResourceTypePort:
|
||
case CmResourceTypeMemory:
|
||
|
||
//
|
||
// common part
|
||
//
|
||
|
||
TempRange.RangeLength =
|
||
cmResourceDescriptor->u.Memory.Length;
|
||
TempRange.RangeStart =
|
||
cmResourceDescriptor->u.Memory.Start;
|
||
TempRange.RangeVisible = 0;
|
||
TempRange.RangeShareable = bShare;
|
||
TempRange.RangePassive = 0;
|
||
|
||
//
|
||
// separate part
|
||
//
|
||
|
||
if (cmResourceDescriptor->Type == CmResourceTypePort) {
|
||
TempRange.RangeInIoSpace = 1;
|
||
} else {
|
||
TempRange.RangeInIoSpace = 0;
|
||
}
|
||
|
||
//
|
||
// See if we need to return the resource to the driver.
|
||
//
|
||
|
||
if (!VpIsLegacyAccessRange(fdoExtension, &TempRange)) {
|
||
|
||
if (j == NumAccessRanges) {
|
||
|
||
status = ERROR_MORE_DATA;
|
||
break;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Only modify the AccessRange array if we are writing
|
||
// valid data.
|
||
//
|
||
|
||
AccessRanges[j] = TempRange;
|
||
j++;
|
||
}
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
case CmResourceTypeInterrupt:
|
||
|
||
fdoExtension->MiniportConfigInfo->BusInterruptVector =
|
||
cmResourceDescriptor->u.Interrupt.Vector;
|
||
fdoExtension->MiniportConfigInfo->BusInterruptLevel =
|
||
cmResourceDescriptor->u.Interrupt.Level;
|
||
fdoExtension->MiniportConfigInfo->InterruptShareable =
|
||
bShare;
|
||
|
||
break;
|
||
|
||
case CmResourceTypeDma:
|
||
|
||
fdoExtension->MiniportConfigInfo->DmaChannel =
|
||
cmResourceDescriptor->u.Dma.Channel;
|
||
fdoExtension->MiniportConfigInfo->DmaPort =
|
||
cmResourceDescriptor->u.Dma.Port;
|
||
fdoExtension->MiniportConfigInfo->DmaShareable =
|
||
bShare;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
pVideoDebugPrint((1, "VideoPortGetAccessRanges: Unknown descriptor type %x\n",
|
||
cmResourceDescriptor->Type ));
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (fdoExtension->Flags & LEGACY_DRIVER) {
|
||
|
||
//
|
||
// Free the resource provided by the IO system.
|
||
//
|
||
|
||
ExFreePool(cmResourceList);
|
||
}
|
||
}
|
||
|
||
// Hack remove extra R
|
||
|
||
*(LPWSTR) (((PUCHAR)DoSpecificExtension->DriverRegistryPath) +
|
||
DoSpecificExtension->DriverRegistryPathLength) = UNICODE_NULL;
|
||
|
||
return status;
|
||
|
||
} // VideoPortGetDeviceResources()
|
||
|
||
BOOLEAN
|
||
VpIsVgaResource(
|
||
PVIDEO_ACCESS_RANGE AccessRange
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Indicates whether the given access range is a vga access range.
|
||
|
||
Arguments:
|
||
|
||
AccessRange - The access range to examine.
|
||
|
||
Returns:
|
||
|
||
TRUE if it is a VGA access range,
|
||
FALSE otherwise.
|
||
|
||
Notes:
|
||
|
||
This routine does not take into account the length of the access range.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (AccessRange->RangeInIoSpace) {
|
||
|
||
ULONGLONG Port = AccessRange->RangeStart.QuadPart;
|
||
|
||
if (((Port >= 0x3b0) && (Port <= 0x3bb)) ||
|
||
((Port >= 0x3c0) && (Port <= 0x3df))) {
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
if (AccessRange->RangeStart.QuadPart == 0xa0000) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
BOOLEAN
|
||
VpTranslateResource(
|
||
IN PFDO_EXTENSION fdoExtension,
|
||
IN OUT PULONG InIoSpace,
|
||
IN PPHYSICAL_ADDRESS PhysicalAddress,
|
||
OUT PPHYSICAL_ADDRESS TranslatedAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine ensures that we do not report any PnP assigned
|
||
resources back to the system.
|
||
|
||
Arguments:
|
||
|
||
fdoExtension - The device extension for the device.
|
||
|
||
PhysicalAddress - The physical address that needs to be translated
|
||
|
||
TranslatedAddress - The location in which to store the translated address.
|
||
Return Value:
|
||
|
||
TRUE if the resource was translated
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCM_FULL_RESOURCE_DESCRIPTOR pcmFullRaw;
|
||
PCM_PARTIAL_RESOURCE_LIST pcmPartialRaw;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR pcmDescriptRaw;
|
||
|
||
PCM_FULL_RESOURCE_DESCRIPTOR pcmFullTranslated;
|
||
PCM_PARTIAL_RESOURCE_LIST pcmPartialTranslated;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR pcmDescriptTranslated;
|
||
|
||
ULONG i, j;
|
||
BOOLEAN IoAddress = (BOOLEAN)(*InIoSpace & VIDEO_MEMORY_SPACE_IO);
|
||
|
||
pcmFullRaw = fdoExtension->RawResources->List;
|
||
pcmFullTranslated = fdoExtension->TranslatedResources->List;
|
||
|
||
for (i = 0; i < fdoExtension->RawResources->Count; i++) {
|
||
|
||
pcmPartialRaw = &(pcmFullRaw->PartialResourceList);
|
||
pcmDescriptRaw = pcmPartialRaw->PartialDescriptors;
|
||
|
||
pcmPartialTranslated = &(pcmFullTranslated->PartialResourceList);
|
||
pcmDescriptTranslated = pcmPartialTranslated->PartialDescriptors;
|
||
|
||
for (j = 0; j < pcmPartialRaw->Count; j++) {
|
||
|
||
if ((pcmDescriptRaw->Type == CmResourceTypeMemory) &&
|
||
(pcmDescriptRaw->u.Memory.Start.QuadPart == PhysicalAddress->QuadPart) &&
|
||
(IoAddress == FALSE)) {
|
||
|
||
*TranslatedAddress =
|
||
pcmDescriptTranslated->u.Memory.Start;
|
||
|
||
if ((pcmDescriptTranslated->Type == CmResourceTypePort) &&
|
||
((*InIoSpace & 0x4) == 0))
|
||
{
|
||
*InIoSpace = VIDEO_MEMORY_SPACE_IO;
|
||
|
||
} else {
|
||
|
||
*InIoSpace = 0;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
if ((pcmDescriptRaw->Type == CmResourceTypePort) &&
|
||
(pcmDescriptRaw->u.Port.Start.QuadPart == PhysicalAddress->QuadPart) &&
|
||
(IoAddress == TRUE)) {
|
||
|
||
*TranslatedAddress =
|
||
pcmDescriptTranslated->u.Port.Start;
|
||
|
||
if ((pcmDescriptTranslated->Type == CmResourceTypePort) &&
|
||
((*InIoSpace & 0x4) == 0))
|
||
{
|
||
*InIoSpace = VIDEO_MEMORY_SPACE_IO;
|
||
|
||
} else {
|
||
|
||
*InIoSpace = 0;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
pcmDescriptRaw++;
|
||
pcmDescriptTranslated++;
|
||
}
|
||
|
||
pcmFullRaw = (PCM_FULL_RESOURCE_DESCRIPTOR) pcmDescriptRaw;
|
||
pcmFullTranslated = (PCM_FULL_RESOURCE_DESCRIPTOR) pcmDescriptTranslated;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
VpIsResourceInList(
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR pResource,
|
||
PCM_FULL_RESOURCE_DESCRIPTOR pFullResource,
|
||
PCM_RESOURCE_LIST removeList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine ensures that we do not report any PnP assigned
|
||
resources back to the system.
|
||
|
||
Arguments:
|
||
|
||
pResource - The resource which we are looking for in the removeList.
|
||
|
||
pFullResource - contains bus info about pResource.
|
||
|
||
removeList - Any resources in this list which appear in the
|
||
resourceList will be removed from the resourceList.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the resource is in the list,
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCM_FULL_RESOURCE_DESCRIPTOR pcmFull;
|
||
PCM_PARTIAL_RESOURCE_LIST pcmPartial;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR pcmDescript;
|
||
|
||
ULONG i, j;
|
||
|
||
if (!removeList) {
|
||
|
||
//
|
||
// If we have not list of resources to remove, then
|
||
// simply return.
|
||
//
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
pcmFull = &(removeList->List[0]);
|
||
|
||
for (i=0; i<removeList->Count; i++)
|
||
{
|
||
pcmPartial = &(pcmFull->PartialResourceList);
|
||
pcmDescript = &(pcmPartial->PartialDescriptors[0]);
|
||
|
||
for (j=0; j<pcmPartial->Count; j++)
|
||
{
|
||
if (pcmDescript->Type == pResource->Type) {
|
||
|
||
switch(pcmDescript->Type) {
|
||
case CmResourceTypeMemory:
|
||
case CmResourceTypePort:
|
||
|
||
if ((pResource->u.Memory.Start.LowPart >= pcmDescript->u.Memory.Start.LowPart) &&
|
||
((pResource->u.Memory.Start.LowPart + pResource->u.Memory.Length) <=
|
||
(pcmDescript->u.Memory.Start.LowPart + pcmDescript->u.Memory.Length))) {
|
||
|
||
//
|
||
// The resources passed in match one of the resources
|
||
// in the list.
|
||
//
|
||
|
||
return TRUE;
|
||
}
|
||
break;
|
||
|
||
case CmResourceTypeInterrupt:
|
||
|
||
//
|
||
// We don't want to report interrupts on the FDO.
|
||
//
|
||
|
||
return TRUE;
|
||
|
||
default:
|
||
|
||
if (!memcmp(&pcmDescript->u, &pResource->u, sizeof(pResource->u))) {
|
||
|
||
//
|
||
// The resources passed in match one of the resources
|
||
// in the list.
|
||
//
|
||
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
pcmDescript++;
|
||
}
|
||
|
||
pcmFull = (PCM_FULL_RESOURCE_DESCRIPTOR) pcmDescript;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
VOID
|
||
VpReleaseResources(
|
||
PFDO_EXTENSION FdoExtension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will release all resource claims for a given device object.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The device object for which to release resource claims.
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_OBJECT DeviceObject = FdoExtension->FunctionalDeviceObject;
|
||
ULONG_PTR emptyResourceList = 0;
|
||
BOOLEAN ignore;
|
||
|
||
pVideoDebugPrint((1, "videoprt: VpReleaseResources called.\n"));
|
||
|
||
if (FdoExtension->Flags & (LEGACY_DETECT | VGA_DETECT)) {
|
||
|
||
pVideoDebugPrint((2, "VideoPrt: VpReleaseResources LEGACY_DETECT\n"));
|
||
IoReportResourceForDetection(FdoExtension->FunctionalDeviceObject->DriverObject,
|
||
NULL,
|
||
0L,
|
||
DeviceObject,
|
||
(PCM_RESOURCE_LIST)&emptyResourceList,
|
||
sizeof (ULONG),
|
||
&ignore);
|
||
|
||
} else {
|
||
|
||
pVideoDebugPrint((2, "VideoPrt: VpReleaseResources non-LEGACY_DETECT\n"));
|
||
IoReportResourceUsage(&VideoClassName,
|
||
FdoExtension->FunctionalDeviceObject->DriverObject,
|
||
NULL,
|
||
0L,
|
||
DeviceObject,
|
||
(PCM_RESOURCE_LIST)&emptyResourceList,
|
||
sizeof(ULONG),
|
||
FALSE,
|
||
&ignore);
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
VpAppendToRequirementsList(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementList,
|
||
IN ULONG NumAccessRanges,
|
||
IN PVIDEO_ACCESS_RANGE AccessRanges
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Builds a IoResourceRequirementsList for a given set of access ranges.
|
||
|
||
Arguments:
|
||
|
||
ResourceList - Pointer to location of the requirments list. Modified
|
||
on completion to point to a new requirements list.
|
||
|
||
NumAccessRanges - Number of access ranges in list.
|
||
|
||
AccessRanges - List of resources.
|
||
|
||
|
||
Returns:
|
||
|
||
STATUS_SUCCESS if successful, otherwise a status code.
|
||
|
||
Notes:
|
||
|
||
This function free's the memory used by the original resource list,
|
||
and allocates a new buffer for the appended resources list.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_RESOURCE_REQUIREMENTS_LIST OriginalRequirementList = *RequirementList;
|
||
PIO_RESOURCE_DESCRIPTOR pioDescript;
|
||
ULONG RequirementListSize;
|
||
ULONG OriginalListSize;
|
||
ULONG RequirementCount;
|
||
ULONG i;
|
||
|
||
RequirementCount = OriginalRequirementList->List[0].Count;
|
||
OriginalListSize = OriginalRequirementList->ListSize;
|
||
|
||
RequirementListSize = OriginalListSize +
|
||
NumAccessRanges * sizeof(IO_RESOURCE_DESCRIPTOR);
|
||
|
||
*RequirementList =
|
||
(PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePoolWithTag(PagedPool,
|
||
RequirementListSize,
|
||
VP_TAG);
|
||
|
||
//
|
||
// Return NULL if the structure could not be allocated.
|
||
// Otherwise, fill it out.
|
||
//
|
||
|
||
if (*RequirementList == NULL) {
|
||
|
||
*RequirementList = OriginalRequirementList;
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Copy the original resource list into the new one.
|
||
//
|
||
|
||
memcpy(*RequirementList, OriginalRequirementList, OriginalListSize);
|
||
|
||
//
|
||
// Free the original list
|
||
//
|
||
|
||
ExFreePool(OriginalRequirementList);
|
||
|
||
//
|
||
// Point to first free entry in requirements list
|
||
//
|
||
|
||
pioDescript =
|
||
&((*RequirementList)->List[0].Descriptors[(*RequirementList)->List[0].Count]);
|
||
|
||
//
|
||
// For each entry in the access range, fill in an entry in the
|
||
// resource list
|
||
//
|
||
|
||
for (i = 0; i < NumAccessRanges; i++) {
|
||
|
||
//
|
||
// We will never claim 0xC0000.
|
||
//
|
||
|
||
if ((AccessRanges->RangeStart.LowPart == 0xC0000) &&
|
||
(AccessRanges->RangeInIoSpace == FALSE))
|
||
{
|
||
AccessRanges++;
|
||
continue;
|
||
}
|
||
|
||
if (AccessRanges->RangeLength == 0) {
|
||
|
||
AccessRanges++;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Watch to see if the VGA resources get added to the
|
||
// requirements list. If so set a flag so that we know
|
||
// we don't need to reclaim VGA resources in FindAdapter.
|
||
//
|
||
|
||
if (VpIsVgaResource(AccessRanges)) {
|
||
DeviceOwningVga = DeviceObject;
|
||
}
|
||
|
||
if (AccessRanges->RangeInIoSpace) {
|
||
pioDescript->Type = CmResourceTypePort;
|
||
pioDescript->Flags = CM_RESOURCE_PORT_IO;
|
||
|
||
//
|
||
// Disable 10_BIT_DECODE. This is causing problems for the
|
||
// PnP folks. If someone has bad hardware, we'll just
|
||
// require them to report all the passive port explicitly.
|
||
//
|
||
//if (VpIsVgaResource(AccessRanges)) {
|
||
//
|
||
// pioDescript->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
|
||
//}
|
||
|
||
} else {
|
||
|
||
pioDescript->Type = CmResourceTypeMemory;
|
||
pioDescript->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
|
||
}
|
||
|
||
if (AccessRanges->RangePassive & VIDEO_RANGE_PASSIVE_DECODE) {
|
||
pioDescript->Flags |= CM_RESOURCE_PORT_PASSIVE_DECODE;
|
||
}
|
||
|
||
if (AccessRanges->RangePassive & VIDEO_RANGE_10_BIT_DECODE) {
|
||
pioDescript->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
|
||
}
|
||
|
||
pioDescript->ShareDisposition =
|
||
(AccessRanges->RangeShareable ?
|
||
CmResourceShareShared :
|
||
CmResourceShareDeviceExclusive);
|
||
|
||
pioDescript->Option = IO_RESOURCE_PREFERRED;
|
||
pioDescript->u.Memory.MinimumAddress = AccessRanges->RangeStart;
|
||
pioDescript->u.Memory.MaximumAddress.QuadPart =
|
||
AccessRanges->RangeStart.QuadPart +
|
||
AccessRanges->RangeLength - 1;
|
||
pioDescript->u.Memory.Alignment = 1;
|
||
pioDescript->u.Memory.Length = AccessRanges->RangeLength;
|
||
|
||
pioDescript++;
|
||
AccessRanges++;
|
||
RequirementCount++;
|
||
}
|
||
|
||
//
|
||
// Update number of elements in list.
|
||
//
|
||
|
||
(*RequirementList)->List[0].Count = RequirementCount;
|
||
(*RequirementList)->ListSize = RequirementListSize;
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
pVideoPortReportResourceList(
|
||
PDEVICE_SPECIFIC_EXTENSION DoSpecificExtension,
|
||
ULONG NumAccessRanges,
|
||
PVIDEO_ACCESS_RANGE AccessRanges,
|
||
PBOOLEAN Conflict,
|
||
PDEVICE_OBJECT DeviceObject,
|
||
BOOLEAN ClaimUnlistedResources
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a resource list which is used to query or report resource usage
|
||
in the system
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to the miniport's driver device extension.
|
||
|
||
NumAccessRanges - Num of access ranges in the AccessRanges array.
|
||
|
||
AccessRanges - Pointer to an array of access ranges used by a miniport
|
||
driver.
|
||
|
||
Conflict - Determines whether or not a conflict occured.
|
||
|
||
DeviceObject - The device object to use when calling
|
||
IoReportResourceUsage.
|
||
|
||
ClaimUnlistedResources - If this flag is true, then the routine will
|
||
also claim resources such as interrupts and DMA channels.
|
||
|
||
Return Value:
|
||
|
||
Returns the final status of the operation
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION FdoExtension = DoSpecificExtension->pFdoExtension;
|
||
PCM_RESOURCE_LIST resourceList;
|
||
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDescriptor;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDescriptor;
|
||
ULONG listLength = 0;
|
||
ULONG size;
|
||
ULONG i;
|
||
ULONG Flags;
|
||
NTSTATUS ntStatus;
|
||
BOOLEAN overrideConflict;
|
||
|
||
#if DBG
|
||
PVIDEO_ACCESS_RANGE SaveAccessRanges=AccessRanges;
|
||
#endif
|
||
|
||
//
|
||
// Create a resource list based on the information in the access range.
|
||
// and the miniport config info.
|
||
//
|
||
|
||
listLength = NumAccessRanges;
|
||
|
||
//
|
||
// Determine if we have DMA and interrupt resources to report
|
||
//
|
||
|
||
if (FdoExtension->HwInterrupt &&
|
||
((FdoExtension->MiniportConfigInfo->BusInterruptLevel != 0) ||
|
||
(FdoExtension->MiniportConfigInfo->BusInterruptVector != 0)) ) {
|
||
|
||
listLength++;
|
||
}
|
||
|
||
if ((FdoExtension->MiniportConfigInfo->DmaChannel) &&
|
||
(FdoExtension->MiniportConfigInfo->DmaPort)) {
|
||
listLength++;
|
||
}
|
||
|
||
//
|
||
// Allocate upper bound.
|
||
//
|
||
|
||
resourceList = (PCM_RESOURCE_LIST)
|
||
ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
|
||
sizeof(CM_RESOURCE_LIST) * 2 +
|
||
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * listLength,
|
||
VP_TAG);
|
||
|
||
//
|
||
// Return NULL if the structure could not be allocated.
|
||
// Otherwise, fill it out.
|
||
//
|
||
|
||
if (!resourceList) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
} else {
|
||
|
||
size = sizeof(CM_RESOURCE_LIST) - sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
||
|
||
resourceList->Count = 1;
|
||
|
||
fullResourceDescriptor = &(resourceList->List[0]);
|
||
fullResourceDescriptor->InterfaceType = FdoExtension->AdapterInterfaceType;
|
||
fullResourceDescriptor->BusNumber = FdoExtension->SystemIoBusNumber;
|
||
fullResourceDescriptor->PartialResourceList.Version = 0;
|
||
fullResourceDescriptor->PartialResourceList.Revision = 0;
|
||
fullResourceDescriptor->PartialResourceList.Count = 0;
|
||
|
||
//
|
||
// For each entry in the access range, fill in an entry in the
|
||
// resource list
|
||
//
|
||
|
||
partialResourceDescriptor =
|
||
&(fullResourceDescriptor->PartialResourceList.PartialDescriptors[0]);
|
||
|
||
for (i = 0; i < NumAccessRanges; i++, AccessRanges++) {
|
||
|
||
//
|
||
// If someone tries to claim a range of length 0 skip it.
|
||
//
|
||
|
||
if (AccessRanges->RangeLength == 0) {
|
||
continue;
|
||
}
|
||
|
||
if (AccessRanges->RangeInIoSpace) {
|
||
|
||
//
|
||
// Fix up odd Matrox legacy resources.
|
||
//
|
||
|
||
if ((AccessRanges->RangeStart.QuadPart == 0xCF8) &&
|
||
!(FdoExtension->Flags & PNP_ENABLED)) {
|
||
continue;
|
||
}
|
||
|
||
partialResourceDescriptor->Type = CmResourceTypePort;
|
||
partialResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
|
||
|
||
//
|
||
// Check to see if the range should be marked as passive
|
||
// decode.
|
||
//
|
||
|
||
if (AccessRanges->RangePassive & VIDEO_RANGE_PASSIVE_DECODE) {
|
||
partialResourceDescriptor->Flags |=
|
||
CM_RESOURCE_PORT_PASSIVE_DECODE;
|
||
}
|
||
|
||
if (AccessRanges->RangePassive & VIDEO_RANGE_10_BIT_DECODE) {
|
||
partialResourceDescriptor->Flags |=
|
||
CM_RESOURCE_PORT_10_BIT_DECODE;
|
||
}
|
||
|
||
//
|
||
// If this is a 0x2E8 port with bit 14 on, and it is
|
||
// not 0xE2E8 then mark the port as passive decode.
|
||
//
|
||
|
||
if (((AccessRanges->RangeStart.QuadPart & 0x43FE) == 0x42E8) &&
|
||
((AccessRanges->RangeStart.QuadPart & 0xFFFC) != 0xE2E8)) {
|
||
|
||
pVideoDebugPrint((2, "Marking IO Port 0x%x as Passive Decode.\n",
|
||
AccessRanges->RangeStart.LowPart));
|
||
|
||
partialResourceDescriptor->Flags |=
|
||
CM_RESOURCE_PORT_PASSIVE_DECODE;
|
||
}
|
||
|
||
//
|
||
// ET4000 tries to claim this port but never touches it!
|
||
//
|
||
|
||
if ((AccessRanges->RangeStart.QuadPart & 0x217a) == 0x217a) {
|
||
|
||
pVideoDebugPrint((2, "Marking IO Port 0x%x as Passive Decode.\n",
|
||
AccessRanges->RangeStart.LowPart));
|
||
|
||
partialResourceDescriptor->Flags |=
|
||
CM_RESOURCE_PORT_PASSIVE_DECODE;
|
||
}
|
||
|
||
//
|
||
// If it is a VGA access range, mark it as 10-bit decode.
|
||
//
|
||
|
||
//
|
||
// Disable 10_BIT_DECODE. This is causing problems for the
|
||
// PnP folks. If someone has bad hardware, we'll just
|
||
// require them to report all the passive port explicitly.
|
||
//
|
||
//if (VpIsVgaResource(AccessRanges)) {
|
||
//
|
||
// partialResourceDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
|
||
//}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Fix up odd memory resources to let legacy Trident boot.
|
||
//
|
||
|
||
if (AccessRanges->RangeStart.LowPart == 0x70) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// The device doesn't actually decode 0xC0000 so we
|
||
// shouldn't report it as a resource.
|
||
//
|
||
|
||
if (AccessRanges->RangeStart.LowPart == 0xC0000) {
|
||
continue;
|
||
}
|
||
|
||
partialResourceDescriptor->Type = CmResourceTypeMemory;
|
||
partialResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
|
||
}
|
||
|
||
partialResourceDescriptor->ShareDisposition =
|
||
(AccessRanges->RangeShareable ?
|
||
CmResourceShareShared :
|
||
CmResourceShareDeviceExclusive);
|
||
|
||
partialResourceDescriptor->u.Memory.Start =
|
||
AccessRanges->RangeStart;
|
||
partialResourceDescriptor->u.Memory.Length =
|
||
AccessRanges->RangeLength;
|
||
|
||
//
|
||
// Increment the size for the new entry
|
||
//
|
||
|
||
if (!VpIsResourceInList(partialResourceDescriptor,
|
||
fullResourceDescriptor,
|
||
FdoExtension->RawResources))
|
||
{
|
||
//
|
||
// Only include this resource if it is not in the
|
||
// list of PnP allocated resources.
|
||
//
|
||
|
||
size += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
||
fullResourceDescriptor->PartialResourceList.Count += 1;
|
||
partialResourceDescriptor++;
|
||
|
||
}
|
||
}
|
||
|
||
if (ClaimUnlistedResources) {
|
||
|
||
//
|
||
// Fill in the entry for the interrupt if it was present.
|
||
//
|
||
|
||
if (FdoExtension->HwInterrupt &&
|
||
((FdoExtension->MiniportConfigInfo->BusInterruptLevel != 0) ||
|
||
(FdoExtension->MiniportConfigInfo->BusInterruptVector != 0)) ) {
|
||
|
||
partialResourceDescriptor->Type = CmResourceTypeInterrupt;
|
||
|
||
partialResourceDescriptor->ShareDisposition =
|
||
(FdoExtension->MiniportConfigInfo->InterruptShareable ?
|
||
CmResourceShareShared :
|
||
CmResourceShareDeviceExclusive);
|
||
|
||
partialResourceDescriptor->Flags = 0;
|
||
|
||
partialResourceDescriptor->u.Interrupt.Level =
|
||
FdoExtension->MiniportConfigInfo->BusInterruptLevel;
|
||
partialResourceDescriptor->u.Interrupt.Vector =
|
||
FdoExtension->MiniportConfigInfo->BusInterruptVector;
|
||
|
||
partialResourceDescriptor->u.Interrupt.Affinity = 0;
|
||
|
||
//
|
||
// Increment the size for the new entry
|
||
//
|
||
|
||
if (!VpIsResourceInList(partialResourceDescriptor,
|
||
fullResourceDescriptor,
|
||
FdoExtension->RawResources))
|
||
{
|
||
//
|
||
// Only include this resource if it is not in the
|
||
// list of PnP allocated resources.
|
||
//
|
||
|
||
size += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
||
fullResourceDescriptor->PartialResourceList.Count += 1;
|
||
partialResourceDescriptor++;
|
||
|
||
} else {
|
||
|
||
pVideoDebugPrint((1, "pVideoPortReportResourceList: "
|
||
"Not reporting PnP assigned resource.\n"));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Fill in the entry for the DMA channel.
|
||
//
|
||
|
||
if ((FdoExtension->MiniportConfigInfo->DmaChannel) &&
|
||
(FdoExtension->MiniportConfigInfo->DmaPort)) {
|
||
|
||
partialResourceDescriptor->Type = CmResourceTypeDma;
|
||
|
||
partialResourceDescriptor->ShareDisposition =
|
||
(FdoExtension->MiniportConfigInfo->DmaShareable ?
|
||
CmResourceShareShared :
|
||
CmResourceShareDeviceExclusive);
|
||
|
||
partialResourceDescriptor->Flags = 0;
|
||
|
||
partialResourceDescriptor->u.Dma.Channel =
|
||
FdoExtension->MiniportConfigInfo->DmaChannel;
|
||
partialResourceDescriptor->u.Dma.Port =
|
||
FdoExtension->MiniportConfigInfo->DmaPort;
|
||
|
||
partialResourceDescriptor->u.Dma.Reserved1 = 0;
|
||
|
||
//
|
||
// Increment the size for the new entry
|
||
//
|
||
|
||
if (!VpIsResourceInList(partialResourceDescriptor,
|
||
fullResourceDescriptor,
|
||
FdoExtension->RawResources))
|
||
{
|
||
//
|
||
// Only include this resource if it is not in the
|
||
// list of PnP allocated resources.
|
||
//
|
||
|
||
size += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
||
fullResourceDescriptor->PartialResourceList.Count += 1;
|
||
partialResourceDescriptor++;
|
||
|
||
} else {
|
||
|
||
pVideoDebugPrint((1, "pVideoPortReportResourceList: "
|
||
"Not reporting PnP assigned resource.\n"));
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Determine if the conflict should be overriden.
|
||
//
|
||
|
||
//
|
||
// If we are loading the VGA, do not generate an error if it conflicts
|
||
// with another driver.
|
||
//
|
||
|
||
|
||
overrideConflict = pOverrideConflict(FdoExtension, TRUE);
|
||
|
||
#if DBG
|
||
if (overrideConflict) {
|
||
|
||
pVideoDebugPrint((2, "We are checking the vga driver resources\n"));
|
||
|
||
} else {
|
||
|
||
pVideoDebugPrint((2, "We are NOT checking vga driver resources\n"));
|
||
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Report resources.
|
||
//
|
||
|
||
Flags = FdoExtension->Flags;
|
||
|
||
if (Flags & (LEGACY_DETECT | VGA_DETECT)) {
|
||
|
||
ntStatus = IoReportResourceForDetection(FdoExtension->FunctionalDeviceObject->DriverObject,
|
||
NULL,
|
||
0L,
|
||
DeviceObject,
|
||
resourceList,
|
||
size,
|
||
Conflict);
|
||
|
||
if ((NT_SUCCESS(ntStatus) == FALSE) && (Flags & VGA_DETECT)) {
|
||
|
||
//
|
||
// There are a few occacations where reporting resources
|
||
// for detection can fail when just calling IoReportResources
|
||
// would have succeeded. So, lets remove the VGA_DETECT
|
||
// flag and try detecting resources again below.
|
||
//
|
||
|
||
Flags &= ~VGA_DETECT;
|
||
}
|
||
|
||
}
|
||
|
||
if ((Flags & (LEGACY_DETECT | VGA_DETECT)) == 0) {
|
||
|
||
ntStatus = IoReportResourceUsage(&VideoClassName,
|
||
FdoExtension->FunctionalDeviceObject->DriverObject,
|
||
NULL,
|
||
0L,
|
||
DeviceObject,
|
||
resourceList,
|
||
size,
|
||
overrideConflict,
|
||
Conflict);
|
||
|
||
if (NT_SUCCESS(ntStatus)) {
|
||
|
||
//
|
||
// Make sure the Flags reflect the way we acquired
|
||
// resources.
|
||
//
|
||
|
||
FdoExtension->Flags = Flags;
|
||
|
||
pVideoDebugPrint((1, "Videoprt: Legacy resources claimed. "
|
||
"Power management may be disabled.\n"));
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
|
||
if (!NT_SUCCESS(ntStatus)) {
|
||
|
||
//
|
||
// We failed to get the resources we required. Dump
|
||
// the requested resources into the registry.
|
||
//
|
||
|
||
PUSHORT ValueData;
|
||
ULONG ValueLength;
|
||
PULONG pulData;
|
||
PWCHAR p;
|
||
ULONG listLength;
|
||
|
||
pVideoDebugPrint((1, "IoReportResourceList Failed:\n"));
|
||
|
||
for(listLength = 0; listLength < NumAccessRanges; ++listLength) {
|
||
|
||
pVideoDebugPrint((1, "Address: 0x%08x Length: 0x%08x I/O: %-5s Visible: %-5s Shared: %-5s\n",
|
||
SaveAccessRanges[listLength].RangeStart.LowPart,
|
||
SaveAccessRanges[listLength].RangeLength,
|
||
SaveAccessRanges[listLength].RangeInIoSpace ? "TRUE" : "FALSE",
|
||
SaveAccessRanges[listLength].RangeVisible ? "TRUE" : "FALSE",
|
||
SaveAccessRanges[listLength].RangeShareable ? "TRUE" : "FALSE"));
|
||
|
||
}
|
||
|
||
ValueLength = NumAccessRanges *
|
||
(sizeof(VIDEO_ACCESS_RANGE) * 2 + 4) *
|
||
sizeof(USHORT) +
|
||
sizeof(USHORT); // second NULL terminator for
|
||
// multi_sz
|
||
|
||
ValueData = ExAllocatePool(PagedPool,
|
||
ValueLength);
|
||
|
||
if (ValueData) {
|
||
|
||
ULONG i, k;
|
||
WCHAR HexDigit[] = {L"0123456789ABCDEF"};
|
||
|
||
//
|
||
// Convert the AccessRanges into Unicode.
|
||
//
|
||
|
||
p = (PWCHAR) ValueData;
|
||
pulData = (PULONG)SaveAccessRanges;
|
||
|
||
for (i=0; i<NumAccessRanges * 4; i++) {
|
||
|
||
for (k=0; k<8; k++) {
|
||
*p++ = HexDigit[0xf & (*pulData >> ((7-k) * 4))];
|
||
}
|
||
|
||
if ((i % 4) != 3) *p++ = (WCHAR) L' ';
|
||
else *p++ = UNICODE_NULL;
|
||
|
||
pulData++;
|
||
}
|
||
*p = UNICODE_NULL;
|
||
|
||
RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
|
||
DoSpecificExtension->DriverRegistryPath,
|
||
L"RequestedResources",
|
||
REG_MULTI_SZ,
|
||
ValueData,
|
||
ValueLength);
|
||
|
||
ExFreePool(ValueData);
|
||
}
|
||
|
||
}
|
||
|
||
#endif
|
||
if (FdoExtension->ResourceList) {
|
||
|
||
ExFreePool(FdoExtension->ResourceList);
|
||
|
||
}
|
||
|
||
FdoExtension->ResourceList = resourceList;
|
||
|
||
//
|
||
// This is for hive compatibility back when we have the VGA driver
|
||
// as opposed to VgaSave.
|
||
// The Vga also cleans up the resource automatically.
|
||
//
|
||
|
||
//
|
||
// If we tried to override the conflict, let's take a look a what
|
||
// we want to do with the result
|
||
//
|
||
|
||
if ((NT_SUCCESS(ntStatus)) &&
|
||
overrideConflict &&
|
||
*Conflict) {
|
||
|
||
//
|
||
// For cases like Detection, a conflict is bad and we do
|
||
// want to fail.
|
||
//
|
||
// In the case of Basevideo, a conflict is possible. But we still
|
||
// want to load the VGA anyways. Return success and reset the
|
||
// conflict flag !
|
||
//
|
||
// pOverrideConflict with the FALSE flag will check that.
|
||
//
|
||
|
||
if (pOverrideConflict(FdoExtension, FALSE)) {
|
||
|
||
VpReleaseResources(FdoExtension);
|
||
|
||
ntStatus = STATUS_CONFLICTING_ADDRESSES;
|
||
|
||
} else {
|
||
|
||
*Conflict = FALSE;
|
||
|
||
ntStatus = STATUS_SUCCESS;
|
||
|
||
}
|
||
}
|
||
|
||
return ntStatus;
|
||
}
|
||
|
||
} // end pVideoPortBuildResourceList()
|
||
|
||
|
||
VP_STATUS
|
||
VideoPortVerifyAccessRanges(
|
||
PVOID HwDeviceExtension,
|
||
ULONG NumAccessRanges,
|
||
PVIDEO_ACCESS_RANGE AccessRanges
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
VideoPortVerifyAccessRanges
|
||
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - Points to the miniport driver's device extension.
|
||
|
||
NumAccessRanges - Number of entries in the AccessRanges array.
|
||
|
||
AccessRanges - Pointer to an array of AccessRanges the miniport driver
|
||
wants to access.
|
||
|
||
Return Value:
|
||
|
||
ERROR_INVALID_PARAMETER in an error occured
|
||
NO_ERROR if the call completed successfully
|
||
|
||
Environment:
|
||
|
||
This routine cannot be called from a miniport routine synchronized with
|
||
VideoPortSynchronizeRoutine or from an ISR.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
BOOLEAN conflict;
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
//
|
||
// According to the DDK docs, you can free all your resources by
|
||
// calling VideoPortVerifyAccessRanges with NumAccessRanges = 0.
|
||
//
|
||
|
||
if (NumAccessRanges == 0) {
|
||
VpReleaseResources(fdoExtension);
|
||
}
|
||
|
||
//
|
||
// If the device is not enabled then we won't allow the miniport
|
||
// to claim resources for it.
|
||
//
|
||
|
||
if (!CheckIoEnabled(
|
||
HwDeviceExtension,
|
||
NumAccessRanges,
|
||
AccessRanges)) {
|
||
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// All resources not passed in during the START_DEVICE irp should
|
||
// be claimed on the FDO. We will strip out the PDO resources
|
||
// in pVideoPortReportResourceList if the miniport driver tries
|
||
// to verify ranges acquired through VideoPortGetAccessRanges.
|
||
//
|
||
|
||
status = pVideoPortReportResourceList(
|
||
GET_DSP_EXT(HwDeviceExtension),
|
||
NumAccessRanges,
|
||
AccessRanges,
|
||
&conflict,
|
||
fdoExtension->FunctionalDeviceObject,
|
||
TRUE
|
||
);
|
||
|
||
//
|
||
// If we're upgrading, don't worry if the VGA driver can't get the
|
||
// resources. Some older legacy driver may be loaded that consumes
|
||
// those resources.
|
||
//
|
||
|
||
if ((VpSetupType == SETUPTYPE_UPGRADE) &&
|
||
(fdoExtension->Flags & VGA_DRIVER) )
|
||
{
|
||
status = STATUS_SUCCESS;
|
||
conflict = 0;
|
||
}
|
||
|
||
|
||
if ((NT_SUCCESS(status)) && (!conflict)) {
|
||
|
||
//
|
||
// Track the resources owned by the VGA driver.
|
||
//
|
||
|
||
if (fdoExtension->Flags & VGA_DRIVER) {
|
||
|
||
if (VgaAccessRanges != AccessRanges) {
|
||
|
||
ULONG Size = NumAccessRanges * sizeof(VIDEO_ACCESS_RANGE);
|
||
|
||
if (VgaAccessRanges) {
|
||
ExFreePool(VgaAccessRanges);
|
||
VgaAccessRanges = NULL;
|
||
NumVgaAccessRanges = 0;
|
||
}
|
||
|
||
if (NumAccessRanges) {
|
||
VgaAccessRanges = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, Size, VP_TAG);
|
||
|
||
if (VgaAccessRanges) {
|
||
memcpy(VgaAccessRanges, AccessRanges, Size);
|
||
NumVgaAccessRanges = NumAccessRanges;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return NO_ERROR;
|
||
|
||
} else {
|
||
|
||
return ERROR_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
} // end VideoPortVerifyAccessRanges()
|
||
|
||
BOOLEAN
|
||
CheckIoEnabled(
|
||
PVOID HwDeviceExtension,
|
||
ULONG NumAccessRanges,
|
||
PVIDEO_ACCESS_RANGE AccessRanges
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine ensures that IO is actually enabled if claiming
|
||
IO ranges.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - Points to the miniport driver's device extension.
|
||
|
||
NumAccessRanges - Number of entries in the AccessRanges array.
|
||
|
||
AccessRanges - Pointer to an array of AccessRanges the miniport driver
|
||
wants to access.
|
||
|
||
Return Value:
|
||
|
||
TRUE if our IO access checks pass,
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
if (fdoExtension->Flags & LEGACY_DRIVER) {
|
||
|
||
//
|
||
// We will always return TRUE for legacy drivers.
|
||
//
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
if (fdoExtension->AdapterInterfaceType == PCIBus) {
|
||
|
||
//
|
||
// Check to see if there are any IO ranges in the
|
||
// list or resources.
|
||
//
|
||
|
||
ULONG i;
|
||
USHORT Command;
|
||
ULONG byteCount;
|
||
|
||
//
|
||
// Get the PCI Command register for this device.
|
||
//
|
||
|
||
byteCount = VideoPortGetBusData(
|
||
HwDeviceExtension,
|
||
PCIConfiguration,
|
||
0,
|
||
&Command,
|
||
FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
|
||
sizeof(USHORT));
|
||
|
||
//
|
||
// If the following test fails it means we couldn't get at
|
||
// the I/O bits in the config space. Assume that the I/O is
|
||
// on and proceed.
|
||
//
|
||
|
||
if (byteCount != sizeof (USHORT)) {
|
||
ASSERT(FALSE);
|
||
return TRUE;
|
||
}
|
||
|
||
for (i=0; i<NumAccessRanges; i++) {
|
||
|
||
if (AccessRanges[i].RangeInIoSpace) {
|
||
|
||
if (!(Command & PCI_ENABLE_IO_SPACE))
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
if (!(Command & PCI_ENABLE_MEMORY_SPACE))
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Non-pci devices will always decode IO operations.
|
||
//
|
||
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
VpIsLegacyAccessRange(
|
||
PFDO_EXTENSION fdoExtension,
|
||
PVIDEO_ACCESS_RANGE AccessRange
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This return determines whether a given access range is
|
||
included in the list of legacy access ranges.
|
||
|
||
Arguments:
|
||
|
||
fdoExtension - The FDO extension for the device using the access range.
|
||
|
||
AccessRange - The access range to look for in the resource list.
|
||
|
||
Returns:
|
||
|
||
TRUE if the given access range is included in the list of reported
|
||
legacy resources, FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
PVIDEO_ACCESS_RANGE CurrResource;
|
||
|
||
if (fdoExtension->HwLegacyResourceList) {
|
||
|
||
CurrResource = fdoExtension->HwLegacyResourceList;
|
||
|
||
for (i=0; i<fdoExtension->HwLegacyResourceCount; i++) {
|
||
|
||
if ((CurrResource->RangeStart.QuadPart ==
|
||
AccessRange->RangeStart.QuadPart) &&
|
||
(CurrResource->RangeLength == AccessRange->RangeLength)) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
CurrResource++;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
ULONG
|
||
GetCmResourceListSize(
|
||
PCM_RESOURCE_LIST CmResourceList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get the size in bytes of a CmResourceList.
|
||
|
||
Arguments:
|
||
|
||
CmResourceList - The list for which to get the size.
|
||
|
||
Returns:
|
||
|
||
Size in bytes of the CmResourceList.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCM_FULL_RESOURCE_DESCRIPTOR pcmFull;
|
||
PCM_PARTIAL_RESOURCE_LIST pcmPartial;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR pcmDescript;
|
||
ULONG i, j;
|
||
|
||
pcmFull = &(CmResourceList->List[0]);
|
||
for (i=0; i<CmResourceList->Count; i++) {
|
||
|
||
pcmPartial = &(pcmFull->PartialResourceList);
|
||
pcmDescript = &(pcmPartial->PartialDescriptors[0]);
|
||
pcmDescript += pcmPartial->Count;
|
||
pcmFull = (PCM_FULL_RESOURCE_DESCRIPTOR) pcmDescript;
|
||
}
|
||
|
||
return (ULONG)(((ULONG_PTR)pcmFull) - ((ULONG_PTR)CmResourceList));
|
||
}
|
||
|
||
PCM_RESOURCE_LIST
|
||
VpRemoveFromResourceList(
|
||
PCM_RESOURCE_LIST OriginalList,
|
||
ULONG NumAccessRanges,
|
||
PVIDEO_ACCESS_RANGE AccessRanges
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates a new CmResourceList with the given access ranges
|
||
removed.
|
||
|
||
Arguments:
|
||
|
||
OriginalList - The original CmResourceList to operate on.
|
||
|
||
NumAccessRanges - The number of entries in the remove list.
|
||
|
||
AccessRanges - The list of ranges which should be removed from
|
||
the list.
|
||
|
||
Returns:
|
||
|
||
A pointer to the new CmResourceList.
|
||
|
||
Notes:
|
||
|
||
The caller is responsible for freeing the memory returned by this
|
||
function.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCM_RESOURCE_LIST FilteredList;
|
||
ULONG Size = GetCmResourceListSize(OriginalList);
|
||
ULONG remainingLength;
|
||
ULONG ResourcesRemoved;
|
||
|
||
FilteredList = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, Size, VP_TAG);
|
||
|
||
if (FilteredList) {
|
||
|
||
ULONG i, j, k;
|
||
PCM_FULL_RESOURCE_DESCRIPTOR pcmFull;
|
||
PCM_PARTIAL_RESOURCE_LIST pcmPartial;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR pcmDescript;
|
||
|
||
//
|
||
// Make a copy of the original list.
|
||
//
|
||
|
||
memcpy(FilteredList, OriginalList, Size);
|
||
remainingLength = Size - sizeof(CM_RESOURCE_LIST);
|
||
|
||
pcmFull = &(FilteredList->List[0]);
|
||
for (i=0; i<FilteredList->Count; i++) {
|
||
|
||
pcmPartial = &(pcmFull->PartialResourceList);
|
||
pcmDescript = &(pcmPartial->PartialDescriptors[0]);
|
||
|
||
ResourcesRemoved = 0;
|
||
|
||
for (j=0; j<pcmPartial->Count; j++) {
|
||
|
||
//
|
||
// See if the current resource is in our legacy list.
|
||
//
|
||
|
||
for (k=0; k<NumAccessRanges; k++) {
|
||
|
||
if ((pcmDescript->u.Memory.Start.LowPart ==
|
||
AccessRanges[k].RangeStart.LowPart) &&
|
||
(AccessRanges[k].RangeStart.LowPart != 0xC0000)) {
|
||
|
||
//
|
||
// Remove the resource.
|
||
//
|
||
|
||
memmove(pcmDescript,
|
||
pcmDescript + 1,
|
||
remainingLength);
|
||
|
||
pcmDescript--;
|
||
ResourcesRemoved++;
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
remainingLength -= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
||
pcmDescript++;
|
||
}
|
||
|
||
//
|
||
// Update the resource count in the partial resource list
|
||
//
|
||
|
||
pcmPartial->Count -= ResourcesRemoved;
|
||
if (pcmPartial->Count == 0) {
|
||
FilteredList->Count--;
|
||
}
|
||
|
||
remainingLength -= sizeof(CM_PARTIAL_RESOURCE_LIST);
|
||
pcmFull = (PCM_FULL_RESOURCE_DESCRIPTOR) pcmDescript;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Make sure we always return a list.
|
||
//
|
||
|
||
ASSERT(FALSE);
|
||
FilteredList = OriginalList;
|
||
}
|
||
|
||
return FilteredList;
|
||
}
|
||
|