Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

694 lines
23 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. resource.c
  5. Abstract:
  6. Common routines for handling resource requirements
  7. Author:
  8. John Vert (jvert) 10/25/1997
  9. Revision History:
  10. --*/
  11. #include "agplib.h"
  12. PCM_RESOURCE_LIST
  13. ApSplitResourceList(
  14. IN PCM_RESOURCE_LIST ResourceList,
  15. OUT PCM_RESOURCE_LIST *NewResourceList
  16. );
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE, AgpFilterResourceRequirements)
  19. #pragma alloc_text(PAGE, AgpStartTarget)
  20. #pragma alloc_text(PAGE, ApSplitResourceList)
  21. #endif
  22. static BOOLEAN ResourceConflict = FALSE;
  23. NTSTATUS
  24. AgpFilterResourceRequirements(
  25. IN PDEVICE_OBJECT DeviceObject,
  26. IN PIRP Irp,
  27. IN PTARGET_EXTENSION Extension
  28. )
  29. /*++
  30. Routine Description:
  31. Completion routine for IRP_MN_QUERY_RESOURCE_REQUIREMENTS. This adds on the
  32. AGP resource requirements.
  33. Arguments:
  34. DeviceObject - Supplies the device object
  35. Irp - Supplies the IRP_MN_QUERY_RESOURCE_REQUIREMENTS Irp
  36. Extension - Supplies the device extension
  37. Return Value:
  38. NTSTATUS
  39. --*/
  40. {
  41. BOOLEAN SwapDescriptor;
  42. ULONG SwapLength;
  43. ULONG ApertureSize;
  44. NTSTATUS Status;
  45. ULONG AddCount;
  46. PHYSICAL_ADDRESS CurrentBase;
  47. PHYSICAL_ADDRESS MaxAddr;
  48. ULONG CurrentSizeInPages;
  49. PIO_RESOURCE_REQUIREMENTS_LIST OldRequirements;
  50. PIO_RESOURCE_REQUIREMENTS_LIST NewRequirements;
  51. ULONG NewSize;
  52. ULONG Alternative;
  53. PIO_RESOURCE_LIST OldResourceList;
  54. PIO_RESOURCE_LIST NewResourceList;
  55. PIO_RESOURCE_DESCRIPTOR Descriptor;
  56. PIO_STACK_LOCATION IrpSp;
  57. PIO_RESOURCE_LIST ApertureRequirements = NULL;
  58. ULONG i;
  59. PAGED_CODE();
  60. AGPLOG(AGP_NOISE,
  61. ("AgpQueryResourceRequirements - IRP %08lx, resource %08lx\n",
  62. Irp,
  63. Irp->IoStatus.Information));
  64. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  65. //
  66. // Create a new resource requirements list with our current aperture
  67. // settings tacked on the end.
  68. //
  69. OldRequirements = IrpSp->Parameters.FilterResourceRequirements.IoResourceRequirementList;
  70. if (OldRequirements == NULL) {
  71. //STATUS_INVALID_DEVICE_REQUEST
  72. // PNP helpfully passes us a NULL pointer instead of an empty resource list
  73. // when the bridge is disabled. In this case we will ignore this irp and not
  74. // add on our requirements since they are not going to be used anyway.
  75. //
  76. return(STATUS_SUCCESS);
  77. }
  78. //
  79. // Get the current GART aperture.
  80. //
  81. Status = AgpQueryAperture(GET_AGP_CONTEXT(Extension),
  82. &CurrentBase,
  83. &CurrentSizeInPages,
  84. &ApertureRequirements);
  85. if (!NT_SUCCESS(Status)) {
  86. AGPLOG(AGP_CRITICAL,
  87. ("AgpQueryResourceRequirements - AgpQueryAperture %08lx failed %08lx\n",
  88. Extension,
  89. Status));
  90. return(Status);
  91. }
  92. ApertureSize = (CurrentSizeInPages * PAGE_SIZE);
  93. MaxAddr.QuadPart = CurrentBase.QuadPart + ApertureSize - 1;
  94. AGPLOG(AGP_NOISE,
  95. ("AgpQueryResourceRequirements - aperture at %I64x, length %08lx pages, Requirements %08lx\n",
  96. CurrentBase.QuadPart,
  97. CurrentSizeInPages,
  98. ApertureRequirements));
  99. //
  100. // We will add IO_RESOURCE_DESCRIPTORs to each alternative.
  101. //
  102. // The first one is a private data type marked with our signature. This is
  103. // a marker so that we know which descriptors are ours so we can remove
  104. // them later.
  105. //
  106. // The second is the actual descriptor for the current aperture settings.
  107. // This is marked as preferred.
  108. //
  109. // Following this is the requirements returned from AgpQueryAperture. These
  110. // get marked as alternatives.
  111. //
  112. AddCount = 2;
  113. //
  114. // Enumerate the old list looking for any preferred descriptor that
  115. // conflicts with our preferred settings; if we find one, then the BIOS
  116. // is whack, and we will throw out our preferred descriptor, and let PnP
  117. // choose from our alternates
  118. //
  119. ResourceConflict = FALSE;
  120. OldResourceList = &OldRequirements->List[0];
  121. for (Alternative = 0; Alternative < OldRequirements->AlternativeLists;
  122. Alternative++) {
  123. for (i = 0; i < OldResourceList->Count; i++) {
  124. Descriptor = &OldResourceList->Descriptors[i];
  125. if ((Descriptor->Option == IO_RESOURCE_PREFERRED) &&
  126. (Descriptor->Type == CmResourceTypeMemory)) {
  127. if (((Descriptor->u.Memory.MinimumAddress.QuadPart >=
  128. CurrentBase.QuadPart) &&
  129. (Descriptor->u.Memory.MinimumAddress.QuadPart <=
  130. MaxAddr.QuadPart)) ||
  131. ((Descriptor->u.Memory.MaximumAddress.QuadPart >=
  132. CurrentBase.QuadPart) &&
  133. (Descriptor->u.Memory.MaximumAddress.QuadPart <=
  134. MaxAddr.QuadPart)) ||
  135. ((Descriptor->u.Memory.MinimumAddress.QuadPart <
  136. CurrentBase.QuadPart) &&
  137. (Descriptor->u.Memory.MaximumAddress.QuadPart >
  138. MaxAddr.QuadPart))) {
  139. AGPLOG(AGP_CRITICAL,
  140. ("AgpQueryResourceRequirements - Conflicted "
  141. "resource detected: %I64X - %I64X\n",
  142. Descriptor->u.Memory.MinimumAddress.QuadPart,
  143. Descriptor->u.Memory.MaximumAddress.QuadPart));
  144. //
  145. // This preferred descriptor is in conflic with our AGP
  146. // preferred setting
  147. //
  148. #if defined(_IA64_)
  149. AGPLOG(AGP_CRITICAL, ("Please contact system manufacturer "
  150. "for a BIOS upgrade.\n"));
  151. #else // _IA64_
  152. AddCount = 1;
  153. ResourceConflict = TRUE;
  154. #endif // _IA64_
  155. break;
  156. }
  157. }
  158. }
  159. OldResourceList = (PIO_RESOURCE_LIST)(OldResourceList->Descriptors +
  160. OldResourceList->Count);
  161. }
  162. //
  163. //
  164. // For IA64, PnP cannot reassign the aperture base, so we can only use
  165. // the "preferred" descriptor
  166. //
  167. if (ApertureRequirements) {
  168. AddCount += ApertureRequirements->Count;
  169. }
  170. NewSize = OldRequirements->ListSize;
  171. NewSize += sizeof(IO_RESOURCE_DESCRIPTOR) *
  172. (AddCount * OldRequirements->AlternativeLists);
  173. NewRequirements = ExAllocatePool(PagedPool, NewSize);
  174. if (NewRequirements == NULL) {
  175. if (ApertureRequirements) {
  176. ExFreePool(ApertureRequirements);
  177. }
  178. return(STATUS_INSUFFICIENT_RESOURCES);
  179. }
  180. NewRequirements->ListSize = NewSize;
  181. NewRequirements->InterfaceType = OldRequirements->InterfaceType;
  182. NewRequirements->BusNumber = OldRequirements->BusNumber;
  183. NewRequirements->SlotNumber = OldRequirements->SlotNumber;
  184. NewRequirements->AlternativeLists = OldRequirements->AlternativeLists;
  185. //
  186. // Append our requirement to each alternative resource list.
  187. //
  188. NewResourceList = &NewRequirements->List[0];
  189. OldResourceList = &OldRequirements->List[0];
  190. for (Alternative = 0; Alternative < OldRequirements->AlternativeLists; Alternative++) {
  191. //
  192. // Copy the old resource list into the new one.
  193. //
  194. NewResourceList->Version = OldResourceList->Version;
  195. NewResourceList->Revision = OldResourceList->Revision;
  196. NewResourceList->Count = OldResourceList->Count + AddCount;
  197. RtlCopyMemory(&NewResourceList->Descriptors[0],
  198. &OldResourceList->Descriptors[0],
  199. OldResourceList->Count * sizeof(IO_RESOURCE_DESCRIPTOR));
  200. Descriptor = &NewResourceList->Descriptors[OldResourceList->Count];
  201. //
  202. // Append the marker descriptor
  203. //
  204. Descriptor->Option = 0;
  205. Descriptor->Flags = 0;
  206. Descriptor->Type = CmResourceTypeDevicePrivate;
  207. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  208. Descriptor->u.DevicePrivate.Data[0] = AgpPrivateResource;
  209. Descriptor->u.DevicePrivate.Data[1] = 1;
  210. ++Descriptor;
  211. //
  212. // Append the new descriptor
  213. //
  214. if (!ResourceConflict) {
  215. Descriptor->Option = IO_RESOURCE_PREFERRED;
  216. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE |
  217. CM_RESOURCE_MEMORY_PREFETCHABLE;
  218. Descriptor->Type = CmResourceTypeMemory;
  219. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  220. Descriptor->u.Memory.Length = CurrentSizeInPages * PAGE_SIZE;
  221. Descriptor->u.Memory.Alignment = CurrentSizeInPages * PAGE_SIZE;
  222. Descriptor->u.Memory.MinimumAddress = CurrentBase;
  223. Descriptor->u.Memory.MaximumAddress = MaxAddr;
  224. ++Descriptor;
  225. }
  226. //
  227. // Append the alternatives
  228. //
  229. if (ApertureRequirements) {
  230. SwapDescriptor = FALSE;
  231. for (i = 0; i < ApertureRequirements->Count; i++) {
  232. //
  233. // Make sure this descriptor makes sense
  234. //
  235. ASSERT(ApertureRequirements->Descriptors[i].Flags ==
  236. (CM_RESOURCE_MEMORY_READ_WRITE |
  237. CM_RESOURCE_MEMORY_PREFETCHABLE));
  238. ASSERT(ApertureRequirements->Descriptors[i].Type ==
  239. CmResourceTypeMemory);
  240. ASSERT(ApertureRequirements->Descriptors[i].ShareDisposition ==
  241. CmResourceShareDeviceExclusive);
  242. *Descriptor = ApertureRequirements->Descriptors[i];
  243. //
  244. // In this case we nuked our preferred descriptor so mark the
  245. // first alternate as preferred
  246. //
  247. if ((i == 0) && ResourceConflict) {
  248. Descriptor->Option = IO_RESOURCE_PREFERRED;
  249. if (Descriptor->u.Memory.Length != ApertureSize) {
  250. SwapLength = Descriptor->u.Memory.Length;
  251. Descriptor->u.Memory.Length = ApertureSize;
  252. Descriptor->u.Memory.Alignment = ApertureSize;
  253. SwapDescriptor = TRUE;
  254. }
  255. } else {
  256. Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
  257. if (SwapDescriptor) {
  258. if (Descriptor->u.Memory.Length == ApertureSize) {
  259. Descriptor->u.Memory.Length = SwapLength;
  260. Descriptor->u.Memory.Alignment = SwapLength;
  261. SwapDescriptor = FALSE;
  262. }
  263. }
  264. }
  265. ++Descriptor;
  266. }
  267. }
  268. //
  269. // Advance to next resource list
  270. //
  271. NewResourceList = (PIO_RESOURCE_LIST)(NewResourceList->Descriptors + NewResourceList->Count);
  272. OldResourceList = (PIO_RESOURCE_LIST)(OldResourceList->Descriptors + OldResourceList->Count);
  273. }
  274. AGPLOG(AGP_NOISE,
  275. ("AgpQueryResourceRequirements - IRP %p, old resources %p, new resources %p\n",
  276. Irp,
  277. OldRequirements,
  278. NewRequirements));
  279. IrpSp->Parameters.FilterResourceRequirements.IoResourceRequirementList = NewRequirements;
  280. Irp->IoStatus.Information = (ULONG_PTR)NewRequirements;
  281. ExFreePool(OldRequirements);
  282. if (ApertureRequirements) {
  283. ExFreePool(ApertureRequirements);
  284. }
  285. return(STATUS_SUCCESS);
  286. }
  287. NTSTATUS
  288. AgpQueryResources(
  289. IN PDEVICE_OBJECT DeviceObject,
  290. IN PIRP Irp,
  291. IN PTARGET_EXTENSION Extension
  292. )
  293. /*++
  294. Routine Description:
  295. Completion routine for IRP_MN_QUERY_RESOURCES. This adds on the
  296. AGP resources
  297. Arguments:
  298. DeviceObject - Supplies the device object
  299. Irp - Supplies the IRP_MN_QUERY_RESOURCES Irp
  300. Extension - Supplies the device extension
  301. Return Value:
  302. NTSTATUS
  303. --*/
  304. {
  305. if (Irp->PendingReturned) {
  306. IoMarkIrpPending(Irp);
  307. }
  308. AGPLOG(AGP_NOISE,
  309. ("AgpQueryResources - IRP %08lx, resource %08lx\n",
  310. Irp,
  311. Irp->IoStatus.Information));
  312. return(STATUS_SUCCESS);
  313. }
  314. NTSTATUS
  315. AgpStartTarget(
  316. IN PIRP Irp,
  317. IN PTARGET_EXTENSION Extension
  318. )
  319. /*++
  320. Routine Description:
  321. Filters out the AGP-specific resource requirements on a
  322. IRP_MN_START_DEVICE Irp.
  323. Arguments:
  324. Irp - supplies the IRP_MN_START_DEVICE Irp.
  325. Extension - Supplies the device extension.
  326. Return Value:
  327. NTSTATUS
  328. --*/
  329. {
  330. PIO_STACK_LOCATION irpSp;
  331. PCM_RESOURCE_LIST NewResources;
  332. PCM_RESOURCE_LIST NewResourcesTranslated;
  333. PCM_RESOURCE_LIST AgpAllocatedResources;
  334. PCM_RESOURCE_LIST AgpAllocatedResourcesTranslated;
  335. NTSTATUS Status;
  336. PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
  337. PAGED_CODE();
  338. irpSp = IoGetCurrentIrpStackLocation(Irp);
  339. AGPLOG(AGP_NOISE,
  340. ("AgpStartTarget - IRP %08lx, resource %08lx\n",
  341. Irp,
  342. Irp->IoStatus.Information));
  343. if (irpSp->Parameters.StartDevice.AllocatedResources != NULL) {
  344. KEVENT event;
  345. //
  346. // Find our private descriptors and split them out into
  347. // our own resource list
  348. //
  349. Extension->Resources = ApSplitResourceList(irpSp->Parameters.StartDevice.AllocatedResources,
  350. &NewResources);
  351. Extension->ResourcesTranslated = ApSplitResourceList(irpSp->Parameters.StartDevice.AllocatedResourcesTranslated,
  352. &NewResourcesTranslated);
  353. //
  354. // Split resources will return two NULL lists when we run low
  355. // memory, so we only need to check one of its return values
  356. //
  357. if ((NewResources == NULL) || (NewResourcesTranslated == NULL)) {
  358. Status = STATUS_INSUFFICIENT_RESOURCES;
  359. } else {
  360. ASSERT(Extension->Resources->Count == 1);
  361. ASSERT(Extension->Resources->List[0].PartialResourceList.Count == 1);
  362. Descriptor = &Extension->Resources->List[0].PartialResourceList.PartialDescriptors[0];
  363. ASSERT(Descriptor->Type == CmResourceTypeMemory);
  364. Extension->GartBase = Descriptor->u.Memory.Start;
  365. Extension->GartLengthInPages = Descriptor->u.Memory.Length / PAGE_SIZE;
  366. //
  367. // Set the new GART aperture
  368. //
  369. Status = AgpSetAperture(GET_AGP_CONTEXT(Extension),
  370. Extension->GartBase,
  371. Extension->GartLengthInPages);
  372. }
  373. ASSERT(NT_SUCCESS(Status));
  374. Irp->IoStatus.Status = Status ;
  375. if (!NT_SUCCESS(Status) ) {
  376. AGPLOG(AGP_CRITICAL,
  377. ("AgpStartTarget - AgpSetAperture to %I64X, %08lx failed %08lx\n",
  378. Extension->GartBase.QuadPart,
  379. Extension->GartLengthInPages * PAGE_SIZE,
  380. Status));
  381. Irp->IoStatus.Status = Status;
  382. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  383. if (NewResources != NULL) {
  384. ExFreePool(NewResources);
  385. ExFreePool(Extension->Resources);
  386. Extension->Resources = NULL;
  387. }
  388. if (NewResourcesTranslated != NULL) {
  389. ExFreePool(NewResourcesTranslated);
  390. ExFreePool(Extension->ResourcesTranslated);
  391. Extension->ResourcesTranslated = NULL;
  392. }
  393. return(Status);
  394. }
  395. KeInitializeEvent(&event, NotificationEvent, FALSE);
  396. //
  397. // Set up the new parameters for the PCI driver.
  398. //
  399. irpSp->Parameters.StartDevice.AllocatedResources = NewResources;
  400. irpSp->Parameters.StartDevice.AllocatedResourcesTranslated = NewResourcesTranslated;
  401. IoCopyCurrentIrpStackLocationToNext(Irp);
  402. IoSetCompletionRoutine(Irp,
  403. AgpSetEventCompletion,
  404. &event,
  405. TRUE,
  406. TRUE,
  407. TRUE);
  408. //
  409. // Pass down the driver stack
  410. //
  411. Status = IoCallDriver(Extension->CommonExtension.AttachedDevice, Irp);
  412. //
  413. // If we did things asynchronously then wait on our event
  414. //
  415. if (Status == STATUS_PENDING) {
  416. //
  417. // We do a KernelMode wait so that our stack where the event is
  418. // doesn't get paged out!
  419. //
  420. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  421. Status = Irp->IoStatus.Status;
  422. }
  423. ExFreePool(irpSp->Parameters.StartDevice.AllocatedResources);
  424. ExFreePool(irpSp->Parameters.StartDevice.AllocatedResourcesTranslated);
  425. IoCompleteRequest(Irp, IO_NO_INCREMENT) ;
  426. return Status;
  427. }
  428. //
  429. // The bridge is disabled, we have been passed a NULL pointer
  430. // instead of an empty resource list. There is nothing to do other
  431. // than pass down the irp
  432. //
  433. IoSkipCurrentIrpStackLocation(Irp);
  434. return(IoCallDriver(Extension->CommonExtension.AttachedDevice, Irp));
  435. }
  436. PCM_RESOURCE_LIST
  437. ApSplitResourceList(
  438. IN PCM_RESOURCE_LIST ResourceList,
  439. OUT PCM_RESOURCE_LIST *NewResourceList
  440. )
  441. /*++
  442. Routine Description:
  443. Splits out the AGP-specific resources from a resource list.
  444. Arguments:
  445. ResourceList - Supplies the resource list.
  446. NewResourceList - Returns the new resource list with the AGP-specific
  447. resources stripped out.
  448. Return Value:
  449. Pointer to the AGP-specific resource list
  450. --*/
  451. {
  452. ULONG Size;
  453. ULONG FullCount;
  454. ULONG PartialCount;
  455. PCM_FULL_RESOURCE_DESCRIPTOR Full, NewFull, AgpFull;
  456. PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, NewPartial, AgpPartial;
  457. PCM_RESOURCE_LIST NewList;
  458. PCM_RESOURCE_LIST AgpList;
  459. ULONG NextAgp=0;
  460. PAGED_CODE();
  461. //
  462. // First walk through the source resource list and figure out how big it
  463. // is. The two resulting resource lists must be smaller than this, so we
  464. // will just allocate them to be that size and not worry about it.
  465. //
  466. Size = sizeof(CM_RESOURCE_LIST) - sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
  467. Full = &ResourceList->List[0];
  468. for (FullCount=0; FullCount<ResourceList->Count; FullCount++) {
  469. Size += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
  470. PartialCount = Full->PartialResourceList.Count;
  471. Size += (PartialCount-1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  472. Full = (PCM_FULL_RESOURCE_DESCRIPTOR)(&Full->PartialResourceList.PartialDescriptors[PartialCount]);
  473. }
  474. //
  475. // Allocate two additional lists
  476. //
  477. NewList = ExAllocatePool(PagedPool, Size);
  478. if (NewList == NULL) {
  479. *NewResourceList = NULL;
  480. return(NULL);
  481. }
  482. AgpList = ExAllocatePool(PagedPool, Size);
  483. if (AgpList == NULL) {
  484. ExFreePool(NewList);
  485. *NewResourceList = NULL;
  486. return(NULL);
  487. }
  488. //
  489. // Initialize both new resource lists to have the same number
  490. // of CM_FULL_RESOURCE_DESCRIPTORs. If any turn out to be empty,
  491. // we will adjust the count.
  492. //
  493. NewList->Count = AgpList->Count = ResourceList->Count;
  494. //
  495. // Walk through each CM_FULL_RESOURCE_DESCRIPTOR, copying as we go.
  496. //
  497. Full = &ResourceList->List[0];
  498. NewFull = &NewList->List[0];
  499. AgpFull = &AgpList->List[0];
  500. for (FullCount = 0;FullCount < ResourceList->Count; FullCount++) {
  501. NewFull->InterfaceType = AgpFull->InterfaceType = Full->InterfaceType;
  502. NewFull->BusNumber = AgpFull->BusNumber = Full->BusNumber;
  503. //
  504. // Initialize the partial resource list header
  505. //
  506. NewFull->PartialResourceList.Version = Full->PartialResourceList.Version;
  507. AgpFull->PartialResourceList.Version = Full->PartialResourceList.Version;
  508. NewFull->PartialResourceList.Revision = Full->PartialResourceList.Revision;
  509. AgpFull->PartialResourceList.Revision = Full->PartialResourceList.Revision;
  510. NewFull->PartialResourceList.Count = AgpFull->PartialResourceList.Count = 0;
  511. NewPartial = &NewFull->PartialResourceList.PartialDescriptors[0];
  512. AgpPartial = &AgpFull->PartialResourceList.PartialDescriptors[0];
  513. for (PartialCount = 0; PartialCount < Full->PartialResourceList.Count; PartialCount++) {
  514. Partial = &Full->PartialResourceList.PartialDescriptors[PartialCount];
  515. if ((Partial->Type == CmResourceTypeDevicePrivate) &&
  516. (Partial->u.DevicePrivate.Data[0] == AgpPrivateResource)) {
  517. //
  518. // Found one of our private marker descriptors
  519. //
  520. // For now, the only kind we should see indicates we skip one descriptor
  521. //
  522. ASSERT(NextAgp == 0);
  523. ASSERT(Partial->u.DevicePrivate.Data[1] == 1);
  524. NextAgp = Partial->u.DevicePrivate.Data[1];
  525. ASSERT(PartialCount+NextAgp < Full->PartialResourceList.Count);
  526. } else {
  527. //
  528. // if NextAgp is set, this descriptor goes in the AGP-specific list.
  529. // Otherwise, it goes in the new list.
  530. //
  531. if (NextAgp > 0) {
  532. --NextAgp;
  533. *AgpPartial++ = *Partial;
  534. ++AgpFull->PartialResourceList.Count;
  535. } else {
  536. *NewPartial++ = *Partial;
  537. ++NewFull->PartialResourceList.Count;
  538. }
  539. }
  540. }
  541. //
  542. // Finished this CM_PARTIAL_RESOURCE_LIST, advance to the next CM_FULL_RESOURCE_DESCRIPTOR
  543. //
  544. if (NewFull->PartialResourceList.Count == 0) {
  545. //
  546. // we can just reuse this partial resource descriptor as it is empty
  547. //
  548. --NewList->Count;
  549. } else {
  550. NewFull = (PCM_FULL_RESOURCE_DESCRIPTOR)NewPartial;
  551. }
  552. if (AgpFull->PartialResourceList.Count == 0) {
  553. //
  554. // we can just reuse this partial resource descriptor as it is empty
  555. //
  556. --AgpList->Count;
  557. } else {
  558. AgpFull = (PCM_FULL_RESOURCE_DESCRIPTOR)NewPartial;
  559. }
  560. }
  561. *NewResourceList = NewList;
  562. return(AgpList);
  563. }