/*++ Copyright (c) 1992 Microsoft Corporation Module Name: assign.c Abstract: IoAssignResources Author: Ken Reneris Environment: EDIT IN 110 COLUMN MODE Revision History: Add PnP support - shielint --*/ #include "iop.h" #define IDBG DBG #define PAGED 1 #define INLINE __inline #define STATIC static //#define IDBG 1 //#define DBG 1 //#define PAGED //#define INLINE //#define STATIC /* * IDBG - Internal debugging. Turn on for runtime DbgPrints of calls to IoAssignResources * PAGED - Declare functions as pageable or not. (usefull for debugging) * INLINE - Inline functions * STATIC - internal functions to this module which are static * */ extern WCHAR IopWstrOtherDrivers[]; extern WCHAR IopWstrAssignedResources[]; extern WCHAR IopWstrRequestedResources[]; extern WCHAR IopWstrSystemResources[]; extern WCHAR IopWstrReservedResources[]; extern WCHAR IopWstrAssignmentOrdering[]; extern WCHAR IopWstrBusValues[]; extern WCHAR IopWstrTranslated[]; extern WCHAR IopWstrBusTranslated[]; #define HRESOURCE_MAP 0 #define HDEVICE_STORAGE 1 #define HCURRENT_CONTROL_SET 2 #define HSYSTEMRESOURCES 3 #define HORDERING 4 #define HRESERVEDRESOURCES 5 #define HBUSVALUES 6 #define HOWNER_MAP 7 #define MAX_REG_HANDLES 8 #define INVALID_HANDLE (HANDLE) -1 #define BUFFERSIZE (2048 + sizeof( KEY_FULL_INFORMATION )) #define MAX_ENTRIES 50 #define SCONFLICT 5 // // Wrapper structures around IO_RESOURCE lists // // owner of TENTRY typedef struct { LIST_ENTRY InConflict; UNICODE_STRING KeyName; UNICODE_STRING DeviceName; WCHAR UnicodeBuffer[1]; // Must be last! } *POWNER; #if _PNP_POWER_ struct _RECONFIGURED_DRIVER; // // Flags for TENTRY // #define TENTRY_FLAGS_IN_USE 0 #define TENTRY_FLAGS_BEING_RELOCATED 1 #define TENTRY_FLAGS_REMOVED 2 #endif // translated entry typedef struct { LONGLONG BAddr; // Beginning address LONGLONG EAddr; // Ending address KAFFINITY Affinity; // Processor affinity of resource POWNER Owner; // Owner of this resource #if _PNP_POWER_ UCHAR Flags; // Flags of this entry #else #if IDBG ULONG na[2]; #endif #endif // _PNP_POWER_ } TENTRY, *PTENTRY; // Translated resource #define DoesTEntryCollide(a,b) \ ( (a).EAddr >= (b).BAddr && (a).BAddr <= (b).EAddr && ((a).Affinity & (b).Affinity) ) // list of translated entries typedef struct _LTENTRY { struct _LTENTRY *Next; // Allocated table size ULONG CurEntries; // No entries in table ULONG na[2]; TENTRY Table[MAX_ENTRIES]; } LTENTRY, *PLTENTRY; // List of translated resources // list of translated entries by CmResourceType typedef struct { PLTENTRY ByType[CmResourceTypeMaximum]; } TENTRIESBYTYPE, *PTENTRIESBYTYPE; // information about conflict typedef struct { ULONG NoConflicts; // # of BAddrs struct { UCHAR Type; LONGLONG BAddr; POWNER Owner; } EasyConflict[SCONFLICT]; LIST_ENTRY OtherConflicts; } IO_TRACK_CONFLICT, *PIO_TRACK_CONFLICT; // a required resource with it's alternatives typedef struct { // work in progress... ULONG CurLoc; // Which IoResourceDescriptor ULONG RunLen; // length of alternative run ULONG PassNo; // current bus specific ordering location ULONG CurBusLoc; // Current Bus descriptor location LONGLONG CurBusMin; // Current bus desc min LONGLONG CurBusMax; // Current bus desc max // raw selection being considered... UCHAR Type; // type of descriptor ULONG CurBLoc; LONGLONG CurBAddr; // bus native BAddr // the raw selection's translation UCHAR TType; // Translated type TENTRY Trans; // Translated info LONG BestPref; // only has meaning on first pass LONG CurPref; // Prefernce of current selection // Phase 3 ULONG PrefCnt; // # of times this level skipped ULONG Pass2HoldCurLoc; // CurBLoc of best selection so far LONGLONG Pass2HoldBAddr; // CurBAddr of best selection so far // resource options ULONG NoAlternatives; // entries in IoResourceDescriptor PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor[1]; // MUST BE LAST ENTRY } DIR_REQUIRED_RESOURCE, *PDIR_REQUIRED_RESOURCE; // a list of required resources for the alternative list typedef struct _DIR_RESOURCE_LIST { struct _DIR_RESOURCE_LIST *Next; // next alternative list PDIR_REQUIRED_RESOURCE ResourceByType[CmResourceTypeMaximum]; // catagorized list LONG CurPref; ULONG LastLevel; // last level tried ULONG FailedLevel; // which level had conflict IO_TRACK_CONFLICT Conflict; // pass3 PIO_RESOURCE_LIST IoResourceList; // this IO_RESOURCE_LIST ULONG NoRequiredResources; // entries in RequiredResource PDIR_REQUIRED_RESOURCE RequiredResource[1]; // MUST BE LAST ENTRY } DIR_RESOURCE_LIST, *PDIR_RESOURCE_LIST; // top level structure typedef struct _DIR_RESREQ_LIST { HANDLE RegHandle[MAX_REG_HANDLES]; // handles to different registry locations struct _DIR_RESREQ_LIST *UserDir; struct _DIR_RESREQ_LIST *BusDir; struct _DIR_RESREQ_LIST *FreeResReqList; // other DIR_RESREQ_LIST which need freed SINGLE_LIST_ENTRY AllocatedHeap; // heap which needs freed TENTRIESBYTYPE InUseResources; TENTRIESBYTYPE InUseSharableResources; TENTRIESBYTYPE ReservedSharableResources; PIO_RESOURCE_REQUIREMENTS_LIST IoResourceReq; // this IO_RESOURCES_REQUIREMENTS_LIST PDIR_RESOURCE_LIST Alternative; // list of alternatives PWCHAR Buffer; // Scratch memory #if _PNP_POWER_ PDIR_RESOURCE_LIST ListPicked; // Resources assigned list struct _RECONFIGURED_DRIVER *ReconfiguredDriver; #endif } DIR_RESREQ_LIST, *PDIR_RESREQ_LIST; // a list of heap which was allocated typedef struct { SINGLE_LIST_ENTRY FreeLink; // List of heap to free PVOID FreeHeap; // pointer to heap to free } USED_HEAP, *PUSED_HEAP; #if _PNP_POWER_ // // IopRelocatedDirList - List of all the DIRs which were created to resolve conflicts. // PDIR_RESREQ_LIST IopRelocatedDirList = NULL; // // Information about conflict used by conflict relocator // typedef struct _RELOCATED_TENTRIES{ struct _RELOCATED_TENTRIES *Next; UCHAR Type; // Type of the TENTRY PTENTRY TranslatedEntry; // Pointer to the TENTRY UNICODE_STRING OriginalDriver; // The names of the original UNICODE_STRING OriginalDevice; // owner. So we can restore then // if necessary. } RELOCATED_TENTRIES, *PRELOCATED_TENTRIES; // // IopInProcessedConflicts - list of all the conflict translated // entries under processed. // PRELOCATED_TENTRIES IopInProcessedConflicts = NULL; // // IopNewResources - list of all the new translated entries // allocated by the reconfigured drivers. // PRELOCATED_TENTRIES IopNewResources = NULL; // // Information about driver/device to be reconfigured. // typedef struct _RECONFIGURED_DRIVER { struct _RECONFIGURED_DRIVER *Next; POWNER Owner; // Owner of this structure struct _DIR_RESREQ_LIST *ReconfiguredDir; // pointer to DIR_RESREQ_LIST PCM_RESOURCE_LIST CmResourceList; // Cm res list of the driver/device ULONG ResourceLength; // The length of the CM resource list UNICODE_STRING DriverClassName; // Required by ReportResourceUsage PDRIVER_OBJECT DriverObject; // pointer to the dev obj of the driver PDEVICE_OBJECT DeviceObject; // Not NULL if resource is device specific PFILE_OBJECT DeviceFileObject; // redundant?? } RECONFIGURED_DRIVER, *PRECONFIGURED_DRIVER; PRECONFIGURED_DRIVER IopReconfiguredDrivers; // // Information to help reconstruct DIR_REQUIRED_LIST // typedef struct _REG_REQUIRED_RESOURCE { // // raw selection // UCHAR Type; // type of descriptor ULONG CurBLoc; LONGLONG CurBAddr; // bus native BAddr // // the raw selection's translation // UCHAR TType; // Translated type TENTRY Trans; // Translated info } REG_REQUIRED_RESOURCE, *PREG_REQUIRED_RESOURCE; typedef struct _REG_REQUIRED_RESOURCE_LIST { ULONG NoRequiredResources; REG_REQUIRED_RESOURCE RegResource[1]; // Must be last entry } REG_REQUIRED_RESOURCE_LIST, *PREG_REQUIRED_RESOURCE_LIST; #endif // _PNP_POWER // // Internal prototypes // PIO_RESOURCE_REQUIREMENTS_LIST IopGetResourceReqRegistryValue ( IN PDIR_RESREQ_LIST Dir, IN HANDLE KeyHandle, IN PWSTR ValueName ); NTSTATUS IopAssignResourcesPhase1 ( IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources, IN PIO_RESOURCE_REQUIREMENTS_LIST *CopiedList ); NTSTATUS IopAssignResourcesPhase2 ( IN PDIR_RESREQ_LIST Dir, IN PUNICODE_STRING DriverClassName, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject ); PDIR_RESOURCE_LIST IopAssignResourcesPhase3 ( IN PDIR_RESREQ_LIST Dir ); PCM_RESOURCE_LIST IopAssignResourcesPhase4 ( IN PDIR_RESREQ_LIST Dir, IN PDIR_RESOURCE_LIST CurList, OUT PULONG Length ); STATIC VOID IopLogConflict ( IN PDRIVER_OBJECT DriverObject, IN PDIR_RESREQ_LIST Dir, IN NTSTATUS FinalStatus ); STATIC PVOID IopAllocateDirPool ( IN PDIR_RESREQ_LIST Dir, IN ULONG Length ); INLINE PTENTRY IopNewTransEntry ( IN PDIR_RESREQ_LIST Dir, IN PTENTRIESBYTYPE pTypes, IN ULONG Type ); STATIC NTSTATUS IopAddCmDescriptorToInUseList ( IN PDIR_RESREQ_LIST Dir, IN PTENTRIESBYTYPE pTypes, IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc, IN POWNER Owner ); ULONG IopFindCollisionInTList ( IN PTENTRY SEntry, #if _PNP_POWER_ IN PLTENTRY List, OUT PTENTRY *ConflictEntry #else IN PLTENTRY List #endif // _PNP_POWER_ ); VOID IopPickupCollisionInTList ( IN PDIR_RESOURCE_LIST CurList, IN UCHAR Type, IN LONGLONG BAddr, IN PTENTRY SEntry, IN PLTENTRY List ); NTSTATUS IopBuildResourceDir ( IN PDIR_RESREQ_LIST ParentDir, IN PDIR_RESREQ_LIST *DirResourceList, IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources ); VOID IopFreeResourceDir ( IN PDIR_RESREQ_LIST DirResourceList ); VOID IopSortDescriptors ( IN OUT PDIR_RESREQ_LIST Dir ); NTSTATUS IopCatagorizeDescriptors ( IN OUT PDIR_RESREQ_LIST Dir ); ULONG IopDescriptorSortingWeight ( IN PIO_RESOURCE_DESCRIPTOR Descriptor ); BOOLEAN IopGenNextValidResourceList ( IN ULONG level, IN PDIR_RESOURCE_LIST CurList, IN PDIR_RESREQ_LIST Dir ); BOOLEAN IopGenNextValidDescriptor ( IN ULONG level, IN PDIR_RESOURCE_LIST CurList, IN PDIR_RESREQ_LIST Dir, IN PULONG collisionlevel ); BOOLEAN IopSlotResourceOwner ( IN PDIR_RESREQ_LIST Dir, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources, IN BOOLEAN AddOwner ); #if _PNP_POWER_ PDIR_RESOURCE_LIST IopAssignMachineDefaultResources ( IN PDIR_RESREQ_LIST Dir, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject, IN PIO_RESOURCE_REQUIREMENTS_LIST RequestedResource ); BOOLEAN IopRelocateResource ( IN PDIR_RESREQ_LIST Dir, IN PDIR_RESOURCE_LIST CurList, IN UCHAR TranslatedType, IN PTENTRY ConflictEntry, IN PTENTRY TranslatedEntry ); PDIR_RESOURCE_LIST IopResolveConflicts ( IN PDIR_RESREQ_LIST Dir ); ULONG IopAddRelocatedEntry ( IN PRELOCATED_TENTRIES *List, IN PTENTRY Entry, IN UCHAR Type, IN POWNER NewOwner ); ULONG IopFindCollisionInRelocatedList ( IN PTENTRY SEntry, IN PRELOCATED_TENTRIES List, OUT PTENTRY *ConflictEntry ); VOID IopFreeRelocatedTEntryLists ( VOID ); NTSTATUS IopQueryReconfigureResource( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject, IN PCM_RESOURCE_LIST CmResources ); NTSTATUS IopReconfigureResource( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject, IN PCM_RESOURCE_LIST CmResources ); NTSTATUS IopCancelReconfigureResource( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject ); NTSTATUS IopRecordAssignInformation( IN PDIR_RESREQ_LIST Dir, IN PUNICODE_STRING DriverClassName, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject, IN PDIR_RESOURCE_LIST CurList ); VOID IopFreeRelocatedResourceDir ( IN PDIR_RESREQ_LIST DirResourceList ); #endif #if IDBG VOID IopDumpIoResourceDir ( IN PDIR_RESREQ_LIST Dir ); VOID IopDumpIoResourceDescriptor ( IN PUCHAR Indent, IN PIO_RESOURCE_DESCRIPTOR Desc ); #endif #if DBG #define CHECK_STATUS(a,b) { if(!NT_SUCCESS(a)) { DebugString = b; goto Exit; } } #else #define CHECK_STATUS(a,b) { if(!NT_SUCCESS(a)) goto Exit; } #endif #if DBG #define DBGMSG(a) DbgPrint(a) #else #define DBGMSG(a) #endif #if IDBG #define IDBGMSG(a) DbgPrint(a) #else #define IDBGMSG(a) #endif #ifdef PAGED #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE,IoAssignResources) #pragma alloc_text(PAGE,IopAssignResourcesPhase1) #pragma alloc_text(PAGE,IopAssignResourcesPhase2) #pragma alloc_text(PAGE,IopAssignResourcesPhase3) #pragma alloc_text(PAGE,IopAssignResourcesPhase4) #pragma alloc_text(PAGE,IopLogConflict) #pragma alloc_text(PAGE,IopGenNextValidResourceList) #pragma alloc_text(PAGE,IopGenNextValidDescriptor) #pragma alloc_text(PAGE,IopFindCollisionInTList) #pragma alloc_text(PAGE,IopPickupCollisionInTList) #pragma alloc_text(PAGE,IopAllocateDirPool) #pragma alloc_text(PAGE,IopGetResourceReqRegistryValue) #pragma alloc_text(PAGE,IopBuildResourceDir) #pragma alloc_text(PAGE,IopFreeResourceDir) #pragma alloc_text(PAGE,IopCatagorizeDescriptors) #pragma alloc_text(PAGE,IopSortDescriptors) #pragma alloc_text(PAGE,IopAddCmDescriptorToInUseList) #pragma alloc_text(PAGE,IopSlotResourceOwner) #if _PNP_POWER_ #pragma alloc_text(PAGE,IoAssignDeviceResources) #pragma alloc_text(PAGE,IopResolveConflicts) #pragma alloc_text(PAGE,IopAddRelocatedEntry) #pragma alloc_text(PAGE,IopFindCollisionInRelocatedList) #pragma alloc_text(PAGE,IopFreeRelocatedTEntryLists) #pragma alloc_text(PAGE,IopRelocateResource) #pragma alloc_text(PAGE,IopQueryReconfigureResource) #pragma alloc_text(PAGE,IopReconfigureResource) #pragma alloc_text(PAGE,IopCancelReconfigureResource) #pragma alloc_text(PAGE,IopRecordAssignInformation) #pragma alloc_text(PAGE,IopFreeRelocatedResourceDir) #endif // _PNP_POWER_ #if IDBG #pragma alloc_text(PAGE,IopDumpIoResourceDir) #pragma alloc_text(PAGE,IopDumpIoResourceDescriptor) #endif #ifndef INLINE #pragma alloc_text(PAGE,IO_DESC_MIN) #pragma alloc_text(PAGE,IO_DESC_MAX) #pragma alloc_text(PAGE,IopDescriptorSortingWeight) #pragma alloc_text(PAGE,IopNewTransEntry) #endif // INLINE #endif // ALLOC_PRAGMA #endif // PAGED #if _PNP_POWER_ NTSTATUS IoAssignDeviceResources ( IN PDEVICE_HANDLER_OBJECT DeviceHandler, IN PUNICODE_STRING RegistryPath OPTIONAL, IN PUNICODE_STRING DriverClassName OPTIONAL, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject, IN PIO_RESOURCE_REQUIREMENTS_LIST RequestedResources OPTIONAL, IN OUT PCM_RESOURCE_LIST *AllocatedResources ) /*++ Routine Description: This routine takes an input request of RequestedResources, and returned allocated resources in pAllocatedResources. The allocated resources are automatically recorded in the registry under the ResourceMap for the DriverClassName/DriverObject/DeviceObject requestor. Arguments: DeviceHandler Supplies a pointer to the device's device handler object. RegistryPath For a simple driver, this would be the value passed to the drivers initialization function. For drivers call IoAssignResources with multiple DeviceObjects are responsible for passing in a unique RegistryPath for each object. Drivers do not need to specify this argument if it is the same as ServiceKeyName. The registry path is checked for: RegitryPath: AssignedSystemResources. AssignSystemResources is of type REG_RESOURCE_REQUIREMENTS_LIST If present, IoAssignResources will attempt to use these settings to satisify the requested resources. If the listed settings do not conform to the resource requirements, then IoAssignResources will fail. Note: IoAssignResources may store other internal binary information in the supplied RegisteryPath. DriverObject: The driver object of the caller. DeviceObject: Supplies a pointer to a device object that the requested resoruce list refers to. DriverClassName Used to partition allocated resources into different device classes. RequestedResources A list of resources to allocate. If NULL, it will be retrieved from the location specified by ServiceKeyName\InstanceNumber. Allocated resources may be freed by re-invoking IoAssignResources with the same RegistryPath, DriverObject and DeviceObject. AllocatedResources Returns the allocated resources for the requested resource list. Note that the driver is responsible for passing in a pointer to an uninitialized pointer. IoAssignDeviceResources will initialize the pointer to point to the allocated CM_RESOURCE_LIST. The driver is responisble for returning the memory back to pool when it is done with them structure. Return Value: The status returned is the final completion status of the operation. --*/ { NTSTATUS status; PIO_RESOURCE_REQUIREMENTS_LIST ioResources = NULL, adjustedIoResources = NULL; PCM_RESOURCE_LIST cmResList = NULL; ULONG instanceFlags, bufferSize, requiredSize; HAL_BUS_INFORMATION busInfo; UNICODE_STRING unicodeName, fullServiceName; HANDLE handle; PAGED_CODE(); // // If caller does not specify RegistryPath, use ServiceKeyName instead. // fullServiceName.Buffer = NULL; if (!ARGUMENT_PRESENT(RegistryPath)) { bufferSize = CmRegistryMachineSystemCurrentControlSetServices.Length + 2 * sizeof(UNICODE_NULL) + DeviceHandler->ServiceKeyName.Length; fullServiceName.Buffer = (PWSTR)ExAllocatePool(PagedPool, bufferSize); if (!fullServiceName.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; } fullServiceName.Length = (USHORT)bufferSize - sizeof(UNICODE_NULL); fullServiceName.MaximumLength = (USHORT)bufferSize; bufferSize = CmRegistryMachineSystemCurrentControlSetServices.Length; RtlMoveMemory (fullServiceName.Buffer, CmRegistryMachineSystemCurrentControlSetServices.Buffer, bufferSize ); fullServiceName.Buffer[bufferSize / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR; bufferSize += sizeof(WCHAR); RtlMoveMemory((PUCHAR)fullServiceName.Buffer + bufferSize, DeviceHandler->ServiceKeyName.Buffer, DeviceHandler->ServiceKeyName.Length ); bufferSize += DeviceHandler->ServiceKeyName.Length; fullServiceName.Buffer[bufferSize / sizeof(WCHAR)] = UNICODE_NULL; RegistryPath = &fullServiceName; } // // if caller does not supplies RequestedResources try to get it from // registry specified by ServiceKeyName and InstanceNumber. // if (!ARGUMENT_PRESENT(RequestedResources)) { bufferSize = 1024; allocAgain: ioResources = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePool(PagedPool, bufferSize); if (ioResources == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto exit0; } status = IoQueryDeviceConfigurationVector( DeviceHandler, &instanceFlags, ioResources, bufferSize, &requiredSize ); if (!NT_SUCCESS(status)) { ExFreePool(ioResources); ioResources = NULL; if (status == STATUS_BUFFER_TOO_SMALL) { bufferSize = requiredSize; goto allocAgain; } } else if (ioResources->ListSize == 0 || requiredSize == 0) { // // if it is an empty list, free the space // ExFreePool(ioResources); ioResources = NULL; } else { RequestedResources = ioResources; } } // // Get machine default resources frome ServiceKeyName\InstanceNumber. // bufferSize = 512; tryAgain: cmResList = (PCM_RESOURCE_LIST)ExAllocatePool(PagedPool, bufferSize); if (cmResList == NULL) { if (ioResources) { ExFreePool(ioResources); } status = STATUS_INSUFFICIENT_RESOURCES; goto exit0; } status = IoQueryDeviceConfiguration( DeviceHandler, &busInfo, &instanceFlags, cmResList, bufferSize, &requiredSize ); if (!NT_SUCCESS(status)) { ExFreePool(cmResList); cmResList = NULL; if (status == STATUS_BUFFER_TOO_SMALL) { bufferSize = requiredSize; goto tryAgain; } } else if (requiredSize == 0 || cmResList->Count == 0) { // // if it is an empty list, free the space // ExFreePool(cmResList); cmResList = NULL; } // // If no possible resource lists and default resource list, // exit. // if (!RequestedResources && !cmResList) { status = STATUS_INVALID_PARAMETER; goto exit0; } if (cmResList) { // // Insert default resources to the RequestedResources such that // the default resource list will be picked with highest priority. // adjustedIoResources = IopAddDefaultResourceList (RequestedResources, cmResList); ExFreePool(cmResList); if (adjustedIoResources) { if (ioResources) { ExFreePool(ioResources); ioResources = NULL; } RequestedResources = adjustedIoResources; } } // // call IoAssignResources to allocate resources for the device // status = IoAssignResources ( RegistryPath, DriverClassName, DriverObject, DeviceObject, RequestedResources, AllocatedResources ); if (!NT_SUCCESS(status)) { goto exit; } #if 0 // // Call Hal to set the allocated resources to the device's corresponding // configuration space. // requiredSize = IopDetermineResourceListSize(*AllocatedResources); status = HalSlotControl(RequestedResources->InterfaceType, RequestedResources->BusNumber, RequestedResources->SlotNumber, DeviceObject, BCTL_SET_DEVICE_RESOURCES, *AllocatedResources, &requiredSize, NULL, (PSLOT_CONTROL_COMPLETION)NULL ); if (NT_SUCCESS(status)) { // // If configuration space was updated successfully, change our registry data. // KeEnterCriticalRegion(); ExAcquireResourceExclusive(&PpRegistryDeviceResource, TRUE); status = IopServiceInstanceToDeviceInstance ( NULL, &DeviceHandler->ServiceKeyName, DeviceHandler->InstanceNumber, NULL, &handle, KEY_ALL_ACCESS ); if (NT_SUCCESS(status)) { // // Set Configuration = data entry to caller supplied resources. // PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_CONFIGURATION); ZwSetValueKey(handle, &unicodeName, TITLE_INDEX_VALUE, REG_RESOURCE_LIST, *AllocatedResources, requiredSize ); ZwClose(handle); } ExReleaseResource(&PpRegistryDeviceResource); KeLeaveCriticalRegion(); } #endif // 0 status = STATUS_SUCCESS; exit: if (ioResources) { ExFreePool(ioResources); } if (adjustedIoResources) { ExFreePool(adjustedIoResources); } exit0: RtlFreeUnicodeString(&fullServiceName); return status; } #endif // _PNP_POWER_ NTSTATUS IoAssignResources ( IN PUNICODE_STRING RegistryPath, IN PUNICODE_STRING DriverClassName OPTIONAL, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PIO_RESOURCE_REQUIREMENTS_LIST RequestedResources, IN OUT PCM_RESOURCE_LIST *pAllocatedResources ) /*++ Routine Description: This routine takes an input request of RequestedResources, and returned allocated resources in pAllocatedResources. The allocated resources are automatically recorded in the registry under the ResourceMap for the DriverClassName/DriverObject/DeviceObject requestor. Arguments: RegistryPath For a simple driver, this would be the value passed to the drivers initialization function. For drivers call IoAssignResources with multiple DeviceObjects are responsible for passing in a unique RegistryPath for each object. The registry path is checked for: RegitryPath: AssignedSystemResources. AssignSystemResources is of type REG_RESOURCE_REQUIREMENTS_LIST If present, IoAssignResources will attempt to use these settings to satisify the requested resources. If the listed settings do not conform to the resource requirements, then IoAssignResources will fail. Note: IoAssignResources may store other internal binary information in the supplied RegisteryPath. DriverObject: The driver object of the caller. DeviceObject: If non-null, then requested resoruce list refers to this device. If null, the requested resource list refers to the driver. DriverClassName Used to partition allocated resources into different device classes. RequestedResources A list of resources to allocate. Allocated resources may be appended or freed by re-invoking IoAssignResources with the same RegistryPath, DriverObject and DeviceObject. (editing requirements on a resource list by using sucessive calls is not preferred driver behaviour). AllocatedResources Returns the allocated resources for the requested resource list. Note that the driver is responsible for passing in a pointer to an uninitialized pointer. IoAssignResources will initialize the pointer to point to the allocated CM_RESOURCE_LIST. The driver is responisble for returning the memory back to pool when it is done with them structure. Return Value: The status returned is the final completion status of the operation. --*/ { PDIR_RESREQ_LIST Dir; USED_HEAP DirHeap; PIO_RESOURCE_REQUIREMENTS_LIST IoResources; PKEY_VALUE_PARTIAL_INFORMATION PartInf; UNICODE_STRING unicodeString; ULONG i, busflags, len; PDIR_RESOURCE_LIST CurList; NTSTATUS status; BOOLEAN flag; BOOLEAN SemaphoreOwned; #if DBG PSZ DebugString = NULL; #endif PAGED_CODE(); SemaphoreOwned = FALSE; IoResources = NULL; Dir = NULL; if (pAllocatedResources) { *pAllocatedResources = NULL; } KeEnterCriticalRegion( ); // // Copy input structure & let hal have a crack at it // if (RequestedResources) { status = IopAssignResourcesPhase1 (RequestedResources, &IoResources); CHECK_STATUS (status, "IopAssignResourcesPhase1 failed"); } // // Build a resource directory from the requested list // status = IopBuildResourceDir (NULL, &Dir, IoResources); if (!NT_SUCCESS(status)) { if (IoResources) { ExFreePool (IoResources); } CHECK_STATUS (status, "RequestedResources could no be parsed"); } // // put IoResources onto allocated heap list // if (IoResources) { DirHeap.FreeHeap = (PVOID) IoResources; PushEntryList (&Dir->AllocatedHeap, &DirHeap.FreeLink); } // // allocate a scratch buffer // Dir->Buffer = (PWSTR) IopAllocateDirPool (Dir, BUFFERSIZE); if (!Dir->Buffer) { status = STATUS_INSUFFICIENT_RESOURCES; CHECK_STATUS (status, "No memory"); } // // Get handles to registry keys: // HRESOURCE_MAP // HDEVICE_STORAGE // HCURRENT_CONTROL_SET // HSYSTEMRESOURCES // HBUSVALUES // HORDERING // HRESERVEDRESOURCES // // // Open resource map // status = IopOpenRegistryKey ( &Dir->RegHandle[HRESOURCE_MAP], NULL, &CmRegistryMachineHardwareResourceMapName, KEY_READ | KEY_WRITE, TRUE ); CHECK_STATUS (status, "No ResourceMap"); // // Open owner map // status = IopOpenRegistryKey ( &Dir->RegHandle[HOWNER_MAP], NULL, &CmRegistryMachineHardwareOwnerMapName, KEY_READ | KEY_WRITE, TRUE ); CHECK_STATUS (status, "No OwnerMap"); // // Open up storage location for this Device/Driver in the registry // status = IopOpenRegistryKey ( &Dir->RegHandle[HDEVICE_STORAGE], NULL, RegistryPath, KEY_READ | KEY_WRITE, TRUE ); CHECK_STATUS (status, "RegistryPath parameter incorrect"); // // Open up current control set // status = IopOpenRegistryKey ( &Dir->RegHandle[HCURRENT_CONTROL_SET], NULL, &CmRegistryMachineSystemCurrentControlSet, KEY_READ | KEY_WRITE, FALSE ); CHECK_STATUS (status, "No CurrentControlSet?"); // // Open up ...Control\SystemResources // RtlInitUnicodeString (&unicodeString, IopWstrSystemResources); status = IopOpenRegistryKey ( &Dir->RegHandle[HSYSTEMRESOURCES], Dir->RegHandle[HCURRENT_CONTROL_SET], &unicodeString, KEY_READ | KEY_WRITE, FALSE ); CHECK_STATUS (status, "SystemResources not found"); // // Open up ...SystemResources\BusValues // RtlInitUnicodeString (&unicodeString, IopWstrBusValues); status = IopOpenRegistryKey ( &Dir->RegHandle[HBUSVALUES], Dir->RegHandle[HSYSTEMRESOURCES], &unicodeString, KEY_READ, FALSE ); CHECK_STATUS (status, "BusValues not found"); // // Open up ...SystemResources\AssignmentOrdering // RtlInitUnicodeString (&unicodeString, IopWstrAssignmentOrdering); status = IopOpenRegistryKey ( &Dir->RegHandle[HORDERING], Dir->RegHandle[HSYSTEMRESOURCES], &unicodeString, KEY_READ, FALSE ); CHECK_STATUS (status, "AssignmentOrdering not found"); // // Open up ...SystemResources\ReservedResources // RtlInitUnicodeString (&unicodeString, IopWstrReservedResources); status = IopOpenRegistryKey ( &Dir->RegHandle[HRESERVEDRESOURCES], Dir->RegHandle[HSYSTEMRESOURCES], &unicodeString, KEY_READ, FALSE ); CHECK_STATUS (status, "ReservedResources not found"); // // If no resource list, then caller wishes to free allocated resources // Else caller wishes to allocate resources // if (RequestedResources == NULL) { // // Lookup callers requested resources which are being freed // RtlInitUnicodeString( &unicodeString, IopWstrRequestedResources ); status = ZwQueryValueKey( Dir->RegHandle[HDEVICE_STORAGE], &unicodeString, KeyValuePartialInformation, NULL, 0, &len ); if (status == STATUS_BUFFER_TOO_SMALL) { PartInf = (PKEY_VALUE_PARTIAL_INFORMATION) IopAllocateDirPool (Dir, len); if (!PartInf) { status = STATUS_INSUFFICIENT_RESOURCES; CHECK_STATUS (status, "No memory"); } status = ZwQueryValueKey( Dir->RegHandle[HDEVICE_STORAGE], &unicodeString, KeyValuePartialInformation, PartInf, len, &len ); } if (!NT_SUCCESS(status)) { DBGMSG ("IoAllocateResources - could not find copy of requested resource to free\n"); } else { IoResources = (PIO_RESOURCE_REQUIREMENTS_LIST) PartInf->Data; flag = IopSlotResourceOwner ( Dir, DriverObject, DeviceObject, IoResources, FALSE // Adding owner ); if (!flag) { status = STATUS_INVALID_OWNER; CHECK_STATUS (status, "(free resources) not owner of slot"); } } // // Release the the acquired resources // i = 0; if (!DeviceObject) { status = IopReportResourceUsage ( DriverClassName, DriverObject, // DriverObject (PCM_RESOURCE_LIST) &i, // DriverList sizeof (i), // DriverListSize DeviceObject, NULL, // DeviceList 0, // DeviceListSize FALSE, // override conflict &flag // conflicted detected ); } else { status = IopReportResourceUsage ( DriverClassName, DriverObject, // DriverObject NULL, // DriverList 0, // DriverListSize DeviceObject, (PCM_RESOURCE_LIST) &i, // DeviceList sizeof (i), // DeviceListSize FALSE, // override conflict &flag // conflicted detected ); } CHECK_STATUS (status, "free resources failed"); } else { flag = IopSlotResourceOwner ( Dir, DriverObject, DeviceObject, IoResources, TRUE // Adding owner ); if (!flag) { status = STATUS_INVALID_OWNER; CHECK_STATUS (status, "not owner of slot"); } #ifndef _PNP_POWER_ // // The copy of the requested resources is stored under // new location : ServiceKeyName\ResourceInformation // Driver\DeviceName.RequestedResources // // // Put a copy of the driver's request into the registry // RtlInitUnicodeString( &unicodeString, IopWstrRequestedResources ); status = ZwSetValueKey( Dir->RegHandle[HDEVICE_STORAGE], &unicodeString, 0L, REG_RESOURCE_REQUIREMENTS_LIST, Dir->IoResourceReq, Dir->IoResourceReq->ListSize ); CHECK_STATUS (status, "SetValueKey error"); #endif // // Sort the request descriptors such that all alternative descriptor // options are grouped by CmResourceType. // IopSortDescriptors (Dir); #if IDBG DbgPrint ("IoAssignResources: Dump of requested resource list\n"); IopDumpIoResourceDir (Dir); #endif // // Check for user assigned resources in RegistryPath // IoResources = IopGetResourceReqRegistryValue ( Dir, Dir->RegHandle[HDEVICE_STORAGE], IopWstrAssignedResources ); if (IoResources) { // // Build directory out of user's assignments // status = IopBuildResourceDir (Dir, &Dir->UserDir, IoResources); CHECK_STATUS (status, "Device AssignedResources could not be parsed"); status = IopCatagorizeDescriptors (Dir->UserDir); CHECK_STATUS (status, "Device AssignedResources could not be catagorized"); } // // Find bus specific ordering // IoResources = NULL; status = IopLookupBusStringFromID ( Dir->RegHandle[HBUSVALUES], Dir->IoResourceReq->InterfaceType, Dir->Buffer, BUFFERSIZE - 10, &busflags ); CHECK_STATUS (status, "Bus identifier unknown"); // // First try BusName_# // for (i=0; Dir->Buffer[i]; i++) ; swprintf (Dir->Buffer+i, L"_%d", Dir->IoResourceReq->BusNumber); IoResources = IopGetResourceReqRegistryValue ( Dir, Dir->RegHandle[HORDERING], Dir->Buffer ); if (!IoResources) { // // Use just BusName // Dir->Buffer[i] = 0; IoResources = IopGetResourceReqRegistryValue ( Dir, Dir->RegHandle[HORDERING], Dir->Buffer ); } if (!IoResources) { status = STATUS_UNSUCCESSFUL; CHECK_STATUS (status, "Bus ordering information not found"); } // // Build a directory & catagorize the resource ordering information for // the bus. // status = IopBuildResourceDir (Dir, &Dir->BusDir, IoResources); CHECK_STATUS (status, "Bus ordering information could not be parsed"); status = IopCatagorizeDescriptors (Dir->BusDir); CHECK_STATUS (status, "Bus ordering information could not be catagorized"); // // Serialize with other resource reporting & assignments // status = KeWaitForSingleObject( &IopRegistrySemaphore, DelayExecution, KernelMode, FALSE, NULL ); CHECK_STATUS (status, "Wait for RegistrySemaphore"); SemaphoreOwned = TRUE; // // Read all currently allocated resources into memory // status = IopAssignResourcesPhase2 (Dir, DriverClassName, DriverObject, DeviceObject); CHECK_STATUS (status, "Phase2 failed"); // // Make resource assignments // CurList = IopAssignResourcesPhase3 (Dir); if (!CurList) { status = STATUS_CONFLICTING_ADDRESSES; IopLogConflict (DriverObject, Dir, status); #if _PNP_POWER_ // // After logging the conflicts, try to resolve the them. // CurList = IopResolveConflicts(Dir); if (!CurList) { status = STATUS_CONFLICTING_ADDRESSES; } else { status = STATUS_SUCCESS; } #endif CHECK_STATUS (status, "Resource assignments failed"); } // // Build CmResourceList from assignments // *pAllocatedResources = IopAssignResourcesPhase4 (Dir, CurList, &len); if (!*pAllocatedResources) { status = STATUS_INSUFFICIENT_RESOURCES; CHECK_STATUS (status, "Phase4 failed"); } // // Report consumed resources.. // if (!DeviceObject) { status = IopReportResourceUsage ( DriverClassName, DriverObject, // DriverObject *pAllocatedResources, // DriverList len, // DriverListSize DeviceObject, // DeviceObject NULL, // DeviceList 0, // DeviceListSize FALSE, // override conflict &flag // conflicted detected ); } else { status = IopReportResourceUsage ( DriverClassName, DriverObject, // DriverObject NULL, // DriverList 0, // DriverListSize DeviceObject, *pAllocatedResources, // DeviceList len, // DeviceListSize FALSE, // override conflict &flag // conflicted detected ); } if (NT_SUCCESS(status) && flag) { // // IopReportResourceUsage saw a conflict? // status = STATUS_CONFLICTING_ADDRESSES; #if _PNP_POWER_ } else if (NT_SUCCESS(status)) { // // Save all the resource information to registry. We may need it // again to solve conflicts. // IopRecordAssignInformation(Dir, DriverClassName, DriverObject, DeviceObject, CurList); #endif } } CHECK_STATUS (status, "IoReportResourceUsage failed"); Exit: if (!NT_SUCCESS(status)) { #if DBG DbgPrint ("IoAssignResources failed %08x - %s\n", status, DebugString); #endif if (pAllocatedResources && *pAllocatedResources) { ExFreePool (*pAllocatedResources); } } // // Free memory, handles, and other any other obtain resources // IopFreeResourceDir (Dir); if (SemaphoreOwned) { KeReleaseSemaphore( &IopRegistrySemaphore, 0, 1, FALSE ); } KeLeaveCriticalRegion( ); return status; } BOOLEAN IopSlotResourceOwner ( IN PDIR_RESREQ_LIST Dir, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject OPTIONAL, IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources, IN BOOLEAN AddOwner ) { ULONG busflags, len, i; PWCHAR KeyName; UNICODE_STRING KeyString, ValueString; POBJECT_NAME_INFORMATION ObjectName; PKEY_VALUE_PARTIAL_INFORMATION PartInf; BOOLEAN Match; NTSTATUS status; PAGED_CODE(); KeyName = ExAllocatePool (PagedPool, BUFFERSIZE * 2); if (!KeyName) { return FALSE; } ObjectName = (POBJECT_NAME_INFORMATION) ((PCHAR)KeyName + BUFFERSIZE); Match = TRUE; // // Find bus specific ordering // status = IopLookupBusStringFromID ( Dir->RegHandle[HBUSVALUES], IoResources->InterfaceType, KeyName, BUFFERSIZE-40, &busflags ); // // Does this bus have unique SlotNumber ownership? // if (NT_SUCCESS(status) && (busflags & 0x1)) { // // Build keyname // for (i=0; KeyName[i]; i++) ; swprintf (KeyName+i, L"_%d_%x", IoResources->BusNumber, IoResources->SlotNumber); RtlInitUnicodeString( &KeyString, KeyName ); // // Build valuename // status = ObQueryNameString( DeviceObject ? (PVOID) DeviceObject : (PVOID) DriverObject, ObjectName, BUFFERSIZE, &len ); if (NT_SUCCESS(status)) { // // Look it up // PartInf = (PKEY_VALUE_PARTIAL_INFORMATION) Dir->Buffer; status = ZwQueryValueKey ( Dir->RegHandle[HOWNER_MAP], &KeyString, KeyValuePartialInformation, Dir->Buffer, BUFFERSIZE, &len ); if (!NT_SUCCESS(status)) { // // No owner listed, see if we should add ourselves // if (AddOwner) { // // Add the key // ZwSetValueKey ( Dir->RegHandle[HOWNER_MAP], &KeyString, 0L, REG_SZ, ObjectName->Name.Buffer, ObjectName->Name.Length ); } } else { // // Owner is listed, see if it's us // ValueString.Buffer = (PWCHAR) PartInf->Data; ValueString.Length = (USHORT) len - (USHORT) FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); ValueString.MaximumLength = ValueString.Length; Match = RtlEqualUnicodeString (&ObjectName->Name, &ValueString, TRUE); if (Match && !AddOwner) { // // Free ownership // ZwDeleteValueKey( Dir->RegHandle[HOWNER_MAP], &KeyString); } } } } ExFreePool (KeyName); return Match; } /*++ Routine Description: IO_DESC_MIN - Returns the descriptor's MIN,MAX or ALIGMENT requirements IO_DESC_MAX --*/ INLINE LONGLONG IO_DESC_MIN ( IN PIO_RESOURCE_DESCRIPTOR Desc ) { LONGLONG li; switch (Desc->Type) { case CmResourceTypePort: li = Desc->u.Port.MinimumAddress.QuadPart; break; case CmResourceTypeMemory: li = Desc->u.Memory.MinimumAddress.QuadPart; break; case CmResourceTypeInterrupt: li = Desc->u.Interrupt.MinimumVector; break; case CmResourceTypeDma: li = Desc->u.Dma.MinimumChannel; break; } return li; } INLINE LONGLONG IO_DESC_MAX ( IN PIO_RESOURCE_DESCRIPTOR Desc ) /*++ Routine Description: Returns the IO_RESORUCE_DESCRIPTOR's maximum value --*/ { LONGLONG li; switch (Desc->Type) { case CmResourceTypePort: li = Desc->u.Port.MaximumAddress.QuadPart; break; case CmResourceTypeMemory: li = Desc->u.Memory.MaximumAddress.QuadPart; break; case CmResourceTypeInterrupt: li = Desc->u.Interrupt.MaximumVector; break; case CmResourceTypeDma: li = Desc->u.Dma.MaximumChannel; break; } return li; } BOOLEAN IopGenNextValidResourceList ( IN ULONG level, IN PDIR_RESOURCE_LIST CurList, IN PDIR_RESREQ_LIST Dir ) /*++ Routine Description: Attempts to find a setting for every required resource in the CurList Arguments: level - Index to which required resource list to start finding resources from CurList - List of required resources being processed Dir - The top directory of resources PassNo - The pass # 1 - Preferred settings only 2 - Available settings 3 - Available settings, find conflict to report Return Value TRUE if all required resources found available settings --*/ { ULONG collisionlevel; BOOLEAN flag; #if _PNP_POWER_ ULONG i; #endif do { if (level > CurList->LastLevel) { CurList->LastLevel = level; } flag = IopGenNextValidDescriptor ( level, CurList, Dir, &collisionlevel ); if (flag == FALSE) { // // Could not generate a valid descriptor setting // if (level == 0 || collisionlevel == -1) { // // No more settings // CurList->FailedLevel = level; return FALSE; } // // Backup to the collision level and try anew // while (level > collisionlevel) { CurList->RequiredResource[level]->CurLoc = 0; CurList->RequiredResource[level]->RunLen = 0; level--; } continue; } #if _PNP_POWER_ if (CurList->RequiredResource[level]->PassNo == 6) { // // if we returned back to here from pass 6, we just resolved a // resource conflict for current level. It is possible that the // reconfigured driver took the resouce which was selected by earlier // level. We must reset level back to 0 and reset PassNo of // current level to 2 to restart the resource assignment. // CurList->RequiredResource[level]->PassNo = 2; i=0; while (i <= level) { CurList->RequiredResource[i]->CurLoc = 0; CurList->RequiredResource[i]->RunLen = 0; i++; } level = 0; continue; } #endif if (CurList->RequiredResource[level]->PassNo == 1 && CurList->RequiredResource[level]->CurPref < CurList->RequiredResource[level]->BestPref) { // // First time through don't mess with unpreferred settings, continue // looking at this level // continue; } // // Go to next level // level++; } while (level < CurList->NoRequiredResources); // // Determine list's preference // (only used on PassNo > 1 since PassNo == 1 only suceedes when // preferred settings are used) // CurList->CurPref = 0; for (level = 0; level < CurList->NoRequiredResources; level++) { CurList->CurPref += CurList->RequiredResource[level]->CurPref; } // // Got a setting for each requested resource, return TRUE // return TRUE; } BOOLEAN IopGenNextValidDescriptor ( IN ULONG level, IN PDIR_RESOURCE_LIST CurList, IN PDIR_RESREQ_LIST Dir, OUT PULONG collisionlevel ) /*++ Routine Description: Arguments: Return Value TRUE if descriptor setting was found FALSE if no setting found --*/ { PDIR_REQUIRED_RESOURCE Res, CRes; PIO_RESOURCE_DESCRIPTOR *Desc, DescTmp; LONGLONG BAddr, EAddr; LONGLONG NBAddr; LONGLONG DescMax, MinAddr, LiILen, LiELen, LiTmp; LONGLONG NAddr, BusMax, BusMin, PBAddr; ULONG indx, j, k, NBLoc; ULONG DescLen, Align, len; BOOLEAN NBSet, flag, flag2; LONG Preference, NPref; UCHAR TType, NTType; TENTRY Trans, NTrans; #if _PNP_POWER_ PRELOCATED_TENTRIES pResourceRecord; PTENTRY pConflictTrans, pNewTrans; UCHAR newTransType; #endif Res = CurList->RequiredResource[level]; *collisionlevel = (ULONG) -1; // assume no collision NBSet = FALSE; do { Desc = &Res->IoResourceDescriptor[Res->CurLoc]; if (!Res->RunLen) { if (Res->CurLoc >= Res->NoAlternatives) { // // No more runs // return FALSE; } // // Get number of alternatives which are of the same type // (alternatives have been sorted into types). // Res->Type = Desc[0]->Type; for (j=Res->CurLoc; j < Res->NoAlternatives; j++) { if (Res->Type != Res->IoResourceDescriptor[j]->Type) { break; } } Res->RunLen = j - Res->CurLoc; if (!Res->RunLen) { // // Out of alternatives for this resource // return FALSE; } // // Start at beginning of bus options // Res->CurBusLoc = 0; DescTmp = Dir->BusDir->Alternative->ResourceByType[Res->Type]->IoResourceDescriptor[0]; if (!DescTmp) { // // There are no bus settings for this type of resource // return FALSE; } Res->CurBusMin = IO_DESC_MIN (DescTmp); Res->CurBusMax = IO_DESC_MAX (DescTmp); NAddr = Res->CurBusMax; } else { // // Decrease current value by one - this will cause this // function to find the next acceptable value. // NAddr = Res->CurBAddr - 1; } // // Return the next available address from NAddr // DescLen = Res->RunLen; BusMax = Res->CurBusMax; BusMin = Res->CurBusMin; NBAddr = 0; for (; ;) { // // Loop for each descriptor in this run and pick the numerical highest // value available for this resource // for (indx=0; indx < DescLen ; indx++) { // // Set len, Align, MinAddr, DescMax // DescTmp = Desc[indx]; switch (DescTmp->Type) { case CmResourceTypePort: len = DescTmp->u.Port.Length; Align = DescTmp->u.Port.Alignment; MinAddr = DescTmp->u.Port.MinimumAddress.QuadPart; DescMax = DescTmp->u.Port.MaximumAddress.QuadPart; break; case CmResourceTypeMemory: len = DescTmp->u.Memory.Length; Align = DescTmp->u.Memory.Alignment; MinAddr = DescTmp->u.Memory.MinimumAddress.QuadPart; DescMax = DescTmp->u.Memory.MaximumAddress.QuadPart; break; case CmResourceTypeInterrupt: len = 1; Align = 1; MinAddr = DescTmp->u.Interrupt.MinimumVector; DescMax = DescTmp->u.Interrupt.MaximumVector; break; case CmResourceTypeDma: len = 1; Align = 1; MinAddr = DescTmp->u.Dma.MinimumChannel; DescMax = DescTmp->u.Dma.MaximumChannel; break; } // // MinAddr is the largest of Descriptor-MinAddr, Bus-MinAddr, or // NextBest-MinAddr. Don't go below the last MinAddr (NBAddr). // So the search is from NAddr -to-> NBAddr // if (BusMin > MinAddr) { MinAddr = BusMin; } if (NBAddr > MinAddr) { MinAddr = NBAddr; } BAddr = NAddr; LiELen = len; // Exclusive length LiILen = len - 1; // Inclusive length // // Set initial preference // Preference = 0; if (Res->PassNo == 1) { if (DescTmp->Option & IO_RESOURCE_PREFERRED) { // Account for device's preference durning first pass Preference = 1; } else if (Res->BestPref) { // Some resource in this list has a prefernce, but it's not // this one. Since this is the PassNo == 1 skip non-preferred. continue; } } // // Loop while BAddr being tested is above MinAddr // while (BAddr >= MinAddr) { EAddr = BAddr + LiILen; if (EAddr > DescMax) { // // The ending address is above the requested limit // compute the best possible beginning address // BAddr = DescMax - LiILen; continue; } if (EAddr > BusMax) { // // The ending address is above the bus'es limit // compute best possible beginning address // BAddr = BusMax - LiILen; continue; } // // Verify selection is within any user supplied requirements // (this is from RegistryPath\AssignResources) // if (Dir->UserDir) { CRes = Dir->UserDir->Alternative->ResourceByType[Res->Type]; flag = FALSE; PBAddr = -1; for (j=0; j < CRes->NoAlternatives; j++) { LiTmp = IO_DESC_MIN (CRes->IoResourceDescriptor[j]); if (BAddr < LiTmp) { // // Beginning address is before user's range, check // next descriptor // continue; } LiTmp = IO_DESC_MAX (CRes->IoResourceDescriptor[j]); if (EAddr > LiTmp) { // // Ending address is above user's range. // Check for new BAddr to continue from // LiTmp = LiTmp - LiILen; if (LiTmp > PBAddr && LiTmp < BAddr) { // // Update next possible setting // PBAddr = LiTmp; } continue; } // // Within user's requested range // flag = TRUE; break; } if (!flag) { BAddr = PBAddr; continue; } } // // So far resource looks good - translate it to system global // settings and verify resource is available // LiTmp = 0; switch (Res->Type) { case CmResourceTypePort: case CmResourceTypeMemory: j = k = Res->Type == CmResourceTypePort ? 1 : 0; flag = HalTranslateBusAddress ( Dir->IoResourceReq->InterfaceType, Dir->IoResourceReq->BusNumber, *((PPHYSICAL_ADDRESS) &BAddr), &j, (PPHYSICAL_ADDRESS) &Trans.BAddr ); // precheck alignment on first half if (Align > 1 && (Trans.BAddr & 0xffffffff00000000) == 0) { RtlEnlargedUnsignedDivide ( *((PULARGE_INTEGER) &Trans.BAddr), Align, (PULONG) &LiTmp); if (LiTmp & 0xffffffff) { break; // alignment is off - don't bother with second translation } } flag2 = HalTranslateBusAddress ( Dir->IoResourceReq->InterfaceType, Dir->IoResourceReq->BusNumber, *((PPHYSICAL_ADDRESS) &EAddr), &k, (PPHYSICAL_ADDRESS) &Trans.EAddr ); TType = j == 1 ? CmResourceTypePort : CmResourceTypeMemory; Trans.Affinity = (KAFFINITY) -1; if (flag == FALSE || flag2 == FALSE || j != k) { // HalAdjustResourceList should ensure that the returned range // for the bus is within the bus limits and no translation // within those limits should ever fail DBGMSG ("IopGenNextValidDescriptor: Error return for HalTranslateBusAddress\n"); return FALSE; } break; case CmResourceTypeInterrupt: TType = CmResourceTypeInterrupt; Trans.Affinity = 0; Trans.BAddr = HalGetInterruptVector ( Dir->IoResourceReq->InterfaceType, Dir->IoResourceReq->BusNumber, (ULONG) BAddr, // bus level (ULONG) BAddr, // bus vector (PKIRQL) &j, // translated level &Trans.Affinity ); Trans.EAddr = Trans.BAddr; if (Trans.Affinity == 0) { // skip vectors which can not be translated LiTmp = 1; } break; case CmResourceTypeDma: TType = CmResourceTypeDma; Trans.BAddr = BAddr; Trans.EAddr = EAddr; Trans.Affinity = (KAFFINITY) -1; break; default: DBGMSG ("IopGenNextValidDescriptor: Invalid resource type\n"); return FALSE; } // // Check bias from translation // if (LiTmp != 0) { // move to next address BAddr = BAddr - LiTmp; continue; } // // Check alignment restrictions // if (Align > 1) { if ((Trans.BAddr & 0xffffffff00000000) == 0) { RtlEnlargedUnsignedDivide ( *((PULARGE_INTEGER) &Trans.BAddr), Align, (PULONG) &LiTmp); } else { RtlExtendedLargeIntegerDivide ( *((PLARGE_INTEGER) &Trans.BAddr), Align, (PULONG) &LiTmp); } if (LiTmp != 0) { // // Starting address not on proper alignment, move to next // aligned address // BAddr = BAddr - LiTmp; continue; } } // // Check for collision with other settings being considered // for (j=0; j < level; j++) { if (CurList->RequiredResource[j]->TType == TType) { CRes = CurList->RequiredResource[j]; if (DoesTEntryCollide (Trans, CRes->Trans)) { // collision break; } } } if (j < level) { // // Current BAddr - EAddr collides with CRes selection // if (j < *collisionlevel) { // // If we fail, back up to this level // *collisionlevel = j; } // // Try BAddr just best address before collision range // BAddr = CRes->CurBAddr - LiELen; continue; } #if _PNP_POWER_ // // Avoid picking up the resources in In-Processed list for pass // no >= 4. // if (Res->PassNo >= 4) { j = IopFindCollisionInRelocatedList (&Trans, IopInProcessedConflicts, &pConflictTrans); if (j) { BAddr = BAddr - j; continue; } } #endif // // Check InUse system resources to verify this range is available. // #if _PNP_POWER_ j = IopFindCollisionInTList (&Trans, Dir->InUseResources.ByType[TType], &pConflictTrans); #else j = IopFindCollisionInTList (&Trans, Dir->InUseResources.ByType[TType]); #endif if (j) { if (Res->PassNo == 3) { // // Track this collision // IopPickupCollisionInTList ( CurList, Res->Type, BAddr, &Trans, Dir->InUseResources.ByType[TType] ); } #if _PNP_POWER_ else if (Res->PassNo > 4) { // // Try to resolve the conflict by relocating the resources // consumed by other drivers. // if (IopRelocateResource ( Dir, CurList, TType, &Trans, pConflictTrans)) { if (Res->PassNo == 6) { // // Mark conflict entry in in-used list to be "Deleted" // if at pass 6. // pConflictTrans->Flags = TENTRY_FLAGS_REMOVED; } Res->CurBAddr = BAddr; Res->TType = TType; Res->Trans = Trans; Res->CurBLoc = Res->CurLoc + indx; return TRUE; } } #endif // _PNP_POWER_ // // This range collides with a resource which is already in use. // Moving begining address to next possible setting // BAddr = BAddr - j; continue; } // // Check to see if this resource selection is being shared // #if _PNP_POWER_ j = IopFindCollisionInTList (&Trans, Dir->InUseResources.ByType[TType], &pConflictTrans); #else j = IopFindCollisionInTList (&Trans, Dir->InUseSharableResources.ByType[TType]); #endif if (j) { // // Current range collided with a resource which is already in use, // but is sharable. If the current required resource is not sharable, // then skip this range; otherwise, reduce the preference for this setting. // if (Res->PassNo == 1 || Desc[indx]->ShareDisposition != CmResourceShareShared) { if (Res->PassNo == 3) { // // Track this collision // IopPickupCollisionInTList ( CurList, Res->Type, BAddr, &Trans, Dir->InUseSharableResources.ByType[TType] ); } // required resource can't be shared, move to next possible setting or // this is the Pass#1 and we don't bother with non-preferred settings BAddr = BAddr - j; continue; } Preference -= 4; } // // Check to see if this resource reserved, but sharable // #if _PNP_POWER_ j = IopFindCollisionInTList (&Trans, Dir->InUseResources.ByType[TType], &pConflictTrans); #else j = IopFindCollisionInTList (&Trans, Dir->ReservedSharableResources.ByType[TType]); #endif if (j) { // // Current range collosided with a resource which is in the // ReservedResource list, but is marked sharable. These resources // are treated as non-preferred regions. // if (Res->PassNo == 1) { // don't bother with non-preferred settings on the first pass. BAddr = BAddr - j; continue; } Preference -= 2; } // // BAddr - EAddr is a good selection // (BAddr is greater than NBAddr) // NBSet = TRUE; NBAddr = BAddr; NTType = TType; NTrans = Trans; NPref = Preference; NBLoc = Res->CurLoc + indx; break; // check next selector in run } // next BAddr } // next descriptor in run if (NBSet) { // SUCCESS We have a hit break; } // // No setting so far, move to next bus ordering descriptor // Res->CurBusLoc++; CRes = Dir->BusDir->Alternative->ResourceByType[Res->Type]; if (Res->CurBusLoc >= CRes->NoAlternatives) { // // no more bus ordering descriptors, move to next ResRun // Res->CurLoc += Res->RunLen; Res->RunLen = 0; break; } DescTmp = CRes->IoResourceDescriptor[Res->CurBusLoc]; Res->CurBusMin = IO_DESC_MIN (DescTmp); Res->CurBusMax = IO_DESC_MAX (DescTmp); BusMin = Res->CurBusMin; BusMax = Res->CurBusMax; NAddr = Res->CurBusMax; } // next bus ordering descriptor } while (!NBSet); // // We have a setting for this resource. Remember it and return. // Res->TType = NTType; // used to detect internal conflicts of translated values Res->Trans = NTrans; // " Res->CurPref = NPref; // Return prefernce of setting Res->CurBAddr = NBAddr; // Return raw BAddr of resource (used by Phase3&4) Res->CurBLoc = NBLoc; // Return location of resource (used by Phase3&4) return TRUE; } ULONG IopFindCollisionInTList ( IN PTENTRY SEntry, #if _PNP_POWER_ IN PLTENTRY List, OUT PTENTRY *ConflictEntry #else IN PLTENTRY List #endif ) /*++ Routine Description: Checks to see if there's a collision between the source TENTRY and the list of TENTRIES passed by PLTENTRY. Arguments: Return Value Returns the skew amount required to continue searching for next possible setting and a pointer to the conflicted entry. A zero skew means no collision occured. --*/ { LONGLONG LiTmp; TENTRY Source; ULONG i, j; Source = *SEntry; while (List) { j = List->CurEntries; for (i=0; i < j; i++) { SEntry = List->Table+i; #if _PNP_POWER_ if (SEntry->Flags != TENTRY_FLAGS_REMOVED) { #endif if (DoesTEntryCollide (Source, *SEntry)) { LiTmp = Source.EAddr - SEntry->BAddr; #if _PNP_POWER_ *ConflictEntry = SEntry; #endif return (ULONG) LiTmp + 1; } #if _PNP_POWER_ } #endif } List = List->Next; } return 0; } #if _PNP_POWER_ PDIR_RESOURCE_LIST IopResolveConflicts ( IN PDIR_RESREQ_LIST Dir ) /*++ Routine Description: This routine tries to satisfy the current resource settings by relocating resources among drivers. Arguments: Dir - supplies a pointer to the DIR_RESREQ_LIST for the request. Returned Value: A DIR_RESOURCE_LIST is returned if the relocation succeeded. Else a value of NULL is returned. --*/ { PDIR_RESOURCE_LIST CurList; ULONG i; PRECONFIGURED_DRIVER tmp; BOOLEAN flag; BOOLEAN success = FALSE; NTSTATUS status; for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) { // // Look for settings - set LastFailed level to pass 6 and try to resolve // the conflicts by relocating resources among the drivers. // while (1) { for (i = CurList->FailedLevel; i < CurList->NoRequiredResources; i++) { CurList->RequiredResource[i]->CurLoc = 0; CurList->RequiredResource[i]->RunLen = 0; CurList->RequiredResource[i]->PassNo = 2; } CurList->RequiredResource[CurList->FailedLevel]->PassNo = 6; success = IopGenNextValidResourceList (CurList->FailedLevel, CurList, Dir); if (CurList->RequiredResource[CurList->FailedLevel]->PassNo == 6 || success) { break; } } while (IopReconfiguredDrivers) { tmp = IopReconfiguredDrivers; if (success) { // // We have successfully resolved the conflicts. Now for // each driver in the IopReconfigDriver List, a Reconfig command is // requested. // i = 0; if (!tmp->DeviceObject) { status = IopReportResourceUsage ( &tmp->DriverClassName, tmp->DriverObject, // DriverObject tmp->CmResourceList, // DriverList tmp->ResourceLength, // DriverListSize tmp->DeviceObject, // DeviceObject NULL, // DeviceList 0, // DeviceListSize TRUE, // override conflict &flag // conflicted detected ); } else { status = IopReportResourceUsage ( &tmp->DriverClassName, tmp->DriverObject, // DriverObject NULL, // DriverList 0, // DriverListSize tmp->DeviceObject, tmp->CmResourceList, // DriverList tmp->ResourceLength, // DeviceListSize TRUE, // override conflict &flag // conflicted detected ); } if (!NT_SUCCESS(status) && status != STATUS_CONFLICTING_ADDRESSES) { #if DBG DbgPrint("ResolveConflict: Report resource usage failed\n"); #endif goto BugCheckExit; } status = IopReconfigureResource(tmp->DriverObject, tmp->DeviceObject, tmp->CmResourceList); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("ResolveConflict: Driver failed to reconfig resources\n"); #endif goto BugCheckExit; } // // Save the resource information to registry. We may need it // again to solve conflicts. // IopRecordAssignInformation(tmp->ReconfiguredDir, &tmp->DriverClassName, tmp->DriverObject, tmp->DeviceObject, tmp->ReconfiguredDir->ListPicked ); } else { // // We have failed to resolve the conflicts. Now for // each driver in the IopReconfigList, a CancelReconfig command is // sent to release the driver. // IopCancelReconfigureResource(tmp->DriverObject, tmp->DeviceObject); } IopReconfiguredDrivers = tmp->Next; ObDereferenceObject(tmp->DriverObject); if (tmp->DeviceObject) { ObDereferenceObject(tmp->DeviceObject); } RtlFreeUnicodeString(&tmp->DriverClassName); if (tmp->CmResourceList) { ExFreePool(tmp->CmResourceList); } ExFreePool(tmp); } // // Clean up and try next list or return success. // IopFreeRelocatedResourceDir(IopRelocatedDirList); IopRelocatedDirList = NULL; IopFreeRelocatedTEntryLists(); if (success) { return CurList; } // Try next resource list } return NULL; BugCheckExit: KeBugCheckEx(PNP_INTERNAL_ERROR, status, 0, 0, 0); } BOOLEAN IopRelocateResource ( IN PDIR_RESREQ_LIST Dir, IN PDIR_RESOURCE_LIST CurList, IN UCHAR TranslatedType, IN PTENTRY ConflictEntry, IN PTENTRY TranslatedEntry ) /*++ Routine Description: This routine tries to satisfy the Resource settings by relocating resources among drivers. Note caller does NOT need to free the returned pNewTranslatedEntry. Arguments: Dir - supplies a pointer to the DIR_RESREQ_LIST for the request. CurList - supplies a pointer to the current DIR_RESOURCE_LIST. Level - Indicates which level of the CurList encountered the conflict. TranslatedType - the resource type. ConflictEntry - supplies a point to a TENTRY which collides with TranslatedEntry. TranslatedEntry - supplies a point to a TENTRY whose resources needs to be relocated. Returned Value: TRUE - succeed otherwise a value of FALSE is returned. --*/ { PRECONFIGURED_DRIVER reconfigDriver, tmp; NTSTATUS status; PDRIVER_OBJECT driverObject = NULL; PDEVICE_OBJECT deviceObject = NULL; PKEY_VALUE_FULL_INFORMATION keyValueInformation; ULONG length, listPicked, collisionLevel; PIO_RESOURCE_REQUIREMENTS_LIST ioResources = NULL; PREG_REQUIRED_RESOURCE_LIST reportedResources = NULL; PDIR_RESREQ_LIST driverDir = NULL, tmpDir; PDIR_RESOURCE_LIST resourceList; PDIR_REQUIRED_RESOURCE reqRes; BOOLEAN found; PCM_RESOURCE_LIST cmResources; UNICODE_STRING driverClassName = {0, 0, NULL}; UNICODE_STRING unicodeValueName; UNICODE_STRING unicodeName1, unicodeName2; HANDLE driverHandle = NULL, resourcesHandle; ULONG i; LONGLONG li; PUSED_HEAP usedHeap; HANDLE deviceHandle; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatus; PFILE_OBJECT fileObject = NULL; UCHAR tmpFlags; POWNER owner; CM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc; PTENTRY trans; PTENTRIESBYTYPE byType; PIO_RESOURCE_DESCRIPTOR ioDesc; // // We need to reconsturct the DIR and all the supporting data structures // for the driver to be relocated. // if (TranslatedEntry->Owner == NULL) { // // Don't know which driver has the resource. Simply return failure. // return FALSE; } if (TranslatedEntry->Flags == TENTRY_FLAGS_BEING_RELOCATED) { // // To avoid infinite loop. // return FALSE; } // // See if the DIR for the relocating resources was built already. // tmpDir = IopRelocatedDirList; while (tmpDir) { if (RtlEqualUnicodeString(&TranslatedEntry->Owner->KeyName, &tmpDir->ReconfiguredDriver->Owner->KeyName, TRUE)){ if (TranslatedEntry->Owner->DeviceName.Length == 0 || RtlEqualUnicodeString(&TranslatedEntry->Owner->DeviceName, &tmpDir->ReconfiguredDriver->Owner->KeyName, TRUE )) { driverDir = tmpDir; break; } } tmpDir = tmpDir->FreeResReqList; } if (!driverDir) { if (TranslatedEntry->Owner->DeviceName.Length > 0) { InitializeObjectAttributes( &objectAttributes, &TranslatedEntry->Owner->DeviceName, 0, (HANDLE) NULL, (PSECURITY_DESCRIPTOR) NULL ); status = NtOpenFile( &deviceHandle, FILE_READ_ATTRIBUTES, &objectAttributes, &ioStatus, 0, FILE_NON_DIRECTORY_FILE ); if (!NT_SUCCESS( status )) { return FALSE; } // // The device object was located, so convert the handle into a pointer // so that the device object itself can be examined. // status = ObReferenceObjectByHandle( deviceHandle, 0, IoFileObjectType, KernelMode, (PVOID *) &fileObject, NULL ); deviceObject = fileObject->DeviceObject; NtClose( deviceHandle ); if (!NT_SUCCESS(status)) { return FALSE; } } // // Read ClassName and requested resources information from // driver's ServiceKeyName\RequestedResources key. // RtlInitUnicodeString(&unicodeName2, L"\\Driver\\"); IopConcatenateUnicodeStrings(&unicodeName1, &unicodeName2, &TranslatedEntry->Owner->KeyName); // // BUGBUG - Can NOT do this!! Will be changed soon... // status = ObReferenceObjectByName(&unicodeName1, OBJ_CASE_INSENSITIVE, NULL, 0, IoDriverObjectType, KernelMode, NULL, &driverObject ); RtlFreeUnicodeString(&unicodeName1); if (!NT_SUCCESS(status)) { goto exit1; } status = IopOpenRegistryKey(&resourcesHandle, NULL, &CmRegistryMachineSystemCurrentControlSetServices, KEY_ALL_ACCESS, FALSE ); if (!NT_SUCCESS(status)) { goto exit1; } status = IopOpenRegistryKey(&driverHandle, resourcesHandle, &driverObject->DriverExtension->ServiceKeyName, KEY_ALL_ACCESS, FALSE ); ZwClose(resourcesHandle); if (!NT_SUCCESS(status)) { goto exit1; } RtlInitUnicodeString(&unicodeName2, L"ResourceInformation"); status = IopOpenRegistryKey(&resourcesHandle, driverHandle, &unicodeName2, KEY_ALL_ACCESS, FALSE ); if (!NT_SUCCESS(status)) { goto exit1; } // // Read driver class name (for report resources) // status = IopGetRegistryValue (resourcesHandle, L"ClassName", &keyValueInformation ); if (NT_SUCCESS( status )) { status = STATUS_FAIL_CHECK; if (keyValueInformation->DataLength != 0L) { if (PiRegSzToString((PWCHAR)KEY_VALUE_DATA(keyValueInformation), keyValueInformation->DataLength, &length, &driverClassName.Buffer)) { driverClassName.Length = (USHORT)length; driverClassName.MaximumLength = (USHORT)length + sizeof (UNICODE_NULL); status = STATUS_SUCCESS; } } ExFreePool(keyValueInformation); } if (!NT_SUCCESS(status)) { ZwClose(resourcesHandle); goto exit1; } // // Read driver/device requested and assigned resources // if (TranslatedEntry->Owner->DeviceName.Length == 0) { RtlInitUnicodeString(&unicodeName1, L"Driver"); } else { unicodeName1 = TranslatedEntry->Owner->DeviceName; } // // Read information on which resource list is picked from // resource requirement list. // RtlInitUnicodeString(&unicodeName2, L".ListPicked"); IopConcatenateUnicodeStrings(&unicodeValueName, &unicodeName1, &unicodeName2); status = IopGetRegistryValue (resourcesHandle, unicodeValueName.Buffer, &keyValueInformation ); if (NT_SUCCESS( status )) { status = STATUS_FAIL_CHECK; if (keyValueInformation->DataLength != 0L) { listPicked = *(PULONG)KEY_VALUE_DATA(keyValueInformation); status = STATUS_SUCCESS; } ExFreePool(keyValueInformation); } RtlFreeUnicodeString(&unicodeValueName); if (!NT_SUCCESS(status)) { ZwClose(resourcesHandle); goto exit1; } // // Read requested resources // RtlInitUnicodeString(&unicodeName2, L".RequestedResources"); IopConcatenateUnicodeStrings(&unicodeValueName, &unicodeName1, &unicodeName2); status = IopGetRegistryValue (resourcesHandle, unicodeValueName.Buffer, &keyValueInformation ); if (NT_SUCCESS( status )) { status = STATUS_FAIL_CHECK; if (keyValueInformation->DataLength != 0L) { usedHeap = (PUSED_HEAP)ExAllocatePool( PagedPool, keyValueInformation->DataLength + sizeof(USED_HEAP)); ioResources = (PIO_RESOURCE_REQUIREMENTS_LIST)(usedHeap + 1); if (usedHeap) { RtlMoveMemory(ioResources, KEY_VALUE_DATA(keyValueInformation), keyValueInformation->DataLength); status = STATUS_SUCCESS; } } ExFreePool(keyValueInformation); } RtlFreeUnicodeString(&unicodeValueName); if (!NT_SUCCESS(status)) { ZwClose(resourcesHandle); goto exit1; } // // read reported resources // RtlInitUnicodeString(&unicodeName2, L".ReportedResources"); IopConcatenateUnicodeStrings(&unicodeValueName, &unicodeName1, &unicodeName2); status = IopGetRegistryValue (resourcesHandle, unicodeValueName.Buffer, &keyValueInformation ); if (NT_SUCCESS( status )) { status = STATUS_FAIL_CHECK; if (keyValueInformation->DataLength != 0L) { reportedResources = (PREG_REQUIRED_RESOURCE_LIST)ExAllocatePool( PagedPool, keyValueInformation->DataLength); if (reportedResources) { RtlMoveMemory(reportedResources, KEY_VALUE_DATA(keyValueInformation), keyValueInformation->DataLength); status = STATUS_SUCCESS; } } ExFreePool(keyValueInformation); } RtlFreeUnicodeString(&unicodeValueName); if (!NT_SUCCESS(status)) { ExFreePool(usedHeap); ZwClose(resourcesHandle); goto exit1; } ZwClose(resourcesHandle); // // Build a resource directory from the requested list // // Note the Io resource requirement list returned by hal is not on // allocated heap list. We will free it manually. // status = IopBuildResourceDir (NULL, &driverDir, ioResources); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("RequestedResources could no be parsed. Status = %lx", status); #endif ExFreePool(usedHeap); ExFreePool(reportedResources); goto exit1; } // // put IoResources onto allocated heap list // usedHeap->FreeHeap = (PVOID) usedHeap; PushEntryList (&driverDir->AllocatedHeap, &usedHeap->FreeLink); // // allocate a scratch buffer // driverDir->Buffer = (PWSTR)IopAllocateDirPool (driverDir, BUFFERSIZE); if (!driverDir->Buffer) { status = STATUS_INSUFFICIENT_RESOURCES; #if DBG DbgPrint("No memory, status = %lx", status); #endif goto exit0; } // // Sort the request descriptors such that all alternative descriptor // options are grouped by CmResourceType. // IopSortDescriptors(driverDir); // // Initialize handles from caller's Dir. // for (i = 0; i < MAX_REG_HANDLES; i++) { driverDir->RegHandle[i] = Dir->RegHandle[i]; } driverDir->RegHandle[HDEVICE_STORAGE] = driverHandle; // // Check for user assigned resources in RegistryPath // ioResources = IopGetResourceReqRegistryValue ( driverDir, driverDir->RegHandle[HDEVICE_STORAGE], IopWstrAssignedResources ); if (ioResources) { // // Build directory out of user's assignments // status = IopBuildResourceDir (driverDir, &driverDir->UserDir, ioResources); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("RelocateResource: Device AssignedResources could not be parsed status = %lx", status); #endif goto exit0; } status = IopCatagorizeDescriptors (driverDir->UserDir); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("RelocateResource: Device AssignedResources could not be catagorized, status = %lx", status); #endif goto exit0; } } // // Init bus specific ordering // driverDir->BusDir = Dir->BusDir; // // Init TENTRIESBYTYPE structures // driverDir->InUseResources = Dir->InUseResources; driverDir->InUseSharableResources = Dir->InUseSharableResources; driverDir->ReservedSharableResources = Dir->ReservedSharableResources; // // Init DIR_REQUIRED_RESOURCE structures from reported resources // resourceList = driverDir->Alternative; for (i = 1; i < listPicked; i++) { resourceList = resourceList->Next; } ASSERT(resourceList->NoRequiredResources = reportedResources->NoRequiredResources); driverDir->ListPicked = resourceList; for (i = 0; i < reportedResources->NoRequiredResources; i++) { resourceList->RequiredResource[i]->Type = reportedResources->RegResource[i].Type; resourceList->RequiredResource[i]->CurBLoc = reportedResources->RegResource[i].CurBLoc; resourceList->RequiredResource[i]->CurBAddr = reportedResources->RegResource[i].CurBAddr; resourceList->RequiredResource[i]->TType = reportedResources->RegResource[i].TType; resourceList->RequiredResource[i]->Trans = reportedResources->RegResource[i].Trans; } // // Link the new DIR to our DIR list // tmpDir = driverDir; while (tmpDir->FreeResReqList) { tmpDir = driverDir->FreeResReqList; } tmpDir->FreeResReqList = IopRelocatedDirList; IopRelocatedDirList = driverDir; // // Create and initialize RECONFIGURE_DRIVER structure for this driverDir // reconfigDriver = (PRECONFIGURED_DRIVER)ExAllocatePool( PagedPool, sizeof(RECONFIGURED_DRIVER)); if (!reconfigDriver) { status = STATUS_INSUFFICIENT_RESOURCES; goto exit0; } driverDir->ReconfiguredDriver = reconfigDriver; reconfigDriver->Owner = TranslatedEntry->Owner; reconfigDriver->ReconfiguredDir = driverDir; reconfigDriver->DriverClassName = driverClassName; reconfigDriver->DriverObject = driverObject; reconfigDriver->DeviceObject = deviceObject; reconfigDriver->DeviceFileObject = fileObject; reconfigDriver->CmResourceList = NULL; } else { reconfigDriver = driverDir->ReconfiguredDriver; // // Snapshot the current assignment such that we can recover it if fails. // resourceList = driverDir->ListPicked; reportedResources = ExAllocatePool(PagedPool, sizeof(REG_REQUIRED_RESOURCE_LIST) + (resourceList->NoRequiredResources - 1) * sizeof(REG_REQUIRED_RESOURCE)); reportedResources->NoRequiredResources = resourceList->NoRequiredResources; for (i = 0; i < reportedResources->NoRequiredResources; i++) { reportedResources->RegResource[i].Type = resourceList->RequiredResource[i]->Type; reportedResources->RegResource[i].CurBLoc = resourceList->RequiredResource[i]->CurBLoc; reportedResources->RegResource[i].CurBAddr = resourceList->RequiredResource[i]->CurBAddr; reportedResources->RegResource[i].TType = resourceList->RequiredResource[i]->TType; reportedResources->RegResource[i].Trans = resourceList->RequiredResource[i]->Trans; } } // // try to regenerate a resource assignment for the requiredResource which // is in conflict at pass 4. // for (i=0; i < resourceList->NoRequiredResources; i++) { reqRes = resourceList->RequiredResource[i]; // // find the required resource which we are interested in. // if (TranslatedEntry->BAddr == reqRes->Trans.BAddr && TranslatedEntry->EAddr == reqRes->Trans.EAddr && reqRes->TType == TranslatedType) { reqRes->CurLoc = 0; reqRes->RunLen = 0; reqRes->PassNo = 4; break; } } ASSERT(i < resourceList->NoRequiredResources); found = IopGenNextValidDescriptor ( i, resourceList, driverDir, &collisionLevel); if (!found) { tmpFlags = TranslatedEntry->Flags; TranslatedEntry->Flags = TENTRY_FLAGS_BEING_RELOCATED; // // Fail go generate a valid assignment at pass 4. // Move to pass 5 see if we can relocate other driver(s) // reqRes->CurLoc = 0; reqRes->RunLen = 0; reqRes->PassNo = 5; found = IopGenNextValidDescriptor ( i, resourceList, driverDir, &collisionLevel); TranslatedEntry->Flags = tmpFlags; } if (found) { // // Build CmResourceList from assignments // cmResources = IopAssignResourcesPhase4 ( driverDir, resourceList, &length); if (!cmResources) { status = STATUS_INSUFFICIENT_RESOURCES; goto exit2; } // // Ask driver if its resources can be reconfigured. // status = IopQueryReconfigureResource( reconfigDriver->DriverObject, reconfigDriver->DeviceObject, cmResources); if (NT_SUCCESS(status)) { // // Link reconfigured driver structure to to IopReconfiguredDrivers // list if it has been done. // if (reconfigDriver->CmResourceList) { ExFreePool(reconfigDriver->CmResourceList); } reconfigDriver->CmResourceList = cmResources; reconfigDriver->ResourceLength = length; tmp = IopReconfiguredDrivers; while (tmp) { if (tmp == reconfigDriver) { break; } tmp = tmp->Next; } if (!tmp) { reconfigDriver->Next = IopReconfiguredDrivers; IopReconfiguredDrivers = reconfigDriver; } if (reqRes->PassNo == 4) { // // the NewTranslatedEntry is return only when we actually // allocated *new* resource in pass 4. If we are in PassNo 5, // we did not allocate *new* resource, we re-use the resource // which is in used. // // // Build Owner structure for TLIST entries // owner = IopAllocateDirPool (driverDir, sizeof (*(TranslatedEntry->Owner))); if (!owner) { status = STATUS_INSUFFICIENT_RESOURCES; goto exit2; } owner->InConflict.Flink = NULL; owner->DeviceName = TranslatedEntry->Owner->DeviceName; owner->KeyName = TranslatedEntry->Owner->KeyName; // // Get a new Trans entry in the InUseResource list or the // InUseSharableResource list // ioDesc = reqRes->IoResourceDescriptor[reqRes->CurBLoc]; if (ioDesc->ShareDisposition == CmResourceShareShared) { byType = &driverDir->InUseSharableResources; } else { byType = &driverDir->InUseResources; } trans = IopNewTransEntry (driverDir, byType, reqRes->TType); if (!trans) { status = STATUS_INSUFFICIENT_RESOURCES; goto exit2; } // // Fill in the Trans structure // *trans = reqRes->Trans; trans->Owner = owner; trans->Flags = TENTRY_FLAGS_IN_USE; // // Add new translated entry to New Resource list // if (!IopAddRelocatedEntry(&IopNewResources, trans, reqRes->TType, owner)) { status = STATUS_INSUFFICIENT_RESOURCES; goto exit2; } } // // Add the conflict entry to Conflict InProcessed list // owner = NULL; if (Dir->ReconfiguredDriver) { owner = Dir->ReconfiguredDriver->Owner; } if (!IopAddRelocatedEntry(&IopInProcessedConflicts, TranslatedEntry, TranslatedType, owner )) { status = STATUS_INSUFFICIENT_RESOURCES; } } } else { status = STATUS_CONFLICTING_ADDRESSES; } exit2: if (!NT_SUCCESS(status)) { if (driverDir) { resourceList = driverDir->ListPicked; for (i = 0; i < reportedResources->NoRequiredResources; i++) { resourceList->RequiredResource[i]->Type = reportedResources->RegResource[i].Type; resourceList->RequiredResource[i]->CurBLoc = reportedResources->RegResource[i].CurBLoc; resourceList->RequiredResource[i]->CurBAddr = reportedResources->RegResource[i].CurBAddr; resourceList->RequiredResource[i]->TType = reportedResources->RegResource[i].TType; resourceList->RequiredResource[i]->Trans = reportedResources->RegResource[i].Trans; } } } if (reportedResources) { ExFreePool(reportedResources); } if (!NT_SUCCESS(status)) { return FALSE; } else { return TRUE; } exit0: IopFreeResourceDir(driverDir); if (reportedResources) { ExFreePool(reportedResources); } exit1: if (driverObject) { ObDereferenceObject(driverObject); } if (driverHandle) { ZwClose(driverHandle); } if (deviceObject) { ObDereferenceObject( fileObject ); ObDereferenceObject(deviceObject); } if (driverClassName.Length != 0) { ExFreePool(driverClassName.Buffer); } return FALSE; } NTSTATUS IopRecordAssignInformation( IN PDIR_RESREQ_LIST Dir, IN PUNICODE_STRING DriverClassName, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject, IN PDIR_RESOURCE_LIST CurList ) /*++ Routine Description: This routine saves resource assignment related information to registry. We may need it later to resolve resource conflicts. If this routine fails to save the information, it is not fatal. But we won't be able to reconfigure the resources of the driver. Arguments: Dir - Supplies a pointer to the DIR_RESREQ_LIST of the resource list DriverClassName - Supplies a pointer to the Driver's class name. It is used to partition allocated resources into different device classes. DriverObject - Supplies a pointer to the driver object of the caller. DeviceObject - Supplies a pointer to the device object of the caller. If non-null, then requested resoruce list refers to this device. If null, the requested resource list refers to the driver. CurDir - supplies a pointer to the selected DIR_RESOURCE_LIST. Returned Value: None. --*/ { HANDLE driverHandle, handle; NTSTATUS status; UNICODE_STRING unicodeName1, unicodeName2, unicodeValueName; ULONG i, length; POBJECT_NAME_INFORMATION obNameInfo; PDIR_RESOURCE_LIST resourceList; PREG_REQUIRED_RESOURCE_LIST regList; PREG_REQUIRED_RESOURCE regResource; PDIR_REQUIRED_RESOURCE reqResource; // // Open CCS\ServiceKeyName\ResourceInformation key for the driver // status = IopOpenRegistryKey(&handle, NULL, &CmRegistryMachineSystemCurrentControlSetServices, KEY_ALL_ACCESS, FALSE ); if (!NT_SUCCESS(status)) { return status; } status = IopOpenRegistryKey(&driverHandle, handle, &DriverObject->DriverExtension->ServiceKeyName, KEY_ALL_ACCESS, FALSE ); ZwClose(handle); if (!NT_SUCCESS(status)) { return status; } RtlInitUnicodeString(&unicodeName2, L"ResourceInformation"); status = IopOpenRegistryKey(&handle, driverHandle, &unicodeName2, KEY_ALL_ACCESS, TRUE ); if (!NT_SUCCESS(status)) { return status; } // // Write driver class name (for report resources) // RtlInitUnicodeString(&unicodeName1, L"ClassName"); if (DriverClassName == NULL) { RtlInitUnicodeString(&unicodeName2, L"OtherDrivers"); DriverClassName = &unicodeName2; } ZwSetValueKey(handle, &unicodeName1, TITLE_INDEX_VALUE, REG_SZ, DriverClassName->Buffer, DriverClassName->Length + sizeof(UNICODE_NULL) ); // // Form ValueName. // obNameInfo = (POBJECT_NAME_INFORMATION) Dir->Buffer; if (DeviceObject) { status = ObQueryNameString (DeviceObject, obNameInfo, BUFFERSIZE, &i); if (!NT_SUCCESS(status)) { goto exit1; } unicodeName1 = obNameInfo->Name; } else { RtlInitUnicodeString(&unicodeName1, L"Driver"); } // // Save requested resources under Driver/DeviceName.RequestedResources // RtlInitUnicodeString( &unicodeName2, L".RequestedResources"); IopConcatenateUnicodeStrings(&unicodeValueName, &unicodeName1, &unicodeName2); ZwSetValueKey( handle, &unicodeValueName, TITLE_INDEX_VALUE, REG_BINARY, Dir->IoResourceReq, Dir->IoResourceReq->ListSize ); RtlFreeUnicodeString(&unicodeValueName); // // Find out which DIR_RESOURCE_LIST was picked and save its data // in Driver/DeviceName.ListPicked and .ReportedResources // resourceList = Dir->Alternative; i = 1; while (resourceList) { if (CurList == resourceList) { break; } resourceList = resourceList->Next; i++; } ASSERT(resourceList != NULL); // // Save Driver/DeviceName.ListPicked = // RtlInitUnicodeString( &unicodeName2, L".ListPicked"); IopConcatenateUnicodeStrings(&unicodeValueName, &unicodeName1, &unicodeName2); ZwSetValueKey( handle, &unicodeValueName, TITLE_INDEX_VALUE, REG_DWORD, &i, sizeof(i) ); RtlFreeUnicodeString(&unicodeValueName); // // Build REG_REQUIRED_RESOURCE_LIST // length = sizeof(REG_REQUIRED_RESOURCE_LIST) + sizeof(REG_REQUIRED_RESOURCE) * (CurList->NoRequiredResources - 1); regList = ExAllocatePool(PagedPool, length); regList->NoRequiredResources = CurList->NoRequiredResources; length = sizeof(regList->NoRequiredResources); for (i = 0; i < CurList->NoRequiredResources; i++) { regResource = ®List->RegResource[i]; reqResource = CurList->RequiredResource[i]; regResource->Type = reqResource->Type; regResource->CurBLoc = reqResource->CurBLoc; regResource->CurBAddr = reqResource->CurBAddr; regResource->TType = reqResource->TType; regResource->Trans = reqResource->Trans; length += sizeof(REG_REQUIRED_RESOURCE); } // // Save the REG_REQUIRED_RESOURCE_LIST to Driver/DeviceName.ReportedResources // RtlInitUnicodeString( &unicodeName2, L".ReportedResources"); IopConcatenateUnicodeStrings(&unicodeValueName, &unicodeName1, &unicodeName2); ZwSetValueKey( handle, &unicodeValueName, TITLE_INDEX_VALUE, REG_BINARY, regList, length ); RtlFreeUnicodeString(&unicodeValueName); ExFreePool(regList); exit1: ZwClose(handle); return status; } NTSTATUS IopQueryReconfigureResource( PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT DeviceObject, PCM_RESOURCE_LIST CmResources ) { return STATUS_SUCCESS; //return STATUS_NOT_IMPLEMENTED; } NTSTATUS IopReconfigureResource( PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT DeviceObject, PCM_RESOURCE_LIST CmResources ) { return STATUS_SUCCESS; //return STATUS_NOT_IMPLEMENTED; } NTSTATUS IopCancelReconfigureResource( PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT DeviceObject ) { return STATUS_SUCCESS; //return STATUS_NOT_IMPLEMENTED; } VOID IopFreeRelocatedTEntryLists( VOID ) /*++ Routine Description: Frees pool used to resolve resource conflicts. Note, we free the RELOCATED_TENTRIES structure but leave the TENTRY in the structure. The TENTRY structure will be freed by resource dir free routine. Arguments: None. Return Value: None. --*/ { PRELOCATED_TENTRIES tmp; while (IopInProcessedConflicts) { tmp = IopInProcessedConflicts; IopInProcessedConflicts = IopInProcessedConflicts->Next; ExFreePool(tmp); } while (IopNewResources) { tmp = IopNewResources; IopNewResources = IopNewResources->Next; ExFreePool(tmp); } } ULONG IopFindCollisionInRelocatedList ( IN PTENTRY SEntry, IN PRELOCATED_TENTRIES List, OUT PTENTRY *ConflictEntry ) /*++ Routine Description: Checks to see if there's a collision between the source TENTRY and the list of RELOCATED_TENTRIES passed by List. Arguments: Return Value Returns the skew amount required to continue searching for next possible setting and a pointer to the conflicted entry. A zero skew means no collision occured. --*/ { LONGLONG liTmp; TENTRY source; source = *SEntry; while (List) { SEntry = List->TranslatedEntry; if (DoesTEntryCollide (source, *SEntry)) { liTmp = source.EAddr - SEntry->BAddr; *ConflictEntry = SEntry; return (ULONG) liTmp + 1; } List = List->Next; } return 0; } ULONG IopAddRelocatedEntry ( IN PRELOCATED_TENTRIES *List, IN PTENTRY Entry, IN UCHAR Type, IN POWNER NewOwner ) /*++ Routine Description: This routine add Entry to the specified RELOCATED_ENTRIES list. Arguments: Return Value TRUE - succeeded. FALSE - failed. --*/ { PRELOCATED_TENTRIES pRelocatedEntry; if (Entry == NULL) { return TRUE; } // // Is the entry already in the specified list // pRelocatedEntry = *List; while (pRelocatedEntry) { if (pRelocatedEntry->TranslatedEntry == Entry) { break; } pRelocatedEntry = pRelocatedEntry->Next; } if (!pRelocatedEntry) { pRelocatedEntry = (PRELOCATED_TENTRIES)ExAllocatePool( PagedPool, sizeof(RELOCATED_TENTRIES)); if (!pRelocatedEntry) { #if DBG DbgPrint("IoAssignResource P4: Failed to allocate memory for InProcess list"); #endif return FALSE; } // // Remember the names of the FIRST owner (i.e. the owner before the relocation began) // pRelocatedEntry->OriginalDriver = Entry->Owner->KeyName; pRelocatedEntry->OriginalDevice = Entry->Owner->DeviceName; pRelocatedEntry->Next = *List; *List = pRelocatedEntry; pRelocatedEntry->Type = Type; pRelocatedEntry->TranslatedEntry = Entry; } Entry->Owner = NewOwner; return TRUE; } VOID IopFreeRelocatedResourceDir ( IN PDIR_RESREQ_LIST DirResourceList ) /*++ Routine Description: This routine does a special handling to the DIR_RESREQ_LIST used to relocate driver resources before calling IopFreeResourceDir. Note, the FreeResReqList should be NULL for relocated driver resource dir. Arguments: DirResourceList - supplies a pointer to the DIR_RESREQ_LIST used to relocate driver resources. Return Value: None. --*/ { ULONG i; PDIR_RESREQ_LIST tmpDir; // // Close any opened handles // tmpDir = DirResourceList; while (tmpDir) { for (i=0; i< MAX_REG_HANDLES; i++) { if (i != HDEVICE_STORAGE) { tmpDir->RegHandle[i] = INVALID_HANDLE; } } tmpDir = tmpDir->FreeResReqList; } IopFreeResourceDir(DirResourceList); } #endif // _PNP_POWER_ VOID IopPickupCollisionInTList ( IN PDIR_RESOURCE_LIST CurList, IN UCHAR Type, IN LONGLONG BAddr, IN PTENTRY SEntry, IN PLTENTRY List ) { TENTRY Source; ULONG i, j, conflicts; Source = *SEntry; // // If resource already listed in easy collision list, skip it // j = CurList->Conflict.NoConflicts; if (j > SCONFLICT) { j = SCONFLICT; } for (i=0; i < j; i++) { if (CurList->Conflict.EasyConflict[i].BAddr == BAddr && CurList->Conflict.EasyConflict[i].Type == Type) { return ; } } // // Add valid, but conflicting, resource setting to failed list // conflicts = CurList->Conflict.NoConflicts; if (conflicts < SCONFLICT) { CurList->Conflict.EasyConflict[conflicts].Type = Type; CurList->Conflict.EasyConflict[conflicts].BAddr = BAddr; } // // Find collision // while (List) { j = List->CurEntries; for (i=0; i < j; i++) { SEntry = List->Table+i; if (DoesTEntryCollide (Source, *SEntry)) { if (SEntry->Owner) { if (conflicts < SCONFLICT) { CurList->Conflict.EasyConflict[conflicts].Owner = SEntry->Owner; SEntry->Owner->InConflict.Flink = (PVOID) -1; } if (SEntry->Owner->InConflict.Flink == NULL) { // // Add owner of this conflict to list of colliding owners // InsertTailList (&CurList->Conflict.OtherConflicts, &SEntry->Owner->InConflict); } } CurList->Conflict.NoConflicts += 1; return ; } } List = List->Next; } } STATIC PVOID IopAllocateDirPool ( IN PDIR_RESREQ_LIST Dir, IN ULONG Length ) /*++ Routine Description: Allocates pool and links the allocation to the DIR_RESREQ_LIST structure so it will be freed when the DIR_RESRES_LIST is freed. WARNING: Just like ExAllocatePool this function needs to return memory aligned on 8 byte boundaries. --*/ { PUSED_HEAP ph; ph = (PUSED_HEAP) ExAllocatePool (PagedPool, Length+sizeof(USED_HEAP)); if (!ph) { return NULL; } ph->FreeHeap = (PVOID) ph; PushEntryList (&Dir->AllocatedHeap, &ph->FreeLink); return (PVOID) (ph+1); } PIO_RESOURCE_REQUIREMENTS_LIST IopGetResourceReqRegistryValue ( IN PDIR_RESREQ_LIST Dir, IN HANDLE KeyHandle, IN PWSTR ValueName ) /*++ Routine Description: Looks up the setting for ValueKey in KeyHandle and returns the data or NULL. If non-null, the memory was obtained via pool. Arguments: Return Value: --*/ { PKEY_VALUE_FULL_INFORMATION KeyInformation; NTSTATUS status; PUCHAR Data; ULONG DataLength, Type; PIO_RESOURCE_REQUIREMENTS_LIST p; for (; ;) { status = IopGetRegistryValue (KeyHandle, ValueName, &KeyInformation); if (!NT_SUCCESS(status)) { return NULL; } // // Get pointer to data & length // Type = KeyInformation->Type; Data = ((PUCHAR) KeyInformation + KeyInformation->DataOffset); DataLength = KeyInformation->DataLength; // // Copy data to aligned paged pool buffer, and free non-paged pool // p = (PIO_RESOURCE_REQUIREMENTS_LIST) IopAllocateDirPool (Dir, DataLength + sizeof (WCHAR)); if (!p) { ExFreePool (KeyInformation); return NULL; } RtlCopyMemory (p, Data, DataLength); ExFreePool (KeyInformation); if (Type == REG_SZ) { // // Forward to different entry - Need to copy name in order to get // space at the end to add the NULL terminator // ValueName = (PWSTR) p; ValueName [DataLength / sizeof (WCHAR)] = 0; continue; } // verify registry entry is of expected type if (Type != REG_RESOURCE_REQUIREMENTS_LIST) { return NULL; } p->ListSize = DataLength; return p; } } NTSTATUS IopAssignResourcesPhase1 ( IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources, IN PIO_RESOURCE_REQUIREMENTS_LIST *pCopiedList ) /*++ Routine Description: Copies the callers supplied resource list and passes it to the HAL. The HAL then adjusts the requested resource list to be within any bus/system requirements the system may have. Arguments: IoResources - Callers requested resource list *pCopiedList - Returned resource list (allocated from heap) --*/ { PIO_RESOURCE_LIST ResourceList; NTSTATUS status; ULONG cnt, length; PUCHAR FirstAddress, LastAddress; PAGED_CODE(); // // Verify Version & Revision of data structure is set correctly // if (IoResources->AlternativeLists == 0 || IoResources->Reserved[0] != 0 || IoResources->Reserved[1] != 0 || IoResources->Reserved[2] != 0) { DBGMSG ("IopAssignResourcesPhase1: Bad structure format\n"); return STATUS_INVALID_PARAMETER; } // // Pass a copy of the list to the HAL for any adjustments // // // Simple sanity check for size of callers RequestedResource list // ResourceList = IoResources->List; FirstAddress = (PUCHAR) ResourceList; LastAddress = (PUCHAR) IoResources + IoResources->ListSize; for (cnt=0; cnt < IoResources->AlternativeLists; cnt++) { if (ResourceList->Version != 1 || ResourceList->Revision < 1) { DBGMSG ("IopAssignResourcesPhase1: Invalid version #\n"); return STATUS_INVALID_PARAMETER; } ResourceList = (PIO_RESOURCE_LIST) (&ResourceList->Descriptors[ResourceList->Count]); if ((PUCHAR) ResourceList < FirstAddress || (PUCHAR) ResourceList > LastAddress) { DBGMSG ("IopAssignResourcesPhase1: IO_RESOURCE_LIST.ListSize too small\n"); return STATUS_INVALID_PARAMETER; } } length = (ULONG) ((PUCHAR) ResourceList - (PUCHAR) IoResources); // // Copy user's passed in list // *pCopiedList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool (PagedPool, length); if (!*pCopiedList) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory (*pCopiedList, IoResources, length); (*pCopiedList)->ListSize = length; // // Let hal adjust the requested list // status = HalAdjustResourceList (pCopiedList); if (!NT_SUCCESS(status)) { DBGMSG ("IopAssignResourcesPhase1: HalAdjustResourceList failed\n"); ExFreePool (*pCopiedList); return status; } return STATUS_SUCCESS; } NTSTATUS IopAssignResourcesPhase2 ( IN PDIR_RESREQ_LIST Dir, IN PUNICODE_STRING DriverClassName, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject ) /* Routine Description: Reads the ResourceMap in the registry and builds a canonical list of all in use resources ranges by resource type. Arguments: Dir - InUseResources & InUseShareableResources are filled in by this call. */ { HANDLE ResourceMap, ClassKeyHandle, DriverKeyHandle; ULONG ClassKeyIndex, DriverKeyIndex, DriverValueIndex, Index; POBJECT_NAME_INFORMATION ObNameInfo; PCM_RESOURCE_LIST CmResList; PCM_FULL_RESOURCE_DESCRIPTOR CmFResDesc; PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc; UNICODE_STRING unicodeString; UNICODE_STRING KeyName, TranslatedName, DriverName, DClassName; PVOID p2; ULONG BufferSize; union { PVOID Buffer; PKEY_BASIC_INFORMATION KeyBInf; PKEY_FULL_INFORMATION KeyFInf; PKEY_VALUE_FULL_INFORMATION VKeyFInf; } U; PUCHAR LastAddr; ULONG junk, Length, i, j, TranslatedStrLen, BusTranslatedStrLen; PWSTR pw; NTSTATUS status; BOOLEAN sameClass, sameDriver; BOOLEAN flag; POWNER Owner; LONGLONG li; PAGED_CODE(); // // Allocate a scratch buffer. Use BUFFSERSIZE or the sizeof the largest // value in SystemResources\ReservedResources // U.Buffer = Dir->Buffer; U.KeyFInf->MaxValueNameLen = U.KeyFInf->MaxValueDataLen = 0; ZwQueryKey( Dir->RegHandle[HRESERVEDRESOURCES], KeyFullInformation, U.KeyFInf, BUFFERSIZE, &junk ); Length = sizeof( KEY_VALUE_FULL_INFORMATION ) + U.KeyFInf->MaxValueNameLen + U.KeyFInf->MaxValueDataLen + sizeof(UNICODE_NULL); BufferSize = Length > BUFFERSIZE ? Length : BUFFERSIZE; U.Buffer = ExAllocatePool (PagedPool, BufferSize); if (!U.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; } // // Build translated registry name to watch for // ObNameInfo = (POBJECT_NAME_INFORMATION) Dir->Buffer; if (DeviceObject) { status = ObQueryNameString (DeviceObject, ObNameInfo, BUFFERSIZE, &Length); if (!NT_SUCCESS(status)) { return status; } } else { ObNameInfo->Name.Length = 0; ObNameInfo->Name.Buffer = (PVOID) ((PUCHAR) Dir->Buffer + sizeof(OBJECT_NAME_INFORMATION)); } ObNameInfo->Name.MaximumLength = BUFFERSIZE - sizeof(OBJECT_NAME_INFORMATION); RtlAppendUnicodeToString (&ObNameInfo->Name, IopWstrTranslated); TranslatedName.Length = ObNameInfo->Name.Length; TranslatedName.MaximumLength = ObNameInfo->Name.Length; TranslatedName.Buffer = IopAllocateDirPool (Dir, TranslatedName.Length); if (!TranslatedName.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory (TranslatedName.Buffer, ObNameInfo->Name.Buffer, TranslatedName.Length); for (TranslatedStrLen=0; IopWstrTranslated[TranslatedStrLen]; TranslatedStrLen++) ; for (BusTranslatedStrLen=0; IopWstrBusTranslated[BusTranslatedStrLen]; BusTranslatedStrLen++) ; TranslatedStrLen *= sizeof (WCHAR); BusTranslatedStrLen *= sizeof (WCHAR); // // Build driver name to watch for // status = ObQueryNameString (DriverObject, ObNameInfo, BUFFERSIZE, &Length); if (!NT_SUCCESS(status)) { return status; } i = 0; pw = ObNameInfo->Name.Buffer; while (*pw) { if (*pw++ == OBJ_NAME_PATH_SEPARATOR) { i = pw - ObNameInfo->Name.Buffer; } } Length = ObNameInfo->Name.Length - i * sizeof (WCHAR); DriverName.Length = (USHORT) Length; DriverName.MaximumLength = (USHORT) Length; DriverName.Buffer = IopAllocateDirPool (Dir, Length); if (!DriverName.Buffer) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory (DriverName.Buffer, ObNameInfo->Name.Buffer + i, Length); // // If no give driver class, use default // if (!DriverClassName) { RtlInitUnicodeString( &DClassName, IopWstrOtherDrivers ); DriverClassName = &DClassName; } // // Walk resource map and collect any inuse resources // ResourceMap = Dir->RegHandle[HRESOURCE_MAP]; ClassKeyIndex = 0; ClassKeyHandle = INVALID_HANDLE; DriverKeyHandle = INVALID_HANDLE; while (NT_SUCCESS(status)) { // // Get the class information // status = ZwEnumerateKey( ResourceMap, ClassKeyIndex++, KeyBasicInformation, U.KeyBInf, BufferSize, &junk ); if (!NT_SUCCESS( status )) { break; } // // Create a UNICODE_STRING using the counted string passed back to // us in the information structure, and open the class key. // KeyName.Buffer = (PWSTR) U.KeyBInf->Name; KeyName.Length = (USHORT) U.KeyBInf->NameLength; KeyName.MaximumLength = (USHORT) U.KeyBInf->NameLength; status = IopOpenRegistryKey( &ClassKeyHandle, ResourceMap, &KeyName, KEY_READ, FALSE ); if (!NT_SUCCESS( status )) { break; } // // Check if we are in the same call node. // sameClass = RtlEqualUnicodeString( DriverClassName, &KeyName, TRUE ); DriverKeyIndex = 0; while (NT_SUCCESS (status)) { // // Get the class information // status = ZwEnumerateKey( ClassKeyHandle, DriverKeyIndex++, KeyBasicInformation, U.KeyBInf, BufferSize, &junk ); if (!NT_SUCCESS( status )) { break; } // // Create a UNICODE_STRING using the counted string passed back to // us in the information structure, and open the class key. // // This is read from the key we created, and the name // was NULL terminated. // KeyName.Buffer = (PWSTR) IopAllocateDirPool (Dir, U.KeyBInf->NameLength); if (!KeyName.Buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory (KeyName.Buffer, U.KeyBInf->Name, U.KeyBInf->NameLength); KeyName.Length = (USHORT) U.KeyBInf->NameLength; KeyName.MaximumLength = (USHORT) U.KeyBInf->NameLength; status = IopOpenRegistryKey( &DriverKeyHandle, ClassKeyHandle, &KeyName, KEY_READ, FALSE ); if (!NT_SUCCESS( status )) { break; } // // Check if we are in the same call node. // sameDriver = sameClass && RtlEqualUnicodeString( &DriverName, &KeyName, TRUE ); // // Get full information for that key so we can get the // information about the data stored in the key. // status = ZwQueryKey( DriverKeyHandle, KeyFullInformation, U.KeyFInf, BufferSize, &junk ); if (!NT_SUCCESS( status )) { break; } Length = sizeof( KEY_VALUE_FULL_INFORMATION ) + U.KeyFInf->MaxValueNameLen + U.KeyFInf->MaxValueDataLen + sizeof(UNICODE_NULL); if (Length > BufferSize) { // // Get a larger buffer // p2 = ExAllocatePool (PagedPool, Length); if (!p2) { status = STATUS_INSUFFICIENT_RESOURCES; break; } ExFreePool (U.Buffer); U.Buffer = p2; BufferSize = Length; } DriverValueIndex = 0; for (; ;) { status = ZwEnumerateValueKey( DriverKeyHandle, DriverValueIndex++, KeyValueFullInformation, U.VKeyFInf, BufferSize, &junk ); if (!NT_SUCCESS( status )) { break; } // // If this is not a translated resource list, skip it. // i = U.VKeyFInf->NameLength; if (i < TranslatedStrLen || RtlCompareMemory ( ((PUCHAR) U.VKeyFInf->Name) + i - TranslatedStrLen, IopWstrTranslated, TranslatedStrLen ) != TranslatedStrLen ) { // does not end in IopWstrTranslated continue; } // // If this is a bus translated resource list, ???? // if (i >= BusTranslatedStrLen && RtlCompareMemory ( ((PUCHAR) U.VKeyFInf->Name) + i - BusTranslatedStrLen, IopWstrBusTranslated, BusTranslatedStrLen ) == BusTranslatedStrLen ) { // ends in IopWstrBusTranslated continue; } // // If these used resources are from the caller, then skip them // if (sameDriver) { unicodeString.Buffer = (PWSTR) U.VKeyFInf->Name; unicodeString.Length = (USHORT) U.VKeyFInf->NameLength; unicodeString.MaximumLength = (USHORT) U.VKeyFInf->NameLength; if (RtlEqualUnicodeString (&unicodeString, &TranslatedName, TRUE)) { // it's the current allocated resources for this caller. // skip this entry. continue; } } // // Build Owner structure for TLIST entries // Owner = IopAllocateDirPool (Dir, sizeof (*Owner) + U.VKeyFInf->NameLength); if (!Owner) { status = STATUS_INSUFFICIENT_RESOURCES; break; } Owner->InConflict.Flink = NULL; Owner->DeviceName.Buffer = NULL; #if _PNP_POWER_ Owner->DeviceName.Length = 0; #endif Owner->KeyName.Buffer = KeyName.Buffer; Owner->KeyName.Length = KeyName.Length; Owner->KeyName.MaximumLength = KeyName.MaximumLength; if (U.VKeyFInf->Name[0] != L'.') { // strip off the .Translated part of the string U.VKeyFInf->NameLength -= TranslatedStrLen; Owner->DeviceName.Buffer = Owner->UnicodeBuffer; Owner->DeviceName.Length = (USHORT) U.VKeyFInf->NameLength; Owner->DeviceName.MaximumLength = (USHORT) U.VKeyFInf->NameLength; RtlCopyMemory (Owner->UnicodeBuffer, U.VKeyFInf->Name, U.VKeyFInf->NameLength); } // // Run the CmResourceList and save each InUse resource // CmResList = (PCM_RESOURCE_LIST) ( (PUCHAR) U.VKeyFInf + U.VKeyFInf->DataOffset); LastAddr = (PUCHAR) CmResList + U.VKeyFInf->DataLength; CmFResDesc = CmResList->List; for (i=0; i < CmResList->Count && NT_SUCCESS(status) ; i++) { CmDesc = CmFResDesc->PartialResourceList.PartialDescriptors; if ((PUCHAR) (CmDesc+1) > LastAddr) { if (i) { DBGMSG ("IopAssignResourcesPhase2: a. CmResourceList in regitry too short\n"); } break; } for (j=0; j < CmFResDesc->PartialResourceList.Count && NT_SUCCESS(status); j++) { if ((PUCHAR) (CmDesc+1) > LastAddr) { i = CmResList->Count; DBGMSG ("IopAssignResourcesPhase2: b. CmResourceList in regitry too short\n"); break; } // // Add this CmDesc to the InUse list // if (CmDesc->ShareDisposition == CmResourceShareShared) { status = IopAddCmDescriptorToInUseList ( Dir, &Dir->InUseSharableResources, CmDesc, Owner ); } else { status = IopAddCmDescriptorToInUseList ( Dir, &Dir->InUseResources, CmDesc, Owner ); } CmDesc++; } CmFResDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) CmDesc; } } // next DriverValueIndex if (DriverKeyHandle != INVALID_HANDLE) { ZwClose (DriverKeyHandle); DriverKeyHandle = INVALID_HANDLE; } if (status == STATUS_NO_MORE_ENTRIES) { status = STATUS_SUCCESS; } if (!NT_SUCCESS(status)) { break; } } // next DriverKeyIndex if (ClassKeyHandle != INVALID_HANDLE) { ZwClose (ClassKeyHandle); ClassKeyHandle = INVALID_HANDLE; } if (status == STATUS_NO_MORE_ENTRIES) { status = STATUS_SUCCESS; } } // next ClassKeyIndex if (status == STATUS_NO_MORE_ENTRIES) { status = STATUS_SUCCESS; } // // All reported resources are read in. // Now read in ...SystemResources\ReservedResources // (note: this infomration could easily be cached if needed) // // // Build owner for all ResevedResources // Owner = IopAllocateDirPool (Dir, sizeof (*Owner) + U.VKeyFInf->NameLength); if (Owner) { Owner->InConflict.Flink = NULL; Owner->DeviceName.Buffer = NULL; #if _PNP_POWER_ Owner->DeviceName.Length = 0; #endif RtlInitUnicodeString (&Owner->KeyName, IopWstrReservedResources); } Index = 0; while (NT_SUCCESS (status)) { status = ZwEnumerateValueKey( Dir->RegHandle[HRESERVEDRESOURCES], Index++, KeyValueFullInformation, U.VKeyFInf, BufferSize, &junk ); if (!NT_SUCCESS( status )) { break; } // // Run the CmResourceList and save each InUse resource // CmResList = (PCM_RESOURCE_LIST) ( (PUCHAR) U.VKeyFInf + U.VKeyFInf->DataOffset); LastAddr = (PUCHAR) CmResList + U.VKeyFInf->DataLength; CmFResDesc = CmResList->List; for (i=0; i < CmResList->Count && NT_SUCCESS(status) ; i++) { CmDesc = CmFResDesc->PartialResourceList.PartialDescriptors; if ((PUCHAR) (CmDesc+1) > LastAddr) { DBGMSG ("IopAssignResourcesPhase2: c. CmResourceList in regitry too short\n"); break; } for (j=0; j < CmFResDesc->PartialResourceList.Count && NT_SUCCESS(status); j++) { if ((PUCHAR) (CmDesc+1) > LastAddr) { i = CmResList->Count; DBGMSG ("IopAssignResourcesPhase2: d. CmResourceList in regitry too short\n"); break; } // // Translate this descriptor to it's TRANSLATED values // switch (CmDesc->Type) { case CmResourceTypePort: case CmResourceTypeMemory: junk = CmDesc->Type == CmResourceTypePort ? 1 : 0; li = *((LONGLONG UNALIGNED *) &CmDesc->u.Port.Start); flag = HalTranslateBusAddress ( CmFResDesc->InterfaceType, CmFResDesc->BusNumber, *((PPHYSICAL_ADDRESS) &li), &junk, (PPHYSICAL_ADDRESS) &li ); *((LONGLONG UNALIGNED *) &CmDesc->u.Port.Start) = li; CmDesc->Type = junk == 1 ? CmResourceTypePort : CmResourceTypeMemory; break; case CmResourceTypeInterrupt: CmDesc->u.Interrupt.Vector = HalGetInterruptVector ( CmFResDesc->InterfaceType, CmFResDesc->BusNumber, CmDesc->u.Interrupt.Vector, // bus level CmDesc->u.Interrupt.Vector, // bus vector (PKIRQL) &junk, // translated level &CmDesc->u.Interrupt.Affinity ); flag = CmDesc->u.Interrupt.Affinity == 0 ? FALSE : TRUE; break; case CmResourceTypeDma: // no translation flag = TRUE; break; default: flag = FALSE; break; } if (flag) { // // Add it to the appropiate tlist // if (CmDesc->ShareDisposition == CmResourceShareShared) { status = IopAddCmDescriptorToInUseList ( Dir, &Dir->ReservedSharableResources, CmDesc, Owner ); } else { status = IopAddCmDescriptorToInUseList ( Dir, &Dir->InUseResources, CmDesc, Owner ); } } CmDesc++; } CmFResDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) CmDesc; } } // Next ReservedResource if (status == STATUS_NO_MORE_ENTRIES) { status = STATUS_SUCCESS; } ExFreePool (U.Buffer); return status; } PDIR_RESOURCE_LIST IopAssignResourcesPhase3 ( IN PDIR_RESREQ_LIST Dir ) /*++ Routine Description: All the information to process the requested resource assignments has been read in & parsed. Phase3 cranks out the resource assignments. Arguments: --*/ { PDIR_RESOURCE_LIST CurList, BestList; PDIR_REQUIRED_RESOURCE ReqRes; ULONG level, i, j; LONG BestPref, Pref; // // Run each list as pass 1 // PAGED_CODE(); for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) { // set to pass 1 for (i=0; i < CurList->NoRequiredResources; i++) { #if _PNP_POWER_ CurList->RequiredResource[i]->CurLoc = 0; CurList->RequiredResource[i]->RunLen = 0; #endif CurList->RequiredResource[i]->PassNo = 1; } // find resouce settings for this list if (IopGenNextValidResourceList (0, CurList, Dir)) { // found good settings, return them return CurList; } } // // Try again - set last checked resource in any given list to pass2 to see if that will // unclog the problem. // IDBGMSG ("First pass attempt at resource settings failed\n"); for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) { for (; ;) { // // Reset last level tried to look for any settings // level = CurList->LastLevel; ReqRes = CurList->RequiredResource[level]; if (ReqRes->PassNo != 1) { // already trying pass 2 on this level break; } ReqRes->PassNo = 2; for (j=0; j < ReqRes->NoAlternatives; j++) { ReqRes->IoResourceDescriptor[j]->Option &= ~IO_RESOURCE_PREFERRED; } // // Back up to failed level and see if this list can now be satisfied // level = CurList->NoRequiredResources; while (level > CurList->FailedLevel) { level--; CurList->RequiredResource[level]->CurLoc = 0; CurList->RequiredResource[level]->RunLen = 0; } if (IopGenNextValidResourceList (level, CurList, Dir)) { // found good settings, return them return CurList; } } // loop and clear next failed level } // loop and try next list // // Try again, this time allow for a complete search. Clear all preferred settings and // move all levels to Pass2 // IDBGMSG ("Pass 2 attempt at resource settings failed\n"); for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) { for (i=0; i < CurList->NoRequiredResources; i++) { ReqRes = CurList->RequiredResource[i]; ReqRes->CurLoc = 0; ReqRes->RunLen = 0; ReqRes->PassNo = 2; for (j=0; j < ReqRes->NoAlternatives; j++) { ReqRes->IoResourceDescriptor[j]->Option &= ~IO_RESOURCE_PREFERRED; } } } BestPref = -999999; BestList = NULL; CurList = Dir->Alternative; level = 0; while (CurList) { // find resouce settings for this list if (IopGenNextValidResourceList (level, CurList, Dir)) { // // We have useable settings, check to see how useable // if (CurList->CurPref >= 0) { // // Nothing wrong with these settings, go use them // IDBGMSG ("Pass3: Good hit\n"); return CurList; } if (CurList->CurPref > BestPref) { // // These are the best so far, remember them // BestPref = CurList->CurPref; BestList = CurList; for (i = 0; i < CurList->NoRequiredResources; i++) { ReqRes = CurList->RequiredResource[i]; ReqRes->Pass2HoldCurLoc = ReqRes->CurBLoc; ReqRes->Pass2HoldBAddr = ReqRes->CurBAddr; } } // // Determine which level to back up too to continue searching from // Pref = CurList->CurPref; level = CurList->NoRequiredResources; while (level && Pref <= BestPref) { level--; Pref -= CurList->RequiredResource[level]->CurPref; CurList->RequiredResource[level]->CurLoc = 0; CurList->RequiredResource[level]->RunLen = 0; } if (CurList->RequiredResource[level]->PrefCnt > 16) { while (level && CurList->RequiredResource[level]->PrefCnt > 16) { level--; Pref -= CurList->RequiredResource[level]->CurPref; CurList->RequiredResource[level]->CurLoc = 0; CurList->RequiredResource[level]->RunLen = 0; } if (level == 0) { // go with best setting so far break; } } CurList->RequiredResource[level]->PrefCnt++; continue ; } // no (more) valid settings found on this list, try the next CurList = CurList->Next; level = 0; } if (!BestList) { // failure IDBGMSG ("Pass3: No settings found\n"); return NULL; } // // Return best settings which were found // for (i = 0; i < BestList->NoRequiredResources; i++) { ReqRes = BestList->RequiredResource[i]; ReqRes->CurBLoc = ReqRes->Pass2HoldCurLoc; ReqRes->CurBAddr = ReqRes->Pass2HoldBAddr; } return BestList; } PCM_RESOURCE_LIST IopAssignResourcesPhase4 ( IN PDIR_RESREQ_LIST Dir, IN PDIR_RESOURCE_LIST CurList, OUT PULONG Length ) /*++ Routine Description: The callers request for resources has been calculated. Phase 4 builds a CM_RESOURCE_LIST of the allocated resources. This functions need CurDesc->CurBLoc & CurDesc->CurBAddr as passed from Phase3. Arguments: --*/ { PCM_RESOURCE_LIST CmRes; PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc; PDIR_REQUIRED_RESOURCE DirDesc, *pDirDesc; PIO_RESOURCE_DESCRIPTOR IoDesc; ULONG i, cnt, len; PAGED_CODE(); cnt = CurList->NoRequiredResources; len = sizeof (CM_RESOURCE_LIST) + cnt * sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR); *Length = len; CmRes = (PCM_RESOURCE_LIST) ExAllocatePool (PagedPool, len); if (!CmRes) { return NULL; } RtlZeroMemory (CmRes, len); CmRes->Count = 1; CmRes->List[0].InterfaceType = Dir->IoResourceReq->InterfaceType; CmRes->List[0].BusNumber = Dir->IoResourceReq->BusNumber; CmRes->List[0].PartialResourceList.Count = CurList->NoRequiredResources; CmDesc = CmRes->List[0].PartialResourceList.PartialDescriptors; pDirDesc = CurList->RequiredResource; // return resources in same order they // where requested #if IDBG DbgPrint ("Acquired Resourses - %d\n", CurList->NoRequiredResources); #endif for (i=0; i < cnt; i++, CmDesc++, pDirDesc++) { DirDesc = *pDirDesc; IoDesc = DirDesc->IoResourceDescriptor[DirDesc->CurBLoc]; CmDesc->Type = IoDesc->Type; CmDesc->ShareDisposition = IoDesc->ShareDisposition; CmDesc->Flags = IoDesc->Flags; switch (CmDesc->Type) { case CmResourceTypePort: CmDesc->u.Port.Start.QuadPart = DirDesc->CurBAddr; CmDesc->u.Port.Length = IoDesc->u.Port.Length; #if IDBG DbgPrint (" IO Start %x:%08x, Len %x\n", CmDesc->u.Port.Start.HighPart, CmDesc->u.Port.Start.LowPart, CmDesc->u.Port.Length ); #endif break; case CmResourceTypeMemory: CmDesc->u.Memory.Start.QuadPart = DirDesc->CurBAddr; CmDesc->u.Memory.Length = IoDesc->u.Memory.Length; #if IDBG DbgPrint (" MEM Start %x:%08x, Len %x\n", CmDesc->u.Memory.Start.HighPart, CmDesc->u.Memory.Start.LowPart, CmDesc->u.Memory.Length ); #endif break; case CmResourceTypeInterrupt: CmDesc->u.Interrupt.Level = (ULONG) DirDesc->CurBAddr; CmDesc->u.Interrupt.Vector = (ULONG) DirDesc->CurBAddr; #if IDBG DbgPrint (" INT Level %x, Vector %x\n", CmDesc->u.Interrupt.Level, CmDesc->u.Interrupt.Vector ); #endif break; case CmResourceTypeDma: CmDesc->u.Dma.Channel = (ULONG) DirDesc->CurBAddr; #if IDBG DbgPrint (" DMA Channel %x\n", CmDesc->u.Dma.Channel); #endif break; default: ExFreePool (CmRes); return NULL; } } return CmRes; } STATIC VOID IopLogConflict ( IN PDRIVER_OBJECT DriverObject, IN PDIR_RESREQ_LIST Dir, IN NTSTATUS FinalStatus ) /*++ Routine Description: Resource settings could not be satisfied. Locate first resource which can not be assigned and report the conflict. Arguments: --*/ { PIO_ERROR_LOG_PACKET ErrLog; PDIR_RESOURCE_LIST CurList; PDIR_REQUIRED_RESOURCE ReqRes; ULONG i, j; ULONG len, ErrorLogNumber, ErrLogBufferLeft; ULONG ConflictLevel; UCHAR s[8]; PWCHAR pLog; POWNER Owner; PAGED_CODE(); IDBGMSG ("\n****\n"); IDBGMSG ("Failed to satisfy the following required resource\n"); ErrLog = NULL; ErrorLogNumber = 0; // // There's a conflict in each alternative list // for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) { // // Clear position (already on pass 2) // for (i=0; i < CurList->NoRequiredResources; i++) { CurList->RequiredResource[i]->CurLoc = 0; CurList->RequiredResource[i]->RunLen = 0; CurList->RequiredResource[i]->PassNo = 2; } // // Look for settings - set ConflictLevel to pass 3 to track where the problem is // ConflictLevel = CurList->FailedLevel; CurList->RequiredResource[ConflictLevel]->PassNo = 3; InitializeListHead (&CurList->Conflict.OtherConflicts); if (IopGenNextValidResourceList (0, CurList, Dir)) { IDBGMSG ("IopLogConflict: internal error\n"); continue ; } #if IDBG if (CurList != Dir->Alternative) { DbgPrint ("the following alternate resource also failed\n"); } s[0] = s[1] = s[2] = s[3] = ' '; s[4] = 0; ReqRes = CurList->RequiredResource[ConflictLevel]; for (j=0; j < ReqRes->NoAlternatives; j++) { IopDumpIoResourceDescriptor (s, ReqRes->IoResourceDescriptor[j]); } i = CurList->Conflict.NoConflicts; if (i > SCONFLICT) { i = SCONFLICT; } for (j=0; j < i; j++) { DbgPrint (" Conflict # %d. ", j+1); switch (CurList->Conflict.EasyConflict[j].Type) { case CmResourceTypePort: DbgPrint ("IO Base %08x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr); break; case CmResourceTypeMemory: DbgPrint ("MEM Base %08x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr); break; case CmResourceTypeInterrupt: DbgPrint ("INT Line %x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr); break; case CmResourceTypeDma: DbgPrint ("DMA Channel %x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr); break; } DbgPrint (" with '%Z' ", &CurList->Conflict.EasyConflict[j].Owner->KeyName); if (CurList->Conflict.EasyConflict[j].Owner->DeviceName.Buffer) { DbgPrint ("'%Z'", &CurList->Conflict.EasyConflict[j].Owner->DeviceName); } DbgPrint ("\n"); } if (CurList->Conflict.NoConflicts > SCONFLICT) { DbgPrint (" ...\n"); DbgPrint ("Total Conflicts = %d\n", CurList->Conflict.NoConflicts); } if (!IsListEmpty (&CurList->Conflict.OtherConflicts)) { DbgPrint ("Possible settings also conflicts with the following list\n"); // bugbug - not done } #endif // // Loop for each easy conflict // i = CurList->Conflict.NoConflicts; if (i > SCONFLICT) { i = SCONFLICT; } for (j=0; j < i; j++) { if (ErrorLogNumber >= 3) { // // only add n logs for a given problem // break; } // // Allocate a new error log structure // ErrorLogNumber += 1; ErrLog = IoAllocateErrorLogEntry (DriverObject, ERROR_LOG_MAXIMUM_SIZE); if (!ErrLog) { break; } // // Initialize errorlog field and counts to append strings // RtlZeroMemory (ErrLog, sizeof (*ErrLog)); ErrLog->FinalStatus = FinalStatus; ErrLog->UniqueErrorValue = ErrorLogNumber; ErrLog->NumberOfStrings = 2; pLog = (PWCHAR) ErrLog->DumpData; ErrLog->StringOffset = (USHORT) ( ((PUCHAR) pLog) - ((PUCHAR) ErrLog) ); ErrLogBufferLeft = (ERROR_LOG_MAXIMUM_SIZE - ErrLog->StringOffset) / sizeof(WCHAR); switch (CurList->Conflict.EasyConflict[j].Type) { case CmResourceTypePort: ErrLog->ErrorCode = IO_ERR_PORT_RESOURCE_CONFLICT; break; case CmResourceTypeMemory: ErrLog->ErrorCode = IO_ERR_MEMORY_RESOURCE_CONFLICT; break; case CmResourceTypeInterrupt: ErrLog->ErrorCode = IO_ERR_INTERRUPT_RESOURCE_CONFLICT; break; case CmResourceTypeDma: ErrLog->ErrorCode = IO_ERR_DMA_RESOURCE_CONFLICT; break; } if (CurList->Conflict.EasyConflict[j].BAddr & 0xffffffff00000000) { len = swprintf (pLog, L"%X:%08X", (ULONG) (CurList->Conflict.EasyConflict[j].BAddr >> 32), (ULONG) CurList->Conflict.EasyConflict[j].BAddr ); } else { len = swprintf (pLog, L"%X", (ULONG) CurList->Conflict.EasyConflict[j].BAddr); } len += 1; // include null pLog += len; ErrLogBufferLeft -= len; Owner = CurList->Conflict.EasyConflict[j].Owner; len = Owner->KeyName.Length / sizeof(WCHAR); if (len > ErrLogBufferLeft) { len = ErrLogBufferLeft; } RtlCopyMemory (pLog, Owner->KeyName.Buffer, len * sizeof(WCHAR) ); pLog += len; ErrLogBufferLeft -= len; if (Owner->DeviceName.Buffer && ErrLogBufferLeft > 11) { len = Owner->DeviceName.Length / sizeof(WCHAR); if (len > ErrLogBufferLeft) { len = ErrLogBufferLeft; } *(pLog++) = ' '; RtlCopyMemory (pLog, Owner->DeviceName.Buffer, len * sizeof(WCHAR)); pLog += len; ErrLogBufferLeft -= len; } *(pLog++) = 0; // null terminate IoWriteErrorLogEntry ( ErrLog ); } } IDBGMSG ("****\n"); } STATIC PTENTRY IopNewTransEntry ( IN PDIR_RESREQ_LIST Dir, IN PTENTRIESBYTYPE pTypes, IN ULONG Type ) { PLTENTRY LEntry, NewTable; LEntry = pTypes->ByType[Type]; if (!LEntry || LEntry->CurEntries == MAX_ENTRIES) { // // Build a new table // NewTable = IopAllocateDirPool (Dir, sizeof (LTENTRY)); if (!NewTable) { return NULL; } pTypes->ByType[Type] = NewTable; NewTable->Next = LEntry; NewTable->CurEntries = 0; LEntry = NewTable; } return LEntry->Table + (LEntry->CurEntries++); } STATIC NTSTATUS IopAddCmDescriptorToInUseList ( IN PDIR_RESREQ_LIST Dir, IN PTENTRIESBYTYPE pTypes, IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc, IN POWNER Owner ) /*++ Routine Description: Adds Translated CmDescriptor to TLIST. Arguments: Return Value: --*/ { PTENTRY Trans; LONGLONG li; if ((CmDesc->Type == CmResourceTypePort && CmDesc->u.Port.Length == 0) || (CmDesc->Type == CmResourceTypeMemory && CmDesc->u.Memory.Length == 0)) { // no length? IDBGMSG ("IopAddCmDescriptor: Skipping zero length descriptor\n"); return STATUS_SUCCESS; } // // Get a new Trans entry in the InUseResource list or the // InUseSharableResource list // Trans = IopNewTransEntry (Dir, pTypes, CmDesc->Type); if (!Trans) { return STATUS_INSUFFICIENT_RESOURCES; } // // Fill in the Trans structure // // NOTE: turning TEntries into a splay tree would speed up the collision // detect process. Trans->Owner = Owner; #if _PNP_POWER_ Trans->Flags = TENTRY_FLAGS_IN_USE; #endif switch (CmDesc->Type) { case CmResourceTypePort: li = CmDesc->u.Port.Length - 1; Trans->BAddr = *((LONGLONG UNALIGNED *) &CmDesc->u.Port.Start); Trans->EAddr = Trans->BAddr + li; Trans->Affinity = (KAFFINITY) -1; break; case CmResourceTypeMemory: li = CmDesc->u.Memory.Length - 1; Trans->BAddr = *((LONGLONG UNALIGNED *) &CmDesc->u.Memory.Start); Trans->EAddr = Trans->BAddr + li; Trans->Affinity = (KAFFINITY) -1; break; case CmResourceTypeInterrupt: Trans->BAddr = CmDesc->u.Interrupt.Vector; Trans->EAddr = CmDesc->u.Interrupt.Vector; Trans->Affinity = CmDesc->u.Interrupt.Affinity; break; case CmResourceTypeDma: Trans->BAddr = CmDesc->u.Dma.Channel; Trans->EAddr = CmDesc->u.Dma.Channel; Trans->Affinity = (KAFFINITY) -1; break; } return STATUS_SUCCESS; } NTSTATUS IopBuildResourceDir ( IN PDIR_RESREQ_LIST ParentDir, IN PDIR_RESREQ_LIST *pDir, IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources ) /*++ Routine Description: Takes an IO_RESOURCE_REQUIREMENTS list and builds a directory for it's contents. Arguments: Return Value: --*/ { PDIR_RESREQ_LIST Dir; PIO_RESOURCE_LIST ResourceList; PIO_RESOURCE_DESCRIPTOR Descriptor, ADescriptor; PDIR_RESOURCE_LIST DirResourceList, *AltListTail; PDIR_REQUIRED_RESOURCE ReqRes; ULONG i, j, alt, cnt, acnt; PUCHAR FirstAddress, LastAddress; // // Allocate and initialize DIR structure // Dir = (PDIR_RESREQ_LIST) ExAllocatePool (PagedPool, sizeof(DIR_RESREQ_LIST)); *pDir = Dir; if (!Dir) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory (Dir, sizeof (DIR_RESREQ_LIST)); for (i=0; i < MAX_REG_HANDLES; i++) { Dir->RegHandle[i] = INVALID_HANDLE; } if (ParentDir) { Dir->FreeResReqList = ParentDir->FreeResReqList; ParentDir->FreeResReqList = Dir; } // // If no IoResources to process, the Dir structure is done // if (!IoResources) { return STATUS_SUCCESS; } // // Verify ResourceList does not exceede ListSize // ResourceList = IoResources->List; FirstAddress = (PUCHAR) ResourceList; LastAddress = (PUCHAR) IoResources + IoResources->ListSize; for (cnt=0; cnt < IoResources->AlternativeLists; cnt++) { ResourceList = (PIO_RESOURCE_LIST) (&ResourceList->Descriptors[ResourceList->Count]); if ((PUCHAR) ResourceList < FirstAddress || (PUCHAR) ResourceList > LastAddress) { DBGMSG ("IopBuildResourceDir: IO_RESOURCE_LIST.ListSize too small\n"); return STATUS_INVALID_PARAMETER; } } // // Build a directory of the block stlye structure IO_RESOURCE_REQUIREMENTS_LIST // Dir->IoResourceReq = IoResources; AltListTail = &Dir->Alternative; ResourceList = IoResources->List; for (alt=0; alt < IoResources->AlternativeLists; alt++) { // // Count number of non-alternative descriptors on this // alternative list // cnt = 0; Descriptor = ResourceList->Descriptors; for (i = ResourceList->Count; i; i--) { if (!(Descriptor->Option & IO_RESOURCE_ALTERNATIVE)) { cnt++; } Descriptor++; } // // Build alternative list structure // i = sizeof (DIR_RESOURCE_LIST) + cnt * sizeof(PVOID) * 2; DirResourceList = (PDIR_RESOURCE_LIST) IopAllocateDirPool (Dir, i); if (!DirResourceList) { return STATUS_INSUFFICIENT_RESOURCES; } // // Initialize structure // RtlZeroMemory (DirResourceList, i); DirResourceList->IoResourceList = ResourceList; // add to tail of single linked list *(AltListTail) = DirResourceList; AltListTail = &DirResourceList->Next; Descriptor = ResourceList->Descriptors; for (i = ResourceList->Count; i; i--) { if (!(Descriptor->Option & IO_RESOURCE_ALTERNATIVE)) { // // Count number of alternative descriptors // acnt = 1; ADescriptor = Descriptor + 1; while (acnt < i && ADescriptor->Option & IO_RESOURCE_ALTERNATIVE) { ADescriptor++; acnt++; } // // Allocate a required resource list // ReqRes = (PDIR_REQUIRED_RESOURCE) IopAllocateDirPool (Dir, sizeof (DIR_REQUIRED_RESOURCE) + acnt * sizeof(PVOID)); if (!ReqRes) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory (ReqRes, sizeof (DIR_REQUIRED_RESOURCE)); DirResourceList->RequiredResource[DirResourceList->NoRequiredResources] = ReqRes; DirResourceList->NoRequiredResources++; // // Fill in all the alternatives for this required resource // ReqRes->NoAlternatives = acnt; ADescriptor = Descriptor; for (j=0; j < acnt; j++) { ReqRes->IoResourceDescriptor[j] = ADescriptor; if (ADescriptor->Option & IO_RESOURCE_PREFERRED) { ReqRes->BestPref = 1; } ADescriptor++; } } // // Next descriptor // Descriptor++; } // // Next alternative resource list // ResourceList = (PIO_RESOURCE_LIST) Descriptor; } return STATUS_SUCCESS; } VOID IopFreeResourceDir ( IN PDIR_RESREQ_LIST DirResourceList ) /*++ Routine Description: Frees pool used to track a DIR_RESREQ_LIST and other assiocated resources. Also free's all pool for DIR_RESREQ_LIST's on a free list. Arguments: Return Value: --*/ { PDIR_RESREQ_LIST NextResourceList; ULONG i; PSINGLE_LIST_ENTRY pe; PUSED_HEAP ph; // // Free any allocated lists // while (DirResourceList) { NextResourceList = DirResourceList->FreeResReqList; // // Free any allocated heap // while (DirResourceList->AllocatedHeap.Next) { pe = PopEntryList (&DirResourceList->AllocatedHeap); ph = CONTAINING_RECORD(pe, USED_HEAP, FreeLink); ExFreePool (ph->FreeHeap); } // // Close any opened handles // for (i=0; i< MAX_REG_HANDLES; i++) { if (DirResourceList->RegHandle[i] != INVALID_HANDLE) { ZwClose (DirResourceList->RegHandle[i]); } } // // Free header // ExFreePool (DirResourceList); // // Next list // DirResourceList = NextResourceList; } } #if IDBG VOID IopDumpIoResourceDir ( IN PDIR_RESREQ_LIST Dir ) { PDIR_RESOURCE_LIST ResourceList; PIO_RESOURCE_DESCRIPTOR Desc; PDIR_REQUIRED_RESOURCE ReqRes; ULONG alt, i, j; UCHAR s[10]; alt = 0; for (ResourceList = Dir->Alternative; ResourceList; ResourceList = ResourceList->Next) { DbgPrint ("Alternative #%d - %d required resources\n", alt++, ResourceList->NoRequiredResources ); for (i=0; i < ResourceList->NoRequiredResources; i++) { ReqRes = ResourceList->RequiredResource[i]; for (j=0; j < ReqRes->NoAlternatives; j++) { Desc = ReqRes->IoResourceDescriptor[j]; if (j == 0) { s[0] = s[1] = s[2] = '*'; s[3] = ' '; } else { s[0] = s[1] = s[2] = s[3] = ' '; } s[4] = Desc->Option & IO_RESOURCE_PREFERRED ? 'P' : ' '; s[5] = ' '; s[6] = 0; IopDumpIoResourceDescriptor (s, Desc); } } } } VOID IopDumpIoResourceDescriptor ( IN PUCHAR Indent, IN PIO_RESOURCE_DESCRIPTOR Desc ) { switch (Desc->Type) { case CmResourceTypePort: DbgPrint ("%sIO Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n", Indent, Desc->u.Port.MinimumAddress.HighPart, Desc->u.Port.MinimumAddress.LowPart, Desc->u.Port.MaximumAddress.HighPart, Desc->u.Port.MaximumAddress.LowPart, Desc->u.Port.Alignment, Desc->u.Port.Length ); break; case CmResourceTypeMemory: DbgPrint ("%sMEM Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n", Indent, Desc->u.Memory.MinimumAddress.HighPart, Desc->u.Memory.MinimumAddress.LowPart, Desc->u.Memory.MaximumAddress.HighPart, Desc->u.Memory.MaximumAddress.LowPart, Desc->u.Memory.Alignment, Desc->u.Memory.Length ); break; case CmResourceTypeInterrupt: DbgPrint ("%sINT Min: %x, Max: %x\n", Indent, Desc->u.Interrupt.MinimumVector, Desc->u.Interrupt.MaximumVector ); break; case CmResourceTypeDma: DbgPrint ("%sDMA Min: %x, Max: %x\n", Indent, Desc->u.Dma.MinimumChannel, Desc->u.Dma.MaximumChannel ); break; } } #endif NTSTATUS IopCatagorizeDescriptors ( IN OUT PDIR_RESREQ_LIST Dir ) /*++ Routine Description: Takes a DIR_RESREQ_LIST and returns a list of resources by catagory. It is assumed that such a directory has one list of alternative descriptors per resource type. Arguments: Return Value: --*/ { PDIR_RESOURCE_LIST DirResourceList; PDIR_REQUIRED_RESOURCE ReqRes; ULONG i, j, acnt; CM_RESOURCE_TYPE type; if (!Dir->Alternative || Dir->Alternative->Next) { // there can only be one list DBGMSG ("IopCatagorizeDescriptors: too many altenative lists\n"); return STATUS_INVALID_PARAMETER_MIX; } DirResourceList = Dir->Alternative; for (i=0; i < DirResourceList->NoRequiredResources; i++) { ReqRes = DirResourceList->RequiredResource[i]; acnt = ReqRes->NoAlternatives; if (!acnt) { // shouldn't have a zero count DBGMSG ("IopCatagorizeDescriptors: no entries\n"); return STATUS_INVALID_PARAMETER_MIX; } type = ReqRes->IoResourceDescriptor[0]->Type; // verify all entries in this list are of the same type for (j=1; j < acnt; j++) { if (ReqRes->IoResourceDescriptor[j]->Type != type) { DBGMSG ("IopCatagorizeDescriptors: mixed types in alternatives\n"); return STATUS_INVALID_PARAMETER_MIX; } } if (type >= CmResourceTypeMaximum) { // unkown catagory continue; } if (DirResourceList->ResourceByType[type]) { // should only have one list per type DBGMSG ("IopCatagorizeDescriptors: multiple lists per resource type\n"); return STATUS_INVALID_PARAMETER_MIX; } DirResourceList->ResourceByType[type] = ReqRes; } return STATUS_SUCCESS; } INLINE ULONG IopDescriptorSortingWeight ( IN PIO_RESOURCE_DESCRIPTOR Descriptor ) /*++ Routine Description: Used by IopSortDescriptors --*/ { ULONG w; switch (Descriptor->Type) { case CmResourceTypeMemory: w = 4; break; case CmResourceTypeInterrupt: w = 3; break; case CmResourceTypeDma: w = 2; break; case CmResourceTypePort: w = 1; break; default: w = 0; break; } return w; } VOID IopSortDescriptors ( IN OUT PDIR_RESREQ_LIST Dir ) /*++ Routine Description: Sorts the directory entries for each decsriptor such that they descriptors are order by resource type. Arguments: Return Value: --*/ { PIO_RESOURCE_DESCRIPTOR Descriptor; PDIR_RESOURCE_LIST DirResourceList; PDIR_REQUIRED_RESOURCE ReqRes; ULONG i, j, k, acnt; ULONG w1, w2; // // Sort each require resource list by descriptor type // for (DirResourceList = Dir->Alternative; DirResourceList; DirResourceList = DirResourceList->Next) { // // Sort the descriptors by type // for (k=0; k < DirResourceList->NoRequiredResources; k++) { ReqRes = DirResourceList->RequiredResource[k]; acnt = ReqRes->NoAlternatives; for (i=0; i < acnt; i++) { w1 = IopDescriptorSortingWeight (ReqRes->IoResourceDescriptor[i]); for (j = i+1; j < acnt; j++) { w2 = IopDescriptorSortingWeight (ReqRes->IoResourceDescriptor[j]); if (w2 > w1) { Descriptor = ReqRes->IoResourceDescriptor[i]; ReqRes->IoResourceDescriptor[i] = ReqRes->IoResourceDescriptor[j]; ReqRes->IoResourceDescriptor[j] = Descriptor; w1 = w2; } } } } } }