516 lines
11 KiB
C
516 lines
11 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"
|
|
|
|
NTSTATUS
|
|
MfUnpackRequirement(
|
|
IN PIO_RESOURCE_DESCRIPTOR Descriptor,
|
|
OUT PULONGLONG Minimum,
|
|
OUT PULONGLONG Maximum,
|
|
OUT PULONG Length,
|
|
OUT PULONG Alignment
|
|
);
|
|
|
|
NTSTATUS
|
|
MfPackResource(
|
|
IN PIO_RESOURCE_DESCRIPTOR Requirement,
|
|
IN ULONGLONG Start,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
|
|
);
|
|
|
|
NTSTATUS
|
|
MfUnpackResource(
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
|
OUT PULONGLONG Start,
|
|
OUT PULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
MfRequirementFromResource(
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource,
|
|
OUT PIO_RESOURCE_DESCRIPTOR Requirement
|
|
);
|
|
|
|
NTSTATUS
|
|
MfUpdateResource(
|
|
IN OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource,
|
|
IN ULONGLONG Start,
|
|
IN ULONG Length
|
|
);
|
|
|
|
//
|
|
// Make everything pageable
|
|
//
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
#pragma alloc_text(PAGE, MfFindResourceType)
|
|
#pragma alloc_text(PAGE, MfUnpackRequirement)
|
|
#pragma alloc_text(PAGE, MfPackResource)
|
|
#pragma alloc_text(PAGE, MfUnpackResource)
|
|
#pragma alloc_text(PAGE, MfUpdateResource)
|
|
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
//
|
|
// This table describes the resource types that are understood by the MF driver.
|
|
// It is implemented thus to that in the future MF could be educated about new
|
|
// resource types dynamically.
|
|
//
|
|
|
|
MF_RESOURCE_TYPE MfResourceTypes[] = {
|
|
|
|
{
|
|
CmResourceTypePort,
|
|
MfUnpackRequirement,
|
|
MfPackResource,
|
|
MfUnpackResource,
|
|
MfRequirementFromResource,
|
|
MfUpdateResource
|
|
|
|
},
|
|
|
|
{
|
|
CmResourceTypeInterrupt,
|
|
MfUnpackRequirement,
|
|
MfPackResource,
|
|
MfUnpackResource,
|
|
MfRequirementFromResource,
|
|
MfUpdateResource
|
|
},
|
|
|
|
{
|
|
CmResourceTypeMemory,
|
|
MfUnpackRequirement,
|
|
MfPackResource,
|
|
MfUnpackResource,
|
|
MfRequirementFromResource,
|
|
MfUpdateResource
|
|
},
|
|
|
|
{
|
|
CmResourceTypeDma,
|
|
MfUnpackRequirement,
|
|
MfPackResource,
|
|
MfUnpackResource,
|
|
MfRequirementFromResource,
|
|
MfUpdateResource
|
|
},
|
|
|
|
{
|
|
CmResourceTypeBusNumber,
|
|
MfUnpackRequirement,
|
|
MfPackResource,
|
|
MfUnpackResource,
|
|
MfRequirementFromResource,
|
|
MfUpdateResource
|
|
}
|
|
};
|
|
|
|
NTSTATUS
|
|
MfRequirementFromResource(
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource,
|
|
OUT PIO_RESOURCE_DESCRIPTOR Requirement
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function build an requirements descriptor for a resource the parent is
|
|
started with.
|
|
|
|
Arguments:
|
|
|
|
Resource - Pointer to the resource to make a requirement from
|
|
|
|
Requirement - Pointer to a descriptor that should be filled in
|
|
|
|
Return Value:
|
|
|
|
Success or otherwise of the operation
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Copy the common fields
|
|
//
|
|
|
|
Requirement->Type = Resource->Type;
|
|
Requirement->ShareDisposition = Resource->ShareDisposition;
|
|
Requirement->Flags = Resource->Flags;
|
|
|
|
//
|
|
// Fill in the requirement
|
|
//
|
|
|
|
switch (Resource->Type) {
|
|
case CmResourceTypeMemory:
|
|
case CmResourceTypePort:
|
|
|
|
//
|
|
// We *DO NOT* support zero length requirements
|
|
//
|
|
|
|
if (Resource->u.Generic.Length == 0) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Requirement->u.Generic.MinimumAddress = Resource->u.Generic.Start;
|
|
Requirement->u.Generic.MaximumAddress.QuadPart =
|
|
Resource->u.Generic.Start.QuadPart + Resource->u.Generic.Length - 1;
|
|
Requirement->u.Generic.Length = Resource->u.Generic.Length;
|
|
Requirement->u.Generic.Alignment = 1;
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
Requirement->u.Interrupt.MinimumVector = Resource->u.Interrupt.Vector;
|
|
Requirement->u.Interrupt.MaximumVector = Resource->u.Interrupt.Vector;
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
Requirement->u.Dma.MinimumChannel = Resource->u.Dma.Channel;
|
|
Requirement->u.Dma.MinimumChannel = Resource->u.Dma.Channel;
|
|
break;
|
|
|
|
case CmResourceTypeBusNumber:
|
|
|
|
//
|
|
// We *DO NOT* support zero length requirements
|
|
//
|
|
|
|
if (Resource->u.BusNumber.Length == 0) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Requirement->u.BusNumber.Length = Resource->u.BusNumber.Length;
|
|
Requirement->u.BusNumber.MinBusNumber = Resource->u.BusNumber.Start;
|
|
Requirement->u.BusNumber.MaxBusNumber = Resource->u.BusNumber.Start +
|
|
Resource->u.BusNumber.Length - 1;
|
|
break;
|
|
|
|
case CmResourceTypeDevicePrivate:
|
|
Requirement->u.DevicePrivate.Data[0] = Resource->u.DevicePrivate.Data[0];
|
|
Requirement->u.DevicePrivate.Data[1] = Resource->u.DevicePrivate.Data[1];
|
|
Requirement->u.DevicePrivate.Data[2] = Resource->u.DevicePrivate.Data[2];
|
|
break;
|
|
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
PMF_RESOURCE_TYPE
|
|
MfFindResourceType(
|
|
IN CM_RESOURCE_TYPE Type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine searches the database of know resource types to find the
|
|
resource descriptor manipulation routines for resources of type Type.
|
|
|
|
Arguments:
|
|
|
|
Type - The resource type we are interested in.
|
|
|
|
Return Value:
|
|
|
|
Returns a pointer to the appropriate MF_RESOURCE_TYPE or NULL if one could
|
|
not be found.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
PMF_RESOURCE_TYPE current;
|
|
|
|
PAGED_CODE();
|
|
|
|
FOR_ALL_IN_ARRAY(MfResourceTypes,
|
|
sizeof(MfResourceTypes) / sizeof(MF_RESOURCE_TYPE),
|
|
current
|
|
) {
|
|
|
|
if (current->Type == Type) {
|
|
return current;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MfUnpackRequirement(
|
|
IN PIO_RESOURCE_DESCRIPTOR Descriptor,
|
|
OUT PULONGLONG Minimum,
|
|
OUT PULONGLONG Maximum,
|
|
OUT PULONG Length,
|
|
OUT PULONG Alignment
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine unpacks an resource requirement descriptor.
|
|
|
|
Arguments:
|
|
|
|
Descriptor - The descriptor describing the requirement to unpack.
|
|
|
|
Minimum - Pointer to where the minimum acceptable start value should be
|
|
unpacked to.
|
|
|
|
Maximum - Pointer to where the maximum acceptable end value should be
|
|
unpacked to.
|
|
|
|
Length - Pointer to where the required length should be unpacked to.
|
|
|
|
Minimum - Pointer to where the required alignment should be unpacked to.
|
|
|
|
Return Value:
|
|
|
|
Returns the status of this operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PAGED_CODE();
|
|
|
|
switch (Descriptor->Type) {
|
|
case CmResourceTypePort:
|
|
case CmResourceTypeMemory:
|
|
|
|
*Maximum = Descriptor->u.Generic.MaximumAddress.QuadPart;
|
|
*Minimum = Descriptor->u.Generic.MinimumAddress.QuadPart;
|
|
*Length = Descriptor->u.Generic.Length;
|
|
*Alignment = Descriptor->u.Generic.Alignment;
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
|
|
*Maximum = Descriptor->u.Interrupt.MaximumVector;
|
|
*Minimum = Descriptor->u.Interrupt.MinimumVector;
|
|
*Length = 1;
|
|
*Alignment = 1;
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
*Maximum = Descriptor->u.Dma.MaximumChannel;
|
|
*Minimum = Descriptor->u.Dma.MinimumChannel;
|
|
*Length = 1;
|
|
*Alignment = 1;
|
|
break;
|
|
|
|
case CmResourceTypeBusNumber:
|
|
*Maximum = Descriptor->u.BusNumber.MaxBusNumber;
|
|
*Minimum = Descriptor->u.BusNumber.MinBusNumber;
|
|
*Length = Descriptor->u.BusNumber.Length;
|
|
*Alignment = 1;
|
|
break;
|
|
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfPackResource(
|
|
IN PIO_RESOURCE_DESCRIPTOR Requirement,
|
|
IN ULONGLONG Start,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine packs an resource descriptor.
|
|
|
|
Arguments:
|
|
|
|
Requirement - The requirement from which this resource was chosen.
|
|
|
|
Start - The start value of the resource.
|
|
|
|
Descriptor - Pointer to the descriptor to pack into.
|
|
|
|
Return Value:
|
|
|
|
Returns the status of this operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
switch (Requirement->Type) {
|
|
case CmResourceTypePort:
|
|
case CmResourceTypeMemory:
|
|
Descriptor->u.Generic.Start.QuadPart = Start;
|
|
Descriptor->u.Generic.Length = Requirement->u.Generic.Length;
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
ASSERT(Start <= MAXULONG);
|
|
Descriptor->u.Interrupt.Level = (ULONG)Start;
|
|
Descriptor->u.Interrupt.Vector = (ULONG)Start;
|
|
Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
ASSERT(Start <= MAXULONG);
|
|
Descriptor->u.Dma.Channel = (ULONG)Start;
|
|
Descriptor->u.Dma.Port = 0;
|
|
break;
|
|
|
|
case CmResourceTypeBusNumber:
|
|
ASSERT(Start <= MAXULONG);
|
|
Descriptor->u.BusNumber.Start = (ULONG)Start;
|
|
Descriptor->u.BusNumber.Length = Requirement->u.BusNumber.Length;
|
|
break;
|
|
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Descriptor->ShareDisposition = Requirement->ShareDisposition;
|
|
Descriptor->Flags = Requirement->Flags;
|
|
Descriptor->Type = Requirement->Type;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
MfUnpackResource(
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
|
OUT PULONGLONG Start,
|
|
OUT PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine unpacks a resource descriptor.
|
|
|
|
Arguments:
|
|
|
|
Descriptor - The descriptor describing the resource to unpack.
|
|
|
|
Start - Pointer to where the start value should be unpacked to.
|
|
|
|
End - Pointer to where the end value should be unpacked to.
|
|
|
|
Return Value:
|
|
|
|
Returns the status of this operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
switch (Descriptor->Type) {
|
|
case CmResourceTypePort:
|
|
case CmResourceTypeMemory:
|
|
*Start = Descriptor->u.Generic.Start.QuadPart;
|
|
*Length = Descriptor->u.Generic.Length;
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
*Start = Descriptor->u.Interrupt.Vector;
|
|
*Length = 1;
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
*Start = Descriptor->u.Dma.Channel;
|
|
*Length = 1;
|
|
break;
|
|
|
|
case CmResourceTypeBusNumber:
|
|
*Start = Descriptor->u.BusNumber.Start;
|
|
*Length = Descriptor->u.BusNumber.Length;
|
|
break;
|
|
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfUpdateResource(
|
|
IN OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource,
|
|
IN ULONGLONG Start,
|
|
IN ULONG Length
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
ASSERT(Resource);
|
|
|
|
switch (Resource->Type) {
|
|
|
|
case CmResourceTypePort:
|
|
case CmResourceTypeMemory:
|
|
Resource->u.Generic.Start.QuadPart = Start;
|
|
Resource->u.Generic.Length = Length;
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
ASSERT(Start < MAXULONG);
|
|
Resource->u.Interrupt.Vector = (ULONG)Start;
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
ASSERT(Start < MAXULONG);
|
|
Resource->u.Dma.Channel = (ULONG)Start;
|
|
break;
|
|
|
|
case CmResourceTypeBusNumber:
|
|
ASSERT(Start < MAXULONG);
|
|
Resource->u.BusNumber.Start = (ULONG)Start;
|
|
Resource->u.BusNumber.Length = Length;
|
|
break;
|
|
|
|
default:
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|