windows-nt/Source/XPSP1/NT/base/busdrv/mf/arbiter.c
2020-09-26 16:20:57 +08:00

359 lines
7.3 KiB
C

/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
arbiter.c
Abstract:
This module provides arbiters for the resources consumed by PDOs.
Author:
Andy Thornton (andrewth) 20-Oct-97
Revision History:
--*/
#include "mfp.h"
#include "arbiter.h"
NTSTATUS
MfInitializeArbiters(
IN PMF_PARENT_EXTENSION Parent
);
NTSTATUS
MfInitializeArbiter(
OUT PMF_ARBITER Arbiter,
IN PDEVICE_OBJECT BusDeviceObject,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
);
LONG
MfNopScore(
IN PIO_RESOURCE_DESCRIPTOR Descriptor
);
NTSTATUS
MfStartArbiter(
IN PARBITER_INSTANCE Arbiter,
IN PCM_RESOURCE_LIST StartResources
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, MfInitializeArbiters)
#pragma alloc_text(PAGE, MfInitializeArbiter)
#pragma alloc_text(PAGE, MfNopScore)
#pragma alloc_text(PAGE, MfStartArbiter)
#endif
NTSTATUS
MfInitializeArbiters(
IN PMF_PARENT_EXTENSION Parent
)
/*++
Routine Description:
This initializes the arbiters required to arbitrated resources for the
parent device.
Arguments:
Parent - The MF device we are initializing arbiters for.
Return Value:
Status of operation.
--*/
{
NTSTATUS status;
PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;
PMF_ARBITER arbiter, newArbiter = NULL;
BOOLEAN existingArbiter;
PAGED_CODE();
//
// REBALANCE - if restart then free the old arbiters
// until we do that, assume we're not restarting
//
ASSERT(IsListEmpty(&Parent->Arbiters));
//
// If we don't have any resources we don't need any arbiters
//
if (!Parent->ResourceList) {
return STATUS_SUCCESS;
}
FOR_ALL_CM_DESCRIPTORS(Parent->ResourceList, descriptor) {
//
// Check if this is an nonarbitrated resource - if it is then we won't
// be needing an arbiter for it!
//
if (!IS_ARBITRATED_RESOURCE(descriptor->Type)) {
continue;
}
//
// See if we already have an arbiter for this resource
//
existingArbiter = FALSE;
FOR_ALL_IN_LIST(MF_ARBITER, &Parent->Arbiters, arbiter) {
if (arbiter->Type == descriptor->Type) {
//
// We already have an arbiter so we don't need
// to create a new one
//
existingArbiter = TRUE;
break;
}
}
if (!existingArbiter) {
//
// We don't have an arbiter for this resource type so make one!
//
DEBUG_MSG(1,
("Creating arbiter for %s\n",
MfDbgCmResourceTypeToText(descriptor->Type)
));
newArbiter = ExAllocatePoolWithTag(PagedPool,
sizeof(MF_ARBITER),
MF_ARBITER_TAG
);
if (!newArbiter) {
return STATUS_INSUFFICIENT_RESOURCES;
}
status = MfInitializeArbiter(newArbiter, Parent->Self, descriptor);
if (!NT_SUCCESS(status)) {
goto cleanup;
}
InsertHeadList(&Parent->Arbiters, &newArbiter->ListEntry);
}
}
FOR_ALL_IN_LIST(MF_ARBITER, &Parent->Arbiters, arbiter) {
MfStartArbiter(&(arbiter->Instance), Parent->ResourceList);
}
return STATUS_SUCCESS;
cleanup:
if (newArbiter) {
ExFreePool(newArbiter);
}
return status;
}
LONG
MfNopScore(
IN PIO_RESOURCE_DESCRIPTOR Descriptor
)
{
PAGED_CODE();
return 0;
}
NTSTATUS
MfInitializeArbiter(
OUT PMF_ARBITER Arbiter,
IN PDEVICE_OBJECT BusDeviceObject,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
)
/*
Routine Description:
This initializes an arbiter to arbitrated the resources described in
Descriptor
Arguments:
Arbiter - Pointer to a buffer where the arbiter should reside.
Descriptor - Describes the resources available to the arbiter.
Return Value:
Status of operation.
*/
{
NTSTATUS status;
PMF_RESOURCE_TYPE resType;
PAGED_CODE();
//
// Do we understand these resources
//
resType = MfFindResourceType(Descriptor->Type);
if (!resType) {
return STATUS_INVALID_PARAMETER;
}
Arbiter->Type = Descriptor->Type;
RtlZeroMemory(&Arbiter->Instance, sizeof(ARBITER_INSTANCE));
Arbiter->Instance.PackResource = resType->PackResource;
Arbiter->Instance.UnpackResource = resType->UnpackResource;
Arbiter->Instance.UnpackRequirement = resType->UnpackRequirement;
//
// Initialize the arbiter
//
status = ArbInitializeArbiterInstance(&Arbiter->Instance,
BusDeviceObject,
Arbiter->Type,
L"Mf Arbiter",
L"Root", // should be NULL
NULL
);
return status;
}
//
// Arbiter support functions
//
NTSTATUS
MfStartArbiter(
IN PARBITER_INSTANCE Arbiter,
IN PCM_RESOURCE_LIST StartResources
)
/*++
Routine Description:
This initializes an arbiter's range list to arbitrate the
resources described in StartResources
Arguments:
Arbiter - Pointer to the arbiter.
StartResources - Describes the resources available to the arbiter.
Return Value:
Status of operation.
--*/
{
RTL_RANGE_LIST invertedAllocation;
PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;
ULONGLONG start;
ULONG length;
NTSTATUS status;
PAGED_CODE();
RtlInitializeRangeList(&invertedAllocation);
//
// Iterate through resource descriptors, adding the resources
// this arbiter arbitrates to the ReverseAllocation
//
FOR_ALL_CM_DESCRIPTORS(StartResources,descriptor) {
if (descriptor->Type == Arbiter->ResourceType) {
status = Arbiter->UnpackResource(descriptor,
&start,
&length);
if (!NT_SUCCESS(status)) {
goto cleanup;
}
if (length > 0) {
//
// we don't care about Attributes, UserData or Owner since this
// list is going to get trashed in a minute anyway
//
status = RtlAddRange(&invertedAllocation,
start,
END_OF_RANGE(start,length),
0, // Attributes
RTL_RANGE_LIST_ADD_SHARED|RTL_RANGE_LIST_ADD_IF_CONFLICT,
0, // UserData
NULL); // Owner
}
if (!NT_SUCCESS(status)) {
goto cleanup;
}
}
}
status = RtlInvertRangeList(Arbiter->Allocation,&invertedAllocation);
if (!NT_SUCCESS(status)) {
goto cleanup;
}
status = STATUS_SUCCESS;
cleanup:
RtlFreeRangeList(&invertedAllocation);
return status;
}