/*++ 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; } // // Zero alignment is illegal. // if (*Alignment == 0) { *Alignment = 1; } 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; }