windows-nt/Source/XPSP1/NT/drivers/video/ms/port/registry.c
2020-09-26 16:20:57 +08:00

2396 lines
65 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}