ReactOS  0.4.15-dev-1632-g4e289ce
fxchildlist.cpp
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft Corporation. All rights reserved.
4 
5 Module Name:
6 
7  FxChildList.cpp
8 
9 Abstract:
10 
11  This module implements the FxChildList class
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19  Kernel mode only
20 
21 Revision History:
22 
23 --*/
24 
25 #include "fxcorepch.hpp"
26 
27 extern "C" {
28 // #include "FxChildList.tmh"
29 }
30 
33  __in ULONG AddressDescriptionSize,
35  )
36 {
39  this, WDF_ALIGN_SIZE_UP(sizeof(*this), sizeof(PVOID)));
40 
42  AddressDescriptionSize;
43 
48  WDF_ALIGN_SIZE_UP(AddressDescriptionSize, sizeof(PVOID)));
49 
52  }
53 
56 
58 
60 
64 
65  //
66  // The parent DO can go away while the child still exists (stuck in a
67  // suprise remove state w/an open handle). As such, when the parent is
68  // destroyed, it will release its reference on the FxChildList. Each
69  // description will have its own reference to the list to keep the list
70  // alive as long as the child DO exists.
71  //
72  m_DeviceList->ADDREF(this);
73 }
74 
76 {
77  m_DeviceList->RELEASE(this);
78 }
79 
81 PVOID
83  __in size_t AllocatorBlock,
84  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
85  __in size_t TotalDescriptionSize
86  )
87 {
88  PVOID p;
89 
90  UNREFERENCED_PARAMETER(AllocatorBlock);
91 
92  p = FxPoolAllocate(FxDriverGlobals, NonPagedPool, TotalDescriptionSize);
93 
94  if (p != NULL) {
95  RtlZeroMemory(p, TotalDescriptionSize);
96  }
97 
98  return p;
99 }
100 
101 VOID
103  VOID
104  )
105 {
106  KIRQL irql;
107 
111 }
112 
113 BOOLEAN
115  VOID
116  )
117 /*++
118 
119 Routine Description:
120  This function tells the caller if the description has been reported missing
121  to the Pnp manager. It does not change the actual state of the description,
122  unlike IsDeviceRemoved().
123 
124 Arguments:
125  None
126 
127 Return Value:
128  TRUE if it has been reported missing, FALSE otherwise
129 
130  --*/
131 {
132  KIRQL irql;
133  BOOLEAN result;
134 
137  result = TRUE;
138  }
139  else {
140  result = FALSE;
141  }
143 
144  return result;
145 }
146 
147 BOOLEAN
149  VOID
150  )
151 {
152  KIRQL irql;
153  BOOLEAN removed;
155 
156  pList = GetParentList();
157  removed = FALSE;
159 
161 
163 
165  //
166  // We should delete this entry as it was reported missing.
167  //
169 
171 
172  //
173  // Remove from the current list if no scan going on.
174  // Note that the description entry can't be removed from list if scan
175  // count is > 0 because it might be part of an iterator that driver is
176  // still using to iterate thru the child list.
177  //
178  if (pList->GetScanCount() == 0) {
179  //
180  // Remove from the current list
181  //
184  }
185  else {
186  //
187  // The entry will be removed and deleted when scan count goes to
188  // zero by the scanning thread, so make sure pdo deosn't reference
189  // the entry any more.
190  //
192  if (m_Pdo != NULL) {
194  }
195  }
196 
197  removed = TRUE;
198 
199  //
200  // No need to add a reference to m_DeviceList becuase as we hold a
201  // reference to it already. This reference is bound by the lifetime
202  // of this object, so we can always safely touch m_DeviceList even if
203  // the FDO is gone before the child is removed.
204  //
205  }
206 
208 
209  return removed;
210 }
211 
212 VOID
214  VOID
215  )
216 {
217  LIST_ENTRY freeHead;
218  KIRQL irql;
220 
222 
223  pList = GetParentList();
224  InitializeListHead(&freeHead);
226 
227  //
228  // Remove from the current list. In some cases the entry may not be in any
229  // list in which case RemoveEntryList() will be a noop.
230  // Note that the description entry can't be removed from list if scan count
231  // is > 0 because it might be part of an iterator that driver is still using
232  // to iterate thru the child list.
233  //
234  if (pList->GetScanCount() == 0 || IsListEmpty(&m_DescriptionLink)) {
236 
237  //
238  // Instead of reimplementing a single description cleanup, just use the
239  // version which cleans up a list.
240  //
241  InsertTailList(&freeHead, &m_DescriptionLink);
242  }
243  else {
244  //
245  // The entry will be removed when scan count goes to zero.
246  //
250  }
251 
253 
254  m_DeviceList->DrainFreeListHead(&freeHead);
255 }
256 
260  __inout PLIST_ENTRY FreeListHead
261  )
262 {
263  FxDeviceDescriptionEntry* pNewEntry;
265 
266  pNewEntry = new(m_DeviceList->GetDriverGlobals(),
271 
272  if (pNewEntry == NULL) {
273  return NULL;
274  }
275 
278 
282  }
283 
284  if (NT_SUCCESS(status)) {
285  pNewEntry->m_FoundInLastScan = TRUE;
286  }
287  else {
288  //
289  // Free it later
290  //
291  InsertTailList(FreeListHead, &pNewEntry->m_DescriptionLink);
292  pNewEntry = NULL;
293  }
294 
295  return pNewEntry;
296 }
297 
299  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
300  __in size_t TotalDescriptionSize,
303  ) :
305  m_TotalDescriptionSize(TotalDescriptionSize),
306  m_EvtCreateDevice(FxDriverGlobals),
307  m_EvtScanForChildren(FxDriverGlobals)
308 {
309  //
310  // Transaction link into list of FxChildList pointers maintained by
311  // FxDevice's pnp package.
312  //
314 
315  m_Device = Device;
316 
319 
324 
328 
332 
334 
337  m_IsAdded = FALSE;
338 
339  m_EnumRetries = 0;
340 
341  m_ScanTag = NULL;
342  m_ScanCount = 0;
343 
344  //
345  // We want all waiters on the event to be satisfied, not just the first one
346  //
348 
350 }
351 
352 BOOLEAN
354  VOID
355  )
356 {
357  if (m_IsAdded) {
358  ASSERT(m_Device != NULL);
359  m_Device->RemoveChildList(this);
360  }
361 
362  return TRUE;
363 }
364 
366 NTSTATUS
369  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
370  __in PWDF_OBJECT_ATTRIBUTES ListAttributes,
371  __in size_t TotalDescriptionSize,
373  __in PWDF_CHILD_LIST_CONFIG ListConfig,
375  )
376 {
377  NTSTATUS ntStatus;
378  FxChildList *childList = NULL;
379 
380  //
381  // Initialize
382  //
383  *ChildList = NULL;
384 
385  //
386  // Allocate a new child list object
387  //
388  childList = new(FxDriverGlobals, ListAttributes)
389  FxChildList(FxDriverGlobals, TotalDescriptionSize, Device, Static);
390  if (childList == NULL) {
393  "No memory for WDFCHILDLIST handle, %!STATUS!",
394  ntStatus);
395  goto exit;
396  }
397 
398  //
399  // Initialize the child list object
400  //
401  childList->Initialize(ListConfig);
402 
403  *ChildList = childList;
404  ntStatus = STATUS_SUCCESS;
405 
406 exit:
407  if (!NT_SUCCESS(ntStatus)) {
408  if (NULL != childList) {
409  childList->DeleteFromFailedCreate();
410  }
411  }
412  return ntStatus;
413 }
414 
416 VOID
419  )
420 {
421  //
422  // Driver cannot call WdfObjectDelete on this handle
423  //
424  MarkNoDeleteDDI();
425 
426  m_IdentificationDescriptionSize = Config->IdentificationDescriptionSize;
427  m_AddressDescriptionSize = Config->AddressDescriptionSize;
428 
429  m_EvtCreateDevice.m_Method = Config->EvtChildListCreateDevice;
430  m_EvtScanForChildren.m_Method = Config->EvtChildListScanForChildren;
431 
432  m_EvtIdentificationDescriptionDuplicate = Config->EvtChildListIdentificationDescriptionDuplicate;
433  m_EvtIdentificationDescriptionCopy = Config->EvtChildListIdentificationDescriptionCopy;
434  m_EvtIdentificationDescriptionCleanup = Config->EvtChildListIdentificationDescriptionCleanup;
435  m_EvtIdentificationDescriptionCompare = Config->EvtChildListIdentificationDescriptionCompare;
436 
437  m_EvtAddressDescriptionDuplicate = Config->EvtChildListAddressDescriptionDuplicate;
438  m_EvtAddressDescriptionCopy = Config->EvtChildListAddressDescriptionCopy;
439  m_EvtAddressDescriptionCleanup = Config->EvtChildListAddressDescriptionCleanup;
440 
441  m_EvtChildListDeviceReenumerated = Config->EvtChildListDeviceReenumerated;
442 
443  //
444  // Add this ChildList to the parent device's list of children lists.
445  //
446  m_Device->AddChildList(this);
447  m_IsAdded = TRUE;
448 }
449 
450 WDFDEVICE
452  VOID
453  )
454 {
455  return m_Device->GetHandle();
456 }
457 
458 FxDevice*
461  )
462 {
464  FxDevice* device;
466  KIRQL irql;
467 
468  device = NULL;
469 
471 
473  Info->IdentificationDescription);
474 
475  if (pEntry != NULL && pEntry->m_ModificationState == ModificationInsert) {
477  }
478  else {
480  Info->IdentificationDescription);
481 
482  if (pEntry != NULL) {
483  if (pEntry->m_DescriptionState == DescriptionPresentNeedsInstantiation) {
485  }
486  else {
488  device = pEntry->m_Pdo;
489  }
490  }
491  else {
493  }
494  }
495 
496  if (pEntry != NULL && Info->AddressDescription != NULL) {
497  CopyAddress(Info->AddressDescription,
498  pEntry->m_AddressDescription);
499  }
500 
502 
503  Info->Status = status;
504 
505  return device;
506 }
507 
509 NTSTATUS
513  )
514 {
517  KIRQL irql;
518 
520 
523 
524  if (pEntry == NULL) {
527  }
528 
529  if (pEntry != NULL) {
530  CopyAddress(AddressDescription, pEntry->m_AddressDescription);
532  }
533  else {
535  }
536 
538 
539  return status;
540 }
541 
542 VOID
546  )
547 {
548  KIRQL irql;
549 
551  CopyAddress(AddressDescription, Entry->m_AddressDescription);
553 }
554 
555 VOID
557  __out_opt PULONG ScanTag
558  )
559 {
562  KIRQL irql;
563 
565 
566  // KeClearEvent is faster than KeResetEvent for putting event to not-signaled state
567  m_ScanEvent.Clear();
568  m_ScanCount++;
569 
572  "Begin scan on WDFCHILDLIST %p, scan count %d",
574 
575  if (ScanTag != NULL) {
576  if (m_ScanTag != NULL) {
578  }
579 
580  *ScanTag = ScanTagActive;
581  m_ScanTag = ScanTag;
582  }
583 
584  //
585  // Start by walking over all entries and setting their FoundInLastScan
586  // fields to FALSE. We need to set both present items in the Desc list
587  // and inserts in the Mod list. It's actually easier just to walk over
588  // everything.
589  //
592  ple = ple->Flink) {
594  pEntry->m_FoundInLastScan = FALSE;
595  }
596 
599  ple = ple->Flink) {
601  pEntry->m_FoundInLastScan = FALSE;
602  }
603 
605 }
606 
607 VOID
609  __inout_opt PULONG ScanTag
610  )
611 {
612  PLIST_ENTRY pCur, pNext;
613  LIST_ENTRY freeHead;
615  KIRQL irql;
616 
617  InitializeListHead(&freeHead);
618 
620 
621  if (ScanTag != NULL) {
622  if (*ScanTag != ScanTagActive) {
623  ASSERT(*ScanTag == ScanTagCancelled);
625  return;
626  }
627 
628  *ScanTag = ScanTagFinished;
629  m_ScanTag = NULL;
630  }
631 
632  m_ScanCount--;
633 
636  "End scan on WDFCHILDLIST %p, scan count %d",
638 
639  if (m_ScanCount == 0) {
640  //
641  // Walk over all modification entries and remove any pending insert that
642  // wasn't seen in the scan. Note that MarkDescriptionNotPresentWorker will
643  // enqueue the entry to be freed later.
644  //
645  // Also, convert any clones of devices not reported as present to
646  // removal modifications so that the original is still reported missing.
647  //
650  pCur = pNext) {
651 
652  pNext = pCur->Flink;
653 
655 
658  "entry %p modified in last scan, "
659  "mod state %!FxChildListModificationState!,"
660  "desc state %!FxChildListDescriptionState!",
661  pEntry, pEntry->m_ModificationState,
662  pEntry->m_DescriptionState);
663 
664  if (pEntry->m_FoundInLastScan == FALSE) {
665  switch (pEntry->m_ModificationState) {
666  case ModificationInsert:
667  //
668  // Insertion that never made through to the end of a scan.
669  //
671  break;
672 
673  case ModificationClone:
676  "clone of PDO WDFDEVICE %p, !devobj %p dropped because "
677  "it is missing", pEntry->m_Pdo->GetHandle(),
678  pEntry->m_Pdo->GetDeviceObject());
679 
680  //
681  // We were asked for a clone in the middle of a scan and the
682  // device was not reported, so it is now missing. Convert
683  // the clone modification to a remove modification.
684  //
685  pEntry->m_ModificationState = ModificationRemoveNotify;
686 
687  //
688  // Remove the modification from the current mod list. It
689  // will be re-added below when we iterate over the
690  // descriptions list.
691  //
692  RemoveEntryList(&pEntry->m_ModificationLink);
693  InitializeListHead(&pEntry->m_ModificationLink);
694 
695  //
696  // We can only have been cloning a device which is present
697  // and not yet reported missing to the OS.
698  //
699  ASSERT(pEntry->m_DescriptionState ==
701  break;
702  }
703  }
704  }
705 
706  //
707  // Walk over all desc entries and remove anything that wasn't found in the
708  // scan. Since MarkDescriptionNotPresentWorker doesn't drain the
709  // modifications, we don't have to worry about any entries disappearing.
710  //
713  pCur = pCur->Flink) {
714 
716 
717  if (pEntry->m_PendingDeleteOnScanEnd) {
718  //
719  // The entry was pnp removed but was not removed from list
720  // because scan count was > 0. It is safe to remove and delete
721  // it now.
722 
723  // Update the current pointer before the entry is removed.
724  pCur = pCur->Blink;
725 
726  RemoveEntryList(&pEntry->m_DescriptionLink);
727  InsertTailList(&freeHead, &pEntry->m_DescriptionLink);
728  pEntry = NULL;
729  continue;
730  }
731  else if (pEntry->IsPresent() && pEntry->m_FoundInLastScan == FALSE) {
732  if (pEntry->m_Pdo != NULL) {
735  "marking PDO WDFDEVICE %p, !devobj %p as not present",
736  pEntry->m_Pdo->GetHandle(),
737  pEntry->m_Pdo->GetDeviceObject());
738 
739  }
740  else {
743  "marking PDO (entry %p) which needs instantiation as "
744  "not present", pEntry);
745  }
746 
748  }
749  }
750 
751  //
752  // Attempt to drain any mods we made.
753  //
754  ProcessModificationsLocked(&freeHead);
755 
756  //
757  // We need to check m_KnownPdo here because if this
758  // object is attached to a PDO, the PDO's devobj could be in a state where
759  // PnP does not know it is a PDO yet. m_KnownPdo
760  // is set when the PDO receives a start device and by the time start
761  // device arrives, we definitely know the PDO is known the PnP.
762  //
763  // No need to hold a lock while checking m_KnownPdo
764  // because if miss the transition from FALSE to TRUE, relations will
765  // automaticaly be invalidated by the cause of that transition (start
766  // device arrival). PnP automatically sends a QDR after a successful
767  // start.
768  //
769 
770  if (m_InvalidationNeeded) {
771  PDEVICE_OBJECT pdo;
772 
773  //
774  // This does the m_KnownPdo check.
775  //
777 
778  if (pdo != NULL) {
781  }
782  }
783 
784  m_ScanEvent.Set();
785  }
786 
788 
789  //
790  // Free structures outside of any internal WDF lock
791  //
792  DrainFreeListHead(&freeHead);
793 }
794 
795 VOID
797  __in BOOLEAN EndTheScan,
798  __inout_opt PULONG ScanTag
799  )
800 {
801  *ScanTag = ScanTagCancelled;
802 
803  if (EndTheScan) {
804  EndScan(ScanTag);
805  }
806 }
807 
808 VOID
811  )
812 {
814 
815  if (Iterator->Flags & WdfRetrievePendingChildren) {
816  Iterator->Reserved[ModificationIndex] = ULongToPtr(1);
817  }
818 }
819 
820 VOID
823  )
824 {
825  KIRQL irql;
826 
827  //
828  // Almost the same semantic as BeginScan except we don't mark all of the
829  // children as missing when we start.
830  //
832 
834  //
835  // Set the scanevent to non-signaled state. Some code paths such as
836  // PDO eject will wait for the completion of child list iteration or scan
837  // so that a QDR that follows eject is guaranteed to pick up the change in
838  // PDO state that the code path made. Note that scan and iteration can be
839  // nested and in that case this event will be clear each time but it will be
840  // set (signalled) only after all the iteration and scan opeartions have
841  // completed.
842  //
843  m_ScanEvent.Clear();
844  m_ScanCount++;
845 
847  "Begin iteration on WDFCHILDLIST %p, scan count %d",
849 
851 }
852 
853 VOID
856  )
857 {
859  "end iteration on WDFCHILDLIST");
860 
861  //
862  // Semantic is exactly the same as EndScan. Basically, all changes are
863  // delayed until there are no more active scans, so the end of an interation
864  // is the same as the end of a scan.
865  //
866  EndScan();
867 
868  RtlZeroMemory(&Iterator->Reserved[0], sizeof(Iterator->Reserved));
869 }
870 
872 NTSTATUS
874  __out WDFDEVICE* Device,
877  )
878 {
883  ULONG cur, i;
884  KIRQL irql;
885  BOOLEAN found;
886 
887  pEntry = NULL;
889 
891 
892  ASSERT(m_ScanCount > 0);
893  if (m_ScanCount == 0) {
895 
898  "WDFCHILDLIST %p cannot retrieve next device if the list is not "
899  "locked for iteration, %!STATUS!", GetHandle(), status);
900 
901  goto Done;
902  }
903 
904  ple = (PLIST_ENTRY) Iterator->Reserved[DescriptionIndex];
905 
906  if (ple != NULL) {
909  if (!NT_SUCCESS(status)) {
910  goto Done;
911  }
912  }
913 
914  found = FALSE;
915 
916  //
917  // Try to find the next entry
918  //
919  for (ple = ple->Flink; ple != &m_DescriptionListHead; ple = ple->Flink) {
921 
922  if (pEntry->MatchStateToFlags(Iterator->Flags)) {
923  //
924  // An item was found
925  //
926  found = TRUE;
927 
928  //
929  // Call the caller's compare function to further refine the match
930  // if necessary.
931  //
932  if (Info != NULL &&
933  Info->EvtChildListIdentificationDescriptionCompare != NULL) {
934 
935  found = Info->EvtChildListIdentificationDescriptionCompare(
936  GetHandle(),
937  Info->IdentificationDescription,
938  pEntry->m_IdentificationDescription);
939  }
940 
941  if (found) {
942  break;
943  }
944  }
945  }
946 
947  if (found) {
948  //
949  // We can safely store the description entry because we are
950  // guaranteed it will stay in the description list until m_ScanCount
951  // reaches zero. In that case, the caller would need to call
952  // EndIteration
953  //
954  Iterator->Reserved[DescriptionIndex] = ple;
955 
956  if (pEntry->m_Pdo != NULL) {
957  *Device = pEntry->m_Pdo->GetHandle();
959  }
960  else {
962  }
963 
964  if (Info != NULL) {
965  if (Info->IdentificationDescription != NULL) {
966  CopyId(Info->IdentificationDescription,
967  pEntry->m_IdentificationDescription);
968  }
969  if (Info->AddressDescription != NULL) {
970  CopyAddress(Info->AddressDescription,
971  pEntry->m_AddressDescription);
972  }
973 
974  Info->Status = dstatus;
975  }
976 
978  }
979  else {
980  Iterator->Reserved[DescriptionIndex] = NULL;
981  ple = NULL;
983  }
984  }
985 
987 
988  if ((Iterator->Flags & WdfRetrievePendingChildren) == 0 ||
989  cur == 0) {
990  goto Done;
991  }
992 
993 
994  //
995  // Walk the modification list. Since this list can change from call to call
996  // to GetNextDevice we can't rely on the previous entry still being present
997  // so we must use an index into the list. This is not guaranteed to
998  // enumerate all pending additions, but it should be good enough.
999  //
1000  found = FALSE;
1001 
1002  for (i = 1, ple = m_ModificationListHead.Flink;
1004  ple = ple->Flink) {
1005 
1007 
1008  if (pEntry->m_ModificationState == ModificationInsert) {
1009  i++;
1010 
1011  if (i > cur) {
1012  found = TRUE;
1013 
1014  if (Info != NULL &&
1015  Info->EvtChildListIdentificationDescriptionCompare != NULL) {
1016 
1017  found = Info->EvtChildListIdentificationDescriptionCompare(
1018  GetHandle(),
1019  Info->IdentificationDescription,
1020  pEntry->m_IdentificationDescription);
1021  }
1022 
1023  if (found) {
1024  //
1025  // Store the next item number
1026  //
1027  Iterator->Reserved[ModificationIndex] = ULongToPtr(i);
1028 
1029  if (Info != NULL) {
1030  if (Info->IdentificationDescription != NULL) {
1031  CopyId(Info->IdentificationDescription,
1032  pEntry->m_IdentificationDescription);
1033  }
1034  if (Info->AddressDescription != NULL) {
1035  CopyAddress(Info->AddressDescription,
1036  pEntry->m_AddressDescription);
1037  }
1038 
1040  }
1041 
1043  break;
1044  }
1045  }
1046  }
1047  }
1048 
1049  if (found == FALSE) {
1050  Iterator->Reserved[ModificationIndex] = ULongToPtr(0);
1051  }
1052 
1053 Done:
1055 
1056  return status;
1057 }
1058 
1059 WDFDEVICE
1061  __in WDFDEVICE PreviousDevice,
1062  __in ULONG Flags
1063  )
1064 {
1065  FxStaticChildDescription *pStatic;
1067  WDFDEVICE result;
1068  PLIST_ENTRY ple;
1069  KIRQL irql;
1070  BOOLEAN isNext;
1071 
1073 
1074  result = NULL;
1075 
1076  if (PreviousDevice == NULL) {
1077  //
1078  // No previous handle, we want the first device we find
1079  //
1080  isNext = TRUE;
1081  }
1082  else {
1083  //
1084  // We have a previuos handle, find it in the list first before setting
1085  // isNext.
1086  //
1087  isNext = FALSE;
1088  }
1089 
1091 
1092  ASSERT(m_ScanCount > 0);
1093  if (m_ScanCount == 0) {
1094  goto Done;
1095  }
1096 
1097  //
1098  // Try to find the next entry
1099  //
1103  ple = ple->Flink) {
1105 
1106  //
1107  // If the entry is marked pending delete, skip it, because the
1108  // relationship between entry and its PDO has been removed and PDO
1109  // may have actually been deleted by this time. The only reason
1110  // this entry is here is because there is still a scan going on
1111  // and the entry can't be removed in the midst of a scan.
1112  //
1113  if (pEntry->m_PendingDeleteOnScanEnd) {
1114  continue;
1115  }
1116 
1117  pStatic = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
1119  Header);
1120 
1121  //
1122  // Only return a handle if it is in a state in which the caller is
1123  // interested in hearing about.
1124  //
1125  if (isNext && pEntry->MatchStateToFlags(Flags)) {
1126  result = pStatic->Pdo->GetHandle();
1127  break;
1128  }
1129  else if (pStatic->Pdo->GetHandle() == PreviousDevice) {
1130  isNext = TRUE;
1131  }
1132  }
1133  }
1134 
1135  //
1136  // We have taken care of all the other states (reported, pending removal,
1137  // removed) in the previuos loop.
1138  //
1139  if (result == NULL && (Flags & WdfRetrievePendingChildren)) {
1140  //
1141  // Walk the modification list. Since this list can change from call to
1142  // call, there is no way to definitively give the driver a snapshot of
1143  // this list of modifications.
1144  //
1147  ple = ple->Flink) {
1148 
1150 
1151  if (pEntry->m_PendingDeleteOnScanEnd) {
1152  continue;
1153  }
1154 
1155  pStatic = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
1157  Header);
1158 
1159  //
1160  // Only return a handle if it is in a state in which the caller is
1161  // interested in hearing about.
1162  //
1163  if (isNext && pEntry->m_ModificationState == ModificationInsert) {
1164  result = pStatic->Pdo->GetHandle();
1165  break;
1166  }
1167  else if (pStatic->Pdo->GetHandle() == PreviousDevice) {
1168  isNext = TRUE;
1169  }
1170  }
1171  }
1172 
1173 Done:
1175 
1176  return result;
1177 }
1178 
1180 NTSTATUS
1183  )
1184 {
1186  LIST_ENTRY freeHead;
1187  NTSTATUS status;
1188  KIRQL irql;
1189 
1190  //
1191  // Assume success
1192  //
1194  InitializeListHead(&freeHead);
1195 
1197 
1199 
1200  if (pEntry != NULL) {
1201 
1202 
1203 
1204 
1205 
1206 
1207 
1208 
1210  }
1211  else {
1213 
1214  if (pEntry != NULL) {
1215  if (pEntry->IsPresent()) {
1217  }
1218  }
1219  else {
1220  //
1221  // Couldn't find anything
1222  //
1224  }
1225  }
1226 
1227  ProcessModificationsLocked(&freeHead);
1228 
1230 
1231  DrainFreeListHead(&freeHead);
1232 
1233  return status;
1234 }
1235 
1237 NTSTATUS
1240  )
1241 /*++
1242 
1243 Routine Description:
1244  Same as UpdateAsMissing except instead of a device description, we have the
1245  device itself.
1246 
1247 Arguments:
1248  Device - the device to mark as missing
1249 
1250 Return Value:
1251  NTSTATUS
1252 
1253  --*/
1254 {
1256  LIST_ENTRY freeHead, *ple;
1257  KIRQL irql;
1258  BOOLEAN found;
1259  CfxDevice *pdo;
1260 
1261  found = FALSE;
1262  pdo = NULL;
1263  InitializeListHead(&freeHead);
1264 
1266 
1269  ple = ple->Blink) {
1270 
1272 
1273  //
1274  // Static PDO may not be populated in m_Pdo yet, so check the PDO
1275  // from id description.
1276  //
1277  if (m_StaticList) {
1278  pdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
1280  Header)->Pdo;
1281  }
1282  else {
1283  pdo = pEntry->m_Pdo;
1284  }
1285 
1286  if (pdo == Device) {
1287  found = TRUE;
1289  break;
1290  }
1291  }
1292 
1293  if (found == FALSE) {
1296  ple = ple->Blink) {
1297 
1299 
1300  //
1301  // Static PDO may not be populated in m_Pdo yet, so check the PDO
1302  // from id description.
1303  //
1304  if (m_StaticList) {
1305  pdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
1307  Header)->Pdo;
1308  }
1309  else {
1310  pdo = pEntry->m_Pdo;
1311  }
1312 
1313  if (pdo == Device) {
1314  found = TRUE;
1315 
1316  if (pEntry->IsPresent()) {
1318  }
1319 
1320  break;
1321  }
1322  }
1323  }
1324 
1325  ProcessModificationsLocked(&freeHead);
1326 
1328 
1329  DrainFreeListHead(&freeHead);
1330 
1331  if (found) {
1332  return STATUS_SUCCESS;
1333  }
1334  else {
1335  return STATUS_NO_SUCH_DEVICE;
1336  }
1337 }
1338 
1339 BOOLEAN
1342  __in BOOLEAN FromQDR
1343  )
1344 {
1345  BOOLEAN result;
1346 
1347  //
1348  // Check to see if there are modifications pending
1349  //
1350  if (IsListEmpty(&Entry->m_ModificationLink) && Entry->IsPresent()) {
1351  //
1352  // No mods pending...
1353  //
1354 
1355  //
1356  // We can only go down this path if the device was reported to the system
1357  // b/c the stack on our PDO is the one invoking this call.
1358  //
1359  ASSERT(Entry->m_DescriptionState == DescriptionInstantiatedHasObject);
1360 
1361  if (FromQDR == FALSE) {
1362  //
1363  // The entry has not been reported as missing by the driver, try to
1364  // clone it and insert a modification.
1365  //
1366  Entry->m_ModificationState = ModificationClone;
1367  InsertTailList(&m_ModificationListHead, &Entry->m_ModificationLink);
1368  }
1369 
1372  "Inserting clone modification for PDO WDFDEVICE %p, !devobj %p",
1373  Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject());
1374 
1375  result = TRUE;
1376  }
1377  else {
1378  //
1379  // If there is a pending modification, we don't do anything.
1380  // If the device is already not present, we don't do anything.
1381  //
1382  // ModficiationRemove or
1383  // ModficiationRemoveNotify: we would be reenumerating a device which
1384  // is being removed which is not what we want
1385  //
1386  // ModificationClone: we would be cloning a clone which is not what
1387  // we want either
1388  //
1391  "Requested reenumeration for PDO WDFDEVICE %p, !devobj %p"
1392  " no possible (pending mod %d, currently present %d)",
1393  Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject(),
1394  IsListEmpty(&Entry->m_ModificationLink), Entry->IsPresent());
1395 
1396  result = FALSE;
1397  }
1398 
1399  return result;
1400 }
1401 
1402 VOID
1405  )
1406 {
1407  LIST_ENTRY freeHead;
1408  KIRQL irql;
1409 
1410  InitializeListHead(&freeHead);
1411 
1414  ProcessModificationsLocked(&freeHead);
1416 
1417  DrainFreeListHead(&freeHead);
1418 }
1419 
1420 
1421 VOID
1423  __in_opt PULONG ScanTag
1424  )
1425 {
1426  PLIST_ENTRY pCur, pNext;
1427  LIST_ENTRY freeHead;
1429  KIRQL irql;
1430 
1432 
1433  if (ScanTag != NULL) {
1434  if (*ScanTag != ScanTagActive) {
1435  ASSERT(*ScanTag == ScanTagCancelled);
1437  return;
1438  }
1439  }
1440 
1441  //
1442  // Walk over all mod entries and ensure any inserts are still marked
1443  // present.
1444  //
1447  pCur = pNext) {
1448 
1449  pNext = pCur->Flink;
1450 
1452 
1453  if (pEntry->m_ModificationState == ModificationInsert) {
1454  pEntry->m_FoundInLastScan = TRUE;
1455  }
1456  }
1457 
1458  //
1459  // Walk over all desc entries and ensure they are marked present.
1460  //
1463  pCur = pCur->Flink) {
1464 
1466 
1467  if (pEntry->IsPresent()) {
1468  ASSERT(pEntry->m_ModificationState != ModificationRemoveNotify);
1469 
1470  if (pEntry->m_ModificationState != ModificationRemove) {
1471  pEntry->m_FoundInLastScan = TRUE;
1472  }
1473  }
1474  }
1475 
1476  //
1477  // Attempt to drain any mods we made.
1478  //
1479  InitializeListHead(&freeHead);
1480  ProcessModificationsLocked(&freeHead);
1481 
1483 
1484  DrainFreeListHead(&freeHead);
1485 }
1486 
1488 NTSTATUS
1492  __in_opt PULONG ScanTag
1493  )
1494 {
1495  LIST_ENTRY freeHead;
1496  KIRQL irql;
1497  NTSTATUS status;
1499  BOOLEAN allocNewEntry;
1500 
1501  if (ScanTag != NULL) {
1502  if (*ScanTag != ScanTagActive) {
1503  ASSERT(*ScanTag == ScanTagCancelled);
1504 
1505  //
1506  // The descriptions are duplicated if needed, so no need to clean
1507  // them up
1508  //
1509  // CleanupDescriptions(IdentificationDescription,
1510  // AddressDescription);
1511 
1512  return STATUS_CANCELLED;
1513  }
1514  }
1515 
1517  allocNewEntry = FALSE;
1518  InitializeListHead(&freeHead);
1519 
1521 
1524  );
1525 
1526  if (pEntry != NULL) {
1527  switch (pEntry->m_ModificationState) {
1528  case ModificationInsert:
1529  if (HasAddressDescriptions()) {
1530  CopyAddress(pEntry->m_AddressDescription,
1532  }
1533 
1534  //
1535  // There is already a pending insert operation. All we need do is
1536  // update the stored description.
1537  //
1538  pEntry->m_FoundInLastScan = TRUE;
1539 
1541  break;
1542 
1543  case ModificationRemove:
1545  //
1546  // We found a pending remove. Therefore we need to add an insert
1547  // operation to the end of the mod list.
1548  //
1549  allocNewEntry = TRUE;
1550  break;
1551 
1552  default:
1553  ASSERTMSG("Invalid description modification state\n", FALSE);
1554  break;
1555  }
1556  }
1557  else {
1558  //
1559  // There are no matching modifications queued in the list. Go examine
1560  // the main list. We can't modify any of the child links right now
1561  // because the list might be locked down, but it is scannable!
1562  //
1565  );
1566 
1567  if (pEntry != NULL && pEntry->IsPresent()) {
1568  //
1569  // This is an update. Enqueue it through this node.
1570  //
1571  ASSERT(pEntry->m_ModificationState == ModificationUnspecified);
1572 
1573  if (HasAddressDescriptions()) {
1574  CopyAddress(pEntry->m_AddressDescription,
1576  }
1577 
1578  pEntry->m_FoundInLastScan = TRUE;
1580  }
1581  else {
1582  //
1583  // Either no entry was found, or a "missing" entry was identified
1584  // instead. In both cases we need to add an insert operation to the
1585  // end of the modification list.
1586  //
1587  allocNewEntry = TRUE;
1588  }
1589  }
1590 
1591  if (allocNewEntry) {
1592 
1593  pEntry =
1598 
1599  if (pEntry != NULL) {
1600  status = DuplicateId(pEntry->m_IdentificationDescription,
1602 
1604  status = DuplicateAddress(pEntry->m_AddressDescription,
1606  }
1607 
1608  if (NT_SUCCESS(status)) {
1609  pEntry->m_FoundInLastScan = TRUE;
1611  &pEntry->m_ModificationLink);
1612 
1613  if (m_StaticList) {
1614  FxDevice* pPdo;
1615 
1616  pPdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
1618  Header)->Pdo;
1619 
1620  //
1621  // The device is no longer deletable by the driver writer
1622  //
1623  pPdo->MarkNoDeleteDDI();
1624 
1625  //
1626  // Plug in the description like we do for dynamic PDOs in
1627  // FxPkgPdo::Initialize.
1628  //
1630 
1631  //
1632  // Let the device know it was inserted into the list. This
1633  // used to know in pPdo::DeleteObject how to proceed.
1634  //
1636  }
1637  }
1638  else {
1639  InsertTailList(&freeHead, &pEntry->m_DescriptionLink);
1640  }
1641  }
1642  else {
1644  }
1645  }
1646 
1647  ProcessModificationsLocked(&freeHead);
1648 
1650 
1651  DrainFreeListHead(&freeHead);
1652 
1653  return status;
1654 }
1655 
1656 VOID
1660  )
1661 {
1662  KIRQL irql;
1663 
1665  CopyAddress(Entry->m_AddressDescription, AddressDescription);
1667 
1668 
1669 
1670 
1671 
1672 
1673 }
1674 
1675 BOOLEAN
1677  __inout PLIST_ENTRY FreeListHead,
1679  __in BOOLEAN FromQDR
1680  )
1681 {
1682  FxDeviceDescriptionEntry* pClone;
1683  BOOLEAN invalidateRelations;
1684 
1687  "attempting to clone PDO WDFDEVICE %p, !devobj %p, From QDR %d",
1688  Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject(), FromQDR);
1689 
1690  invalidateRelations = FALSE;
1691 
1692  pClone = Entry->Clone(FreeListHead);
1693 
1694  if (pClone != NULL) {
1695  //
1696  // Check to see if the driver writer OKs the cloning, aka
1697  // reenumeration.
1698  //
1701  GetHandle(),
1702  Entry->m_Pdo->GetHandle(),
1703  Entry->m_AddressDescription,
1704  pClone->m_AddressDescription) == FALSE){
1705  //
1706  // The clone will be freed later by the caller by placing
1707  // it on the free list.
1708  //
1709  InsertTailList(FreeListHead, &pClone->m_DescriptionLink);
1710  }
1711  else {
1714  "clone successful (new entry is %p), marking PDO "
1715  "WDFDEVICE %p, !devobj %p as missing", pClone,
1716  Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject());
1717 
1718  //
1719  // Setup the state of the clone
1720  //
1723 
1724  //
1725  // This is important that this is last. If a subsequent
1726  // modification arrives for this device, we want to find the
1727  // clone before the old device. Since all changes search the
1728  // list backwards, inserting at the tail accomplishes this.
1729  //
1731  &pClone->m_DescriptionLink);
1732 
1733  if (FromQDR == FALSE) {
1734  Entry->m_DescriptionState = DescriptionNotPresent;
1735  invalidateRelations = TRUE;
1736  }
1737  }
1738  }
1739  else {
1740  //
1741  // Could not allocate a clone, do not anything.
1742  //
1743  DO_NOTHING();
1744  }
1745 
1746  //
1747  // Convert the original device's modification state back to a
1748  // unspecified in all cases.
1749  //
1750  Entry->m_ModificationState = ModificationUnspecified;
1751 
1752  return invalidateRelations;
1753 }
1754 
1755 VOID
1757  __inout PLIST_ENTRY FreeListHead
1758  )
1759 {
1761  PLIST_ENTRY pCur, pNext;
1762  BOOLEAN invalidateRelations;
1763 
1764  //
1765  // If the list is locked or there are still active scans, we must not process
1766  // any modifications.
1767  //
1768  if (m_State != ListUnlocked || m_ScanCount > 0) {
1771  "Not processing modifications on WDFCHILDLIST %p (list state %d, "
1772  "scan count %d)", GetObjectHandle(), m_State, m_ScanCount);
1773  return;
1774  }
1775 
1778  "Begin processing modifications on WDFCHILDLIST %p", GetObjectHandle());
1779 
1780  //
1781  // First do the mod updates. As quick as possible. Note that we need to
1782  // update
1783  //
1786  pCur = pNext) {
1787 
1788  pNext = pCur->Flink;
1789 
1791 
1792  switch (pEntry->m_ModificationState) {
1794 
1795 
1796 
1797 
1798 
1799 
1800 
1801 
1802 
1803 
1804 
1805 
1806 
1807 
1808 
1809  pEntry->m_ModificationState = ModificationRemove;
1810  break;
1811 
1812  default:
1813  break;
1814  }
1815  }
1816 
1817  invalidateRelations = FALSE;
1820 
1823 
1824  ASSERT(pEntry->m_ModificationState == ModificationInsert ||
1825  pEntry->m_ModificationState == ModificationClone ||
1826  pEntry->m_ModificationState == ModificationRemove);
1827 
1830  "entry %p, mod state is %!FxChildListModificationState!",
1831  pEntry, pEntry->m_ModificationState);
1832 
1833  switch (pEntry->m_ModificationState) {
1834  case ModificationRemove:
1835  //
1836  // Remove's are stacked on top of the entry they need to take out.
1837  //
1838  ASSERT(pEntry->IsPresent());
1839 
1840  pEntry->m_ModificationState = ModificationUnspecified;
1841 
1844  "processing remove on entry %p, description state is "
1845  "%!FxChildListDescriptionState!",
1846  pEntry, pEntry->m_DescriptionState);
1847 
1848  switch (pEntry->m_DescriptionState) {
1850  //
1851  // We got to the entry before a DO could be created for it or
1852  // an instantiation failed. If deleeted before creation, the
1853  // list entry points to itself. If the instantiation failed,
1854  // the list entry is in the description list and must be
1855  // removed from it.
1856  //
1857  // Mark it for deletion now (outside of the lock being held).
1858  //
1861  "entry %p never reported to pnp, mark for deletion", pEntry);
1862 
1863  RemoveEntryList(&pEntry->m_DescriptionLink);
1864  InsertTailList(FreeListHead, &pEntry->m_DescriptionLink);
1865  break;
1866 
1870  "committing PDO WDFDEVICE %p, !devobj %p as not present",
1871  pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject());
1872 
1873  pEntry->m_DescriptionState = DescriptionNotPresent;
1874  invalidateRelations = TRUE;
1875  break;
1876 
1877  default:
1878  ASSERTMSG("Invalid description state\n", FALSE);
1879  break;
1880  }
1881 
1882  break;
1883 
1884  case ModificationInsert:
1885  //
1886  // CurEntry is our entry to insert into the list. We simply "move"
1887  // the mod entries to desc entries.
1888  //
1889  ASSERT(pEntry->m_DescriptionState == DescriptionUnspecified);
1890  pEntry->m_DescriptionState = DescriptionPresentNeedsInstantiation;
1891 
1894  "marking entry %p as needing instantiation", pEntry);
1895 
1896  InsertTailList(&m_DescriptionListHead, &pEntry->m_DescriptionLink);
1897  pEntry->m_ModificationState = ModificationUnspecified;
1898  invalidateRelations = TRUE;
1899  break;
1900 
1901  case ModificationClone:
1902  invalidateRelations = CloneEntryLocked(FreeListHead, pEntry, FALSE);
1903  break;
1904 
1905  default:
1906  ASSERTMSG("Invalid description modification state\n", FALSE);
1907  break;
1908  }
1909  }
1910 
1911  if (invalidateRelations) {
1912  PDEVICE_OBJECT pdo;
1913 
1914  if (m_ScanCount) {
1916  }
1917  else if ((pdo = m_Device->GetSafePhysicalDevice()) != NULL) {
1918  //
1919  // See previous usage of m_Device->m_KnownPdo for
1920  // comments on why a lock is not necessary when reading its value.
1921  //
1924  }
1925  else {
1927  }
1928  }
1929 
1932  "end processing modifications on WDFCHILDLIST %p", GetObjectHandle());
1933 }
1934 
1935 VOID
1937  __inout FxDeviceDescriptionEntry* DescriptionEntry,
1938  __in BOOLEAN ModificationCanBeQueued
1939  )
1940 /*++
1941 
1942 Routine Description:
1943 
1944  This worker function marks the passed in mod or desc entry in the device
1945  list "not present". The change is enqueued in the mod list but the mod
1946  list is not drained.
1947 
1948 Arguments:
1949 
1950  DescriptionEntry - Entry to be marked as "not present".
1951 
1952  ModificationCanBeQueued - whether the caller allows for this description
1953  to be a modification already queued on the modification list
1954 
1955 Assumes:
1956  DescriptionEntry->IsPresent() == TRUE
1957 
1958 Return Value:
1959  None
1960 
1961 --*/
1962 {
1963  BOOLEAN queueMod;
1964 
1965  ASSERT(DescriptionEntry->IsPresent());
1966 
1967  queueMod = FALSE;
1968 
1969  if (ModificationCanBeQueued) {
1970  if (IsListEmpty(&DescriptionEntry->m_ModificationLink)) {
1971  queueMod = TRUE;
1972  }
1973  else {
1974  //
1975  // If the modification is queued, it must be removal
1976  //
1977  ASSERT(DescriptionEntry->m_ModificationState ==
1979  ASSERT(DescriptionEntry->m_FoundInLastScan == FALSE);
1980  }
1981  }
1982  else {
1983  queueMod = TRUE;
1984  }
1985 
1986  if (queueMod) {
1987  ASSERT(IsListEmpty(&DescriptionEntry->m_ModificationLink));
1988  ASSERT(DescriptionEntry->m_ModificationState == ModificationUnspecified);
1989 
1990  //
1991  // Add a removal modification entry into the modification list.
1992  // The ModificationRemoveNotify state will be converted into
1993  // ModificationRemove later while the list lock is still being held.
1994  //
1995  DescriptionEntry->m_ModificationState = ModificationRemoveNotify;
1996  DescriptionEntry->m_FoundInLastScan = FALSE;
1997 
1999  &DescriptionEntry->m_ModificationLink);
2000  }
2001 }
2002 
2003 VOID
2005  __inout PLIST_ENTRY FreeListHead,
2006  __inout FxDeviceDescriptionEntry* ModificationEntry
2007  )
2008 /*++
2009 
2010 Routine Description:
2011 
2012  This worker function marks the passed in mod or desc entry in the device
2013  list "not present". The change is enqueued in the mod list but the mod
2014  list is not drained.
2015 
2016 Arguments:
2017 
2018  FreeListHead - Free list of entries.
2019 
2020  ModificationEntry - Entry to be marked as "not present".
2021 
2022 Return Value:
2023  None
2024 
2025 --*/
2026 {
2027  switch (ModificationEntry->m_ModificationState) {
2028  case ModificationInsert:
2029  //
2030  // This one was never reported to the OS. Remove it now.
2031  //
2032  RemoveEntryList(&ModificationEntry->m_ModificationLink);
2033  InitializeListHead(&ModificationEntry->m_ModificationLink);
2034 
2035  if (IsStaticList()) {
2036  //
2037  // There is a corner case of a static PDO being added and
2038  // immediately marked as missing before it has a chance to move to
2039  // description list. This case is handled here by marking the
2040  // modification state to ModificationNeedsPnpRemoval. Fx cannot just
2041  // delete the description because there is a driver-created PDO
2042  // associated with the description and it needs to be cleaned up.
2043  //
2044  ModificationEntry->m_ModificationState = ModificationNeedsPnpRemoval;
2045  ASSERT(ModificationEntry->m_DescriptionState == DescriptionUnspecified);
2046  }
2047 
2048  ASSERT(IsListEmpty(&ModificationEntry->m_DescriptionLink));
2049  InsertTailList(FreeListHead, &ModificationEntry->m_DescriptionLink);
2050  break;
2051 
2052  case ModificationClone:
2053  //
2054  // In between the PDOs stack asking for a reenumeration and applying
2055  // this change, the bus driver has reported the child as missing.
2056  // Convert the clone modification to a removal modification.
2057  //
2058 
2059  //
2060  // MarkDescriptionNotPresentWorker expects that m_ModificationEntry is
2061  // not in any list and points to itself.
2062  //
2063  RemoveEntryList(&ModificationEntry->m_ModificationLink);
2064  InitializeListHead(&ModificationEntry->m_ModificationLink);
2065 
2066  MarkDescriptionNotPresentWorker(ModificationEntry, FALSE);
2067  break;
2068 
2069  default:
2070  DO_NOTHING();
2071  break;
2072  }
2073 }
2074 
2075 VOID
2077  __inout PLIST_ENTRY FreeListHead
2078  )
2079 {
2081  FxDevice* pPdo;
2082  PLIST_ENTRY pCur;
2083 
2084  while (!IsListEmpty(FreeListHead)) {
2085  pCur = RemoveHeadList(FreeListHead);
2087 
2089 
2090  //
2091  // If this is a static list and the entry has not yet been instantiated,
2092  // tell PnP to remove the device.
2093  //
2094  // There is a corner case of a static PDO being added and
2095  // immediately marked as missing before it has a chance to move to
2096  // description list. This case is handled here by checking the
2097  // modification state of ModificationNeedsPnpRemoval. Fx cannot just
2098  // delete the description because there is a driver-created PDO
2099  // associated with the description and it needs to be cleaned up.
2100  //
2101  if (m_StaticList &&
2102  (pEntry->m_DescriptionState == DescriptionPresentNeedsInstantiation ||
2103  pEntry->m_ModificationState == ModificationNeedsPnpRemoval )) {
2104 
2105  pPdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
2107  Header)->Pdo;
2108 
2109  //
2110  // The pnp removal path expects that there is no modifcation pending
2111  // when removing the description.
2112  //
2113  if (pEntry->m_ModificationState == ModificationNeedsPnpRemoval) {
2114  ASSERT(pEntry->m_DescriptionState == DescriptionUnspecified);
2115  ASSERT(IsListEmpty(&pEntry->m_ModificationLink));
2116 
2117  pEntry->m_ModificationState = ModificationUnspecified;
2118  }
2119 
2120  //
2121  // Change the state to reported missing (which is what we are basically
2122  // simulating here anyways) so that when we process the entry again
2123  // when the PDO really goes away we cleanup the entry.
2124  //
2125  // Also, when posting PnpEventRemove to the child, child will
2126  // call FxDeviceDescriptionEntry::IsDeviceRemoved which checks for
2127  // reported missing before reporting if the device has been removed
2128  // (and we want the device to be reported as removed).
2129  //
2130  pEntry->m_DescriptionState = DescriptionReportedMissing;
2131 
2132  //
2133  // Not yet reported to PnP, so it should be in the initial state
2134  //
2136 
2137  //
2138  // m_Description should be set when the FxPkgPdo was created
2139  //
2141 
2142  //
2143  // Since the pPdo->m_PkgPnp->m_DeviceRemoveProcessed == NULL, the
2144  // pnp state machine will delete the PDO. We are simulating the same
2145  // situation where an FDO is in the remove path and is telling each
2146  // of its removed PDOs to delete themselves.
2147  //
2149  }
2150  else {
2151  CleanupDescriptions(pEntry->m_IdentificationDescription,
2152  pEntry->m_AddressDescription);
2153 
2154  delete pEntry;
2155  }
2156  }
2157 }
2158 
2162  )
2163 {
2164  PLIST_ENTRY ple;
2166 
2169  ple = ple->Blink) {
2170 
2172 
2173  if (CompareId(pEntry->m_IdentificationDescription, Id)) {
2174  return pEntry;
2175  }
2176  }
2177 
2178  return NULL;
2179 }
2180 
2184  )
2185 {
2186  PLIST_ENTRY ple;
2188 
2191  ple = ple->Blink) {
2192 
2194 
2195  if (CompareId(pEntry->m_IdentificationDescription, Id)) {
2196  return pEntry;
2197  }
2198  }
2199 
2200  return NULL;
2201 }
2202 
2204 NTSTATUS
2207  )
2208 {
2209  if (Entry == &m_DescriptionListHead) {
2210  return STATUS_SUCCESS;
2211  }
2212  else {
2213  PLIST_ENTRY ple;
2214 
2217  ple = ple->Flink) {
2218  if (Entry == ple) {
2219  return STATUS_SUCCESS;
2220  }
2221  }
2222 
2223  return STATUS_INVALID_PARAMETER;
2224  }
2225 }
2226 
2228 NTSTATUS
2231  )
2232 {
2233  if (Entry == &m_ModificationListHead) {
2234  return STATUS_SUCCESS;
2235  }
2236  else {
2237  PLIST_ENTRY ple;
2238 
2241  ple = ple->Flink) {
2242  if (Entry == ple) {
2243  return STATUS_SUCCESS;
2244  }
2245  }
2246 
2247  return STATUS_INVALID_PARAMETER;
2248  }
2249 }
2250 
2251 BOOLEAN
2254  __inout PBOOLEAN InvalidateRelations
2255  )
2256 {
2258  NTSTATUS status;
2259  KIRQL irql;
2260 
2261  init.CreatedOnStack = TRUE;
2262  init.SetPdo(m_Device);
2263  init.Pdo.DescriptionEntry = Entry;
2264 
2265  if (m_StaticList) {
2266  init.CreatedDevice =
2267  CONTAINING_RECORD(Entry->m_IdentificationDescription,
2269  Header)->Pdo;
2270  }
2271  else {
2272  //
2273  // This description needs a device, create it now.
2274  //
2276  GetHandle(), Entry->m_IdentificationDescription, &init);
2277 
2278  if (status == STATUS_RETRY) {
2279  if (init.CreatedDevice != NULL) {
2280  //
2281  // Destroy any allocations assocated with the device.
2282  //
2283  init.CreatedDevice->Destroy();
2284  }
2285 
2286  *InvalidateRelations = TRUE;
2287 
2288  return FALSE;
2289  }
2290 
2291  if (NT_SUCCESS(status)) {
2292  //
2293  // Make sure that a framework device was actually created
2294  //
2295  if (init.CreatedDevice == NULL) {
2296  //
2297  // Driver didn't actually create the device, even though its
2298  // EvtChildListCreateDevice returned a successful return code.
2299  // Change the status to indicate an error, so that we enter the
2300  // error handling code below.
2301  //
2304  "EvtChildListCreateDevice returned a successful status "
2305  "%!STATUS! but did not create a device object", status);
2306 
2308 
2310  }
2311  }
2312 
2313  if (!NT_SUCCESS(status)) {
2314  if (init.CreatedDevice != NULL) {
2316  //
2317  // Set to missing so that when the pnp machine evaluates whether the
2318  // PDO has been reported missing or not, it chooses missing and
2319  // deletes the PDO immediately.
2320  //
2321  Entry->m_DescriptionState = DescriptionReportedMissing;
2322 
2323  if (Entry->m_ModificationState != ModificationUnspecified) {
2324  //
2325  // Cannot be ModificationInsert since this device ID is already
2326  // in the list.
2327  //
2328  // Cannot be ModificationClone since the FDO for this device
2329  // is the only one who can ask for that and since PDO creation
2330  // failed, there is no FDO.
2331  //
2332  // Cannot be ModificationRemove because the list is locked
2333  // against changes and ModificationRemoveNotify becomes
2334  // ModificationRemove only after the list has been unlocked.
2335  //
2336  ASSERT(Entry->m_ModificationState == ModificationRemoveNotify);
2337 
2338  //
2339  // Remove the modification from the list. The call to
2340  // DeleteDeviceFromFailedCreate below will destroy this
2341  // Entry due to the pnp state machine deleting the PDO.
2342  //
2343  RemoveEntryList(&Entry->m_ModificationLink);
2344  }
2346 
2347  ASSERT(init.CreatedDevice->IsPnp());
2348  ASSERT(init.CreatedDevice->GetDevicePnpState() == WdfDevStatePnpInit);
2349  ASSERT(init.CreatedDevice->GetPdoPkg()->m_Description != NULL);
2350 
2351  ASSERT(Entry->m_Pdo == NULL);
2352 
2355  "WDFDEVICE %p !devobj %p created, but EvtChildListCreateDevice "
2356  "returned status %!STATUS!", init.CreatedDevice->GetHandle(),
2357  init.CreatedDevice->GetDeviceObject(), status);
2358 
2359  //
2360  // Simulate a remove event coming to the device. After this call
2361  // returns, init.CreatedDevice is no longer a valid pointer!
2362  //
2363  // Please note that DeleteDeviceFromFailedCreate just returns
2364  // the passed status back unless device is a filter, in which
2365  // case it changes it to success.
2366  //
2367  // It is not really the status of DeleteDeviceFromFailedCreate
2368  // operation, which is why we don't check it.
2369  //
2370  (void) init.CreatedDevice->DeleteDeviceFromFailedCreate(
2371  status,
2372  TRUE);
2373 
2374  init.CreatedDevice = NULL;
2375  }
2376  else {
2377  LIST_ENTRY freeHead;
2378 
2379  InitializeListHead(&freeHead);
2380 
2381  //
2382  // Add a modification that this entry is now gone. If there is
2383  // an active scan and it has added this device, there would
2384  // be no entry in the modification case list because the add
2385  // would have updated the description entry.
2386  //
2389  ProcessModificationsLocked(&freeHead);
2391 
2392  //
2393  // Free structures outside of any internal WDF lock
2394  //
2395  DrainFreeListHead(&freeHead);
2396  }
2397 
2398  return FALSE;
2399  }
2400  }
2401 
2402  //
2403  // Assign m_Pdo here once we have a fully baked and created device. We only
2404  // assign m_Pdo after we have completely initalized device because we check
2405  // for m_Pdo in PostParentToD0.
2406  //
2407  Entry->m_Pdo = init.CreatedDevice;
2408  Entry->m_DescriptionState = DescriptionInstantiatedHasObject;
2409 
2410  return TRUE;
2411 }
2412 
2414 NTSTATUS
2416  __inout PDEVICE_RELATIONS *DeviceRelations
2417  )
2418 {
2419  LIST_ENTRY freeHead;
2420  PLIST_ENTRY ple, pNext;
2422  PDEVICE_RELATIONS pPriorRelations, pNewRelations;
2424  BOOLEAN needToReportMissingChildren, invalidateRelations, cleanupRelations;
2425  ULONG additionalCount, totalCount, i;
2426  size_t size;
2427  NTSTATUS status;
2428  KIRQL irql;
2430 
2432 
2433  pNewRelations = NULL;
2434  invalidateRelations = FALSE;
2435  cleanupRelations = TRUE;
2436  InitializeListHead(&freeHead);
2438 
2439  //
2440  // Get the count of DO's we will need to add. While we're at it, free any
2441  // extensions that never got a chance for a DO, and note extensions that
2442  // will need to wait for a remove IRP.
2443  //
2445 
2447 
2448  additionalCount = 0;
2449  needToReportMissingChildren = FALSE;
2450 
2453  ple = ple->Flink) {
2454 
2456 
2457  switch (pEntry->m_DescriptionState) {
2458 
2461  //
2462  // We'll be needing a DO here.
2463  //
2464  additionalCount++;
2465  break;
2466 
2467  case DescriptionNotPresent:
2468  //
2469  // We will now report the description as missing
2470  //
2473  "PDO WDFDEVICE %p !devobj %p in a not present state, need to "
2474  "report as missing",
2475  pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject());
2476 
2477  needToReportMissingChildren = TRUE;
2478  break;
2479 
2481  //
2482  // Already reported missing in a previous handling of QDR
2483  //
2484  break;
2485 
2486  default:
2487  ASSERTMSG("Invalid description state\n", FALSE);
2488  break;
2489  }
2490  }
2491 
2493 
2494  pPriorRelations = *DeviceRelations;
2495 
2496  //
2497  // If we have
2498  // 1) no devices in the list AND
2499  // a) we have nothing to report OR
2500  // b) we have something to report and there are previous relations (which
2501  // if left unchanged will be used to report our missing devices)
2502  //
2503  // THEN nothing else to do except marking the NotPresent children as
2504  // missing, unlock the list and return the special return
2505  // code STATUS_NOT_SUPPORTED indicating this condition.
2506  //
2507  if (additionalCount == 0 &&
2508  (needToReportMissingChildren == FALSE || pPriorRelations != NULL)) {
2509  //
2510  // We have nothing to add, nor subtract from prior allocations. Note
2511  // the careful logic with counting missing children - the OS does not
2512  // treat no list and an empty list identically. As such we must be
2513  // sure to return some kind of list in the case where we reported
2514  // something previously.
2515  //
2516  // Mark the NotPresent children as Missing
2517  // We can walk the ChildList without holding the spinlock because we set
2518  // m_State to ListLockedForEnum.
2519  //
2520  if (needToReportMissingChildren) {
2523  ple = pNext) {
2524  pNext = ple->Flink;
2525 
2527 
2528  if (pEntry->m_DescriptionState == DescriptionNotPresent) {
2529  //
2530  // We will now report the description as missing
2531  //
2534  "PDO WDFDEVICE %p !devobj %p reported as missing to pnp",
2535  pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject());
2536 
2537  pEntry->m_DescriptionState = DescriptionReportedMissing;
2538  pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked;
2539  }
2540  }
2541  }
2542  else {
2545  "Nothing to report on WDFCHILDLIST %p, returning early", GetHandle());
2546  }
2547 
2548  cleanupRelations = FALSE;
2550  goto Done;
2551  }
2552 
2553  //
2554  // Adjust the count for any existing relations.
2555  //
2556  totalCount = additionalCount;
2557  if (pPriorRelations != NULL) {
2558  totalCount += pPriorRelations->Count;
2559  }
2560 
2561  size = _ComputeRelationsSize(totalCount);
2562 
2563  pNewRelations = (PDEVICE_RELATIONS)
2565 
2566  if (pNewRelations == NULL) {
2567  //
2568  // We can't add our information.
2569  //
2571  "Could not allocate relations for %d devices",
2572  totalCount);
2573 
2574  //
2575  // Just like above, STATUS_NOT_SUPPORTED is a special value indicating
2576  // to the caller that the QDR has not been handled and that the caller
2577  // should not change the status or the existing relations in the irp.
2578  //
2579  cleanupRelations = FALSE;
2581 
2582  m_EnumRetries++;
2584  invalidateRelations = TRUE;
2585  }
2586  else {
2587  if (needToReportMissingChildren) {
2590  "WDFCHILDLIST %p could not allocate relations required for "
2591  "reporting children as missing after max retries",
2592  GetHandle());
2593  }
2594 
2597  "WDFCHILDLIST %p retried %d times to report relations, but "
2598  "failed each time", GetHandle(), FX_CHILD_LIST_MAX_RETRIES);
2599  }
2600 
2601  if (pPriorRelations == NULL) {
2602  //
2603  // If the prior relations are NULL we can just return failure and
2604  // not affect anyone else's state that had previous thought they
2605  // committed a relations structure back to pnp (which we tried to
2606  // update but could not b/c of no memory).
2607  //
2608  // By returning failure that is != STATUS_NOT_SUPPORTED, the pnp
2609  // manager will not process a change in the relations.
2610  //
2612  }
2613  else {
2614  //
2615  // Do *not* throw away the old list and return error because that
2616  // will put the driver which created the existing relations into an
2617  // inconsistent state with respect to the pnp manager state if we
2618  // fail it here and the pnp manager never seeds the changes.
2619  //
2620  // Instead, we must process the failure locally and mark each object
2621  // which is already reported as present as missing.
2622  //
2625  ple = pNext) {
2626 
2627  pNext = ple->Flink;
2629 
2630  switch (pEntry->m_DescriptionState) {
2632  //
2633  // This description can stay in this state b/c we will just
2634  // ask for another QDR.
2635  //
2636  break;
2637 
2641  "PDO WDFDEVICE %p !devobj %p being marked as missing "
2642  "because of failure to allocate device relations and "
2643  "an already existing relations %p",
2644  pEntry->m_Pdo->GetHandle(),
2645  pEntry->m_Pdo->GetDeviceObject(), pPriorRelations);
2646 
2648  if (m_StaticList == FALSE) {
2653  "PDO WDFDEVICE %p !devobj %p being cloned "
2654  "because of the failure to allocate device "
2655  "relations",
2656  pEntry->m_Pdo->GetHandle(),
2657  pEntry->m_Pdo->GetDeviceObject());
2658 
2659  (void) CloneEntryLocked(&freeHead, pEntry, TRUE);
2660  }
2661  }
2662  else {
2666  "PDO WDFDEVICE %p !devobj %p is a statically "
2667  "enumerated PDO therefore can not be cloned and is "
2668  "being marked missing because of failure to "
2669  "allocate device relations. It will be surprise "
2670  "removed by pnp manager. Bus driver may continue "
2671  "to function normally but will lose this child PDO",
2672  pEntry->m_Pdo->GetHandle(),
2673  pEntry->m_Pdo->GetDeviceObject());
2674  }
2675  pEntry->m_DescriptionState = DescriptionReportedMissing;
2676  pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked;
2678  break;
2679 
2680  case DescriptionNotPresent:
2681  //
2682  // We will now report the description as missing
2683  //
2686  "PDO WDFDEVICE %p !devobj %p reported as missing to pnp "
2687  "(by using existing relations)",
2688  pEntry->m_Pdo->GetHandle(),
2689  pEntry->m_Pdo->GetDeviceObject());
2690 
2691  pEntry->m_DescriptionState = DescriptionReportedMissing;
2692  pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked;
2693  break;
2694  }
2695  }
2696  }
2697 
2698  goto Done;
2699  }
2700 
2701  RtlZeroMemory(pNewRelations, size);
2702 
2703  if (pPriorRelations != NULL && pPriorRelations->Count > 0) {
2706  "WDFCHILDLIST %p prior relations %p contained %d objects",
2707  GetHandle(), pPriorRelations, pPriorRelations->Count
2708  );
2709 
2710  RtlCopyMemory(pNewRelations,
2711  pPriorRelations,
2712  _ComputeRelationsSize(pPriorRelations->Count));
2713  }
2714 
2715  //
2716  // We can walk the ChildList without holding the spinlock because we set
2717  // m_State to ListLockedForEnum.
2718  //
2720 
2723  ple = pNext) {
2724  pNext = ple->Flink;
2725 
2727 
2728  switch (pEntry->m_DescriptionState) {
2730  //
2731  // This extension needs a device handle. Create one now.
2732  //
2734  "Creating PDO device object from reported device");
2735  if (CreateDevice(pEntry, &invalidateRelations) == FALSE) {
2736  break;
2737  }
2738 
2741  "PDO created successfully, WDFDEVICE %p !devobj %p",
2742  pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject());
2743 
2744  // || || Fall through || ||
2745  // \/ \/ \/ \/
2747 
2749  "Reporting PDO WDFDEVICE %p !devobj %p",
2750  pEntry->m_Pdo->GetHandle(),
2751  pEntry->m_Pdo->GetDeviceObject());
2752 
2753  pDevice = pEntry->m_Pdo->GetDeviceObject();
2755  pNewRelations->Objects[pNewRelations->Count] = pDevice;
2756  pNewRelations->Count++;
2757  break;
2758 
2759  case DescriptionNotPresent:
2760  //
2761  // We will now report the description as missing
2762  //
2765  "PDO WDFDEVICE %p !devobj %p reported as missing to pnp",
2766  pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject());
2767 
2768  pEntry->m_DescriptionState = DescriptionReportedMissing;
2769  pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked;
2770 
2771  break;
2772 
2774  break;
2775 
2776  default:
2777  ASSERTMSG("Invalid description state\n", FALSE);
2778  break;
2779  }
2780  }
2781 
2782 Done:
2784 
2785  //
2786  // Make sure that the description we just dequeued is not on the modification
2787  // list.
2788  //
2790  ProcessModificationsLocked(&freeHead);
2791 
2792  if (NT_SUCCESS(status)) {
2793  m_EnumRetries = 0;
2794  }
2795 
2797 
2798  if (invalidateRelations) {
2799  //
2800  // We failed for some reason or other. Queue up a new attempt.
2801  //
2802  // NOTE: no need to check m_Device->m_KnownPdo here
2803  // because we are in the middle of a QDR for m_Device which means
2804  // that it, or its stack, is already known to PnP.
2805  //
2807  }
2808 
2809  DrainFreeListHead(&freeHead);
2810 
2811  if (cleanupRelations) {
2812  if (pPriorRelations != NULL) {
2815  "Freeing prior relations %p", pPriorRelations);
2816 
2817  ExFreePool(pPriorRelations);
2818  pPriorRelations = NULL;
2819  }
2820 
2821  if (!NT_SUCCESS(status) && pNewRelations != NULL) {
2822  for(i = 0; i < pNewRelations->Count; i++) {
2823  ObDereferenceObject(pNewRelations->Objects[i]);
2824  }
2825 
2826  ExFreePool(pNewRelations);
2827  pNewRelations = NULL;
2828  }
2829 
2830  *DeviceRelations = pNewRelations;
2831  }
2832 
2833  return status;
2834 }
2835 
2836 VOID
2838  VOID
2839  )
2840 {
2841  PLIST_ENTRY ple, pNext;
2842  KIRQL irql;
2844  LIST_ENTRY freeHead;
2845 
2846  InitializeListHead(&freeHead);
2847 
2848  //
2849  // Prevent modification list processing so that we can walk the
2850  // description list safely.
2851  //
2855 
2856  //
2857  // Invoke the ReportedMissing callback if present for children reported
2858  // missing.
2859  //
2862  ple = pNext) {
2863  pNext = ple->Flink;
2864 
2866 
2867  if (pEntry->m_ReportedMissingCallbackState == CallbackNeedsToBeInvoked) {
2868  (pEntry->m_Pdo->GetPdoPkg())->m_DeviceReportedMissing.Invoke(
2869  pEntry->m_Pdo->GetHandle());
2870 
2871  pEntry->m_ReportedMissingCallbackState = CallbackInvoked;
2872  }
2873  }
2874 
2877  ProcessModificationsLocked(&freeHead);
2879 
2880  DrainFreeListHead(&freeHead);
2881 }
2882 
2883 VOID
2885  VOID
2886  )
2887 {
2889  PLIST_ENTRY ple;
2890  KIRQL irql;
2891 
2895  ple = ple->Flink) {
2896 
2898 
2899  if (pEntry->m_PendingDeleteOnScanEnd) {
2900  COVERAGE_TRAP();
2901  continue;
2902  }
2903 
2904  if (pEntry->m_Pdo != NULL) {
2905  pEntry->m_Pdo->m_PkgPnp->PowerProcessEvent(PowerParentToD0);
2906  }
2907  }
2909 }
2910 
2911 VOID
2914  )
2915 /*++
2916 
2917 Routine Description:
2918  Propagates the wait wake status to all the child PDOs. This will cause any
2919  pended wait wake requests to be completed with the given wait wake status.
2920 
2921 Arguments:
2922  WaitWakeStatus - The NTSTATUS value to use for compeleting any pended wait
2923  wake requests on the child PDOs.
2924 
2925 Return Value:
2926  None
2927 
2928  --*/
2929 {
2931  PLIST_ENTRY ple;
2932  KIRQL irql;
2933 
2937  ple = ple->Flink) {
2938 
2940 
2941  if (pEntry->m_PendingDeleteOnScanEnd) {
2942  COVERAGE_TRAP();
2943  continue;
2944  }
2945 
2946  if (pEntry->m_Pdo != NULL) {
2947  ASSERT(pEntry->m_Pdo->m_PkgPnp->m_SharedPower.m_WaitWakeOwner == TRUE);
2948  pEntry->m_Pdo->m_PkgPnp->PowerIndicateWaitWakeStatus(WaitWakeStatus);
2949  }
2950  }
2952 }
2953 
2954 VOID
2956  VOID
2957  )
2958 /*++
2959 
2960 Routine Description:
2961  Notification through IFxStateChangeNotification that the parent device is
2962  being surprise removed
2963 
2964 Arguments:
2965  None
2966 
2967 Return Value:
2968  None
2969 
2970  --*/
2971 {
2972  PLIST_ENTRY pCur, pNext;
2973  LIST_ENTRY freeHead;
2975  KIRQL irql;
2976 
2977  InitializeListHead(&freeHead);
2978 
2980 
2982 
2983  //
2984  // Walk over all mod entries and remove any pending inserts. Note that
2985  // MarkModificationNotPresentWorker will add any such INSERTs found in the
2986  // mod list to the free list.
2987  //
2990  pCur = pNext) {
2991 
2992  pNext = pCur->Flink;
2993 
2995 
2996  if (pEntry->m_ModificationState == ModificationInsert) {
2998  }
2999  }
3000 
3001  //
3002  // Walk over all desc entries and remove them. Since
3003  // MarkDescriptionNotPresentWorker doesn't drain the mods,
3004  // we don't have to worry about any entries disappearing.
3005  //
3008  pCur = pCur->Flink) {
3009 
3011 
3012  if (pEntry->IsPresent()) {
3014  }
3015  }
3016 
3017  //
3018  // Attempt to drain any mods we made.
3019  //
3020  ProcessModificationsLocked(&freeHead);
3021 
3022  //
3023  // Walk over all desc entries and advance them to missing.
3024  //
3027  pCur = pCur->Flink) {
3028 
3030 
3031  if (pEntry->m_DescriptionState == DescriptionNotPresent) {
3032  pEntry->m_DescriptionState = DescriptionReportedMissing;
3033  }
3034  }
3035 
3037 
3038  DrainFreeListHead(&freeHead);
3039 }
3040 
3041 VOID
3043  __inout PLONG ChildCount
3044  )
3045 /*++
3046 
3047 Routine Description:
3048  Notification through IFxStateChangeNotification that the parent device is
3049  being removed.
3050 
3051 Arguments:
3052  None
3053 
3054 Return Value:
3055  None
3056 
3057  --*/
3058 {
3059  PLIST_ENTRY pCur;
3060  LIST_ENTRY freeHead;
3062  KIRQL irql;
3063 
3065  "WDFCHILDLIST %p: removing children", GetHandle());
3066 
3067  InitializeListHead(&freeHead);
3068  pEntry = NULL;
3069 
3071 
3072  //
3073  // Surprise remove handling covers the first stage of processing. This will
3074  // process the modification list, esp the insert modifications which will
3075  // be cleaned up.
3076  //
3078 
3080 
3081  ProcessModificationsLocked(&freeHead);
3082 
3084 
3085  for ( ; ; ) {
3086 
3087  //
3088  // Find the first child which was not surprise removed. If surprise
3089  // removed and not yet removed, then there is an outstanding handle
3090  // which has not yet been closed.
3091  //
3094  pCur = pCur->Flink) {
3095 
3097 
3098  ASSERT(pEntry->m_DescriptionState == DescriptionReportedMissing);
3099 
3100  if (pEntry->m_ProcessingSurpriseRemove == FALSE) {
3101  break;
3102  }
3103  }
3104 
3105  //
3106  // If we are at the end of the list, we are done
3107  //
3108  if (pCur == &m_DescriptionListHead) {
3109  break;
3110  }
3111 
3113  "Removing entry %p, WDFDEVICE %p, PDO %p",
3114  pEntry, pEntry->m_Pdo->GetHandle(),
3115  pEntry->m_Pdo->GetPhysicalDevice());
3116 
3117  ASSERT(pEntry->m_ModificationState == ModificationUnspecified);
3118  RemoveEntryList(&pEntry->m_DescriptionLink);
3119  InitializeListHead(&pEntry->m_DescriptionLink);
3120 
3122 
3123  //
3124  // Go through FxPkgPdo to handle cleanup. CleanupOrphanedDevice will
3125  // free this entry.
3126  //
3127  ASSERT(pEntry->m_Pdo != NULL);
3128  ASSERT(pEntry->m_PendingDeleteOnScanEnd == FALSE);
3129 
3130  pEntry->m_Pdo->SetParentWaitingOnRemoval();
3131  InterlockedIncrement(ChildCount);
3132 
3133  //
3134  // Start the child going away
3135  //
3136  pEntry->m_Pdo->m_PkgPnp->PnpProcessEvent(PnpEventParentRemoved);
3137 
3139  }
3140 
3142  ProcessModificationsLocked(&freeHead);
3143 
3145 
3146  DrainFreeListHead(&freeHead);
3147 }
3148 
3150 NTSTATUS
3152  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
3154  __in size_t* TotalDescriptionSize
3155  )
3156 {
3157  NTSTATUS status;
3158 
3159  if (Config == NULL) {
3162  "Invalid Config, NULL is not allowed, %!STATUS!", status);
3163  return status;
3164  }
3165 
3166  if (Config->Size != sizeof(WDF_CHILD_LIST_CONFIG)) {
3169  "Config->Size incorrect, expected %d, got %d, %!STATUS!",
3170  sizeof(WDF_CHILD_LIST_CONFIG), Config->Size, status);
3171  return status;
3172  }
3173  if (Config->IdentificationDescriptionSize == 0) {
3176  "Config->IdentificationDescriptionSize must be non zero, "
3177  "%!STATUS!", status);
3178  return status;
3179  }
3180  if (Config->EvtChildListCreateDevice == NULL) {
3183  "Config->EvtChildListCreateDevice, NULL is not allowed, "
3184  "%!STATUS!", status);
3185  return status;
3186  }
3187 
3188  return _ComputeTotalDescriptionSize(FxDriverGlobals,
3189  Config,
3190  TotalDescriptionSize);
3191 }
3192 
3194 NTSTATUS
3196  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
3198  __in size_t* TotalDescriptionSize
3199  )
3200 {
3201  size_t addressAligned, idAligned;
3202  NTSTATUS status;
3203 
3204  *TotalDescriptionSize = 0;
3205 
3206  //
3207  // FxDeviceDescriptionEntry::operator new() will allocate a block of memory
3208  // that is
3209  // size =
3210  // WDF_ALIGN_SIZE_UP(sizeof(FxDeviceDescriptionEntry), sizeof(PVOID)) +
3211  // WDF_ALIGN_SIZE_UP(AddressDescriptionSize, sizeof(PVOID)) +
3212  // WDF_ALIGN_SIZE_UP(IdentificationDescriptionSize, sizeof(PVOID));
3213  //
3214  // Validate the size now beforehand, not every we allocate
3215  //
3216  //
3217  // Test for overflow
3218  //
3219  idAligned = WDF_ALIGN_SIZE_UP(Config->IdentificationDescriptionSize,
3220  sizeof(PVOID));
3221  if (idAligned < Config->IdentificationDescriptionSize) {
3224  "Config->IdentificationDescriptionSize %d too large"
3225  "%!STATUS!", Config->IdentificationDescriptionSize,
3226  status);
3227  return status;
3228  }
3229 
3230  addressAligned = WDF_ALIGN_SIZE_UP(Config->AddressDescriptionSize,
3231  sizeof(PVOID));
3232  if (addressAligned < Config->AddressDescriptionSize) {
3235  "Config->AddressDescriptionSize %d too large, %!STATUS!",
3236  Config->AddressDescriptionSize, status);
3237  return status;
3238  }
3239 
3240  status = RtlSizeTAdd(
3242  idAligned,
3243  TotalDescriptionSize
3244  );
3245  if (!NT_SUCCESS(status)) {
3247  FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
3248  "Could not add ID description size to block size, %!STATUS!",
3249  status);
3250  return status;
3251  }
3252 
3253  status = RtlSizeTAdd(*TotalDescriptionSize,
3254  addressAligned,
3255  TotalDescriptionSize);
3256  if (!NT_SUCCESS(status)) {
3258  FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
3259  "Could not add address description size to block size, %!STATUS!",
3260  status);
3261  return status;
3262  }
3263 
3264  return STATUS_SUCCESS;
3265 }
struct _LIST_ENTRY * PLIST_ENTRY
FxChildList * m_DeviceList
FxDeviceDescriptionEntry * SearchBackwardsForMatchingDescriptionLocked(__in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Id)
Definition: window.h:584
CfxDevice * m_Device
Definition: fxobject.hpp:329
VOID MarkModificationNotPresentWorker(__inout PLIST_ENTRY FreeListHead, __inout FxDeviceDescriptionEntry *ModificationEntry)
BOOLEAN HasAddressDescriptions(VOID)
LIST_ENTRY m_ModificationListHead
_Must_inspect_result_ NTSTATUS VerifyModificationEntry(__in PLIST_ENTRY Entry)
return STATUS_NOT_SUPPORTED
LIST_ENTRY m_DescriptionListHead
#define _Must_inspect_result_
Definition: no_sal2.h:62
PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY m_EvtIdentificationDescriptionCopy
#define ULongToPtr(ul)
Definition: basetsd.h:92
BOOLEAN CloneEntryLocked(__inout PLIST_ENTRY FreeListHead, __inout FxDeviceDescriptionEntry *Entry, __in BOOLEAN FromQDR)
BOOLEAN FxVerifierOn
Definition: fxglobals.h:420
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
pInit Pdo Static
_Must_inspect_result_ NTSTATUS GetNextDevice(__out WDFDEVICE *Device, __inout PWDF_CHILD_LIST_ITERATOR Iterator, __inout_opt PWDF_CHILD_RETRIEVE_INFO Info)
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
#define STATUS_NO_MORE_ENTRIES
Definition: ntstatus.h:205
struct _Entry Entry
Definition: kefuncs.h:627
GLuint64EXT * result
Definition: glext.h:11304
VOID CopyAddress(__out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER Dest, __in_opt PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER Source)
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
VOID PnpProcessEvent(__in FxPnpEvent Event, __in BOOLEAN ProcessEventOnDifferentThread=FALSE)
_Must_inspect_result_ NTSTATUS Invoke(__in WDFCHILDLIST DeviceList, __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, __in PWDFDEVICE_INIT ChildInit)
Definition: fxchildlist.hpp:46
FxDeviceDescriptionEntry * SearchBackwardsForMatchingModificationLocked(__in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Id)
#define WDF_PTR_ADD_OFFSET(_ptr, _offset)
Definition: wdfcore.h:144
PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE m_EvtAddressDescriptionDuplicate
BOOLEAN m_InvalidationNeeded
#define __in_opt
Definition: dbghelp.h:38
VOID CleanupDescriptions(__in_opt PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdDescription, __in_opt PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddrDescription)
VOID NotifyDeviceSurpriseRemove(VOID)
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
WDFDEVICE __inline GetHandle(VOID)
Definition: fxdevice.hpp:237
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
PDEVICE_OBJECT Objects[1]
Definition: iotypes.h:2160
FxChildListScanForChildrenCallback m_EvtScanForChildren
VOID UpdateAllAsPresent(__in_opt PULONG ScanTag=NULL)
PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY m_EvtAddressDescriptionCopy
PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP m_EvtAddressDescriptionCleanup
_Must_inspect_result_ NTSTATUS DuplicateAddress(__out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER Dest, __in PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER Source)
#define STATUS_OBJECT_NAME_EXISTS
Definition: ntstatus.h:114
LONG NTSTATUS
Definition: precomp.h:26
virtual BOOLEAN Dispose(VOID)
operator
__inline VOID Set()
Definition: mxeventkm.h:91
struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER * PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER
WDFDEVICE GetDevice(VOID)
static size_t _ComputeRelationsSize(__in ULONG Count)
FxDevice * pPdo
VOID SetTransactionedObject(__in FxObject *Object)
KIRQL irql
Definition: wave.h:1
VOID InvokeReportedMissingCallback(VOID)
PDEVICE_LIST DeviceList
Definition: utils.c:27
BOOLEAN m_AddedToStaticList
Definition: fxpkgpdo.hpp:63
_Must_inspect_result_ NTSTATUS ProcessBusRelations(__inout PDEVICE_RELATIONS *DeviceRelations)
static const WCHAR Description[]
Definition: oid.c:1266
#define InsertTailList(ListHead, Entry)
#define __inout_opt
Definition: dbghelp.h:53
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
VOID EndIteration(__inout PWDF_CHILD_LIST_ITERATOR Iterator)
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
static int init
Definition: wintirpc.c:33
PULONG m_ScanTag
DWORD Id
PSINGLE_LIST_ENTRY ple
PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP m_EvtIdentificationDescriptionCleanup
FxDevice * device
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:683
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
CfxDevice * GetDeviceFromId(__inout PWDF_CHILD_RETRIEVE_INFO Info)
UCHAR KIRQL
Definition: env_spec_w32.h:591
_Must_inspect_result_ NTSTATUS UpdateDeviceAsMissing(__in CfxDevice *Device)
FxChildList(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in size_t TotalDescriptionSize, __in CfxDevice *Device, __in BOOLEAN Static)
#define __out_opt
Definition: dbghelp.h:65
_Must_inspect_result_ NTSTATUS DuplicateId(__out PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Dest, __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Source)
CHECK_RETURN_IF_USER_MODE __inline NTSTATUS Initialize(__in EVENT_TYPE Type, __in BOOLEAN InitialState)
Definition: mxeventkm.h:55
_Must_inspect_result_ _In_ WDFDEVICE _In_ NTSTATUS WaitWakeStatus
Definition: wdfdevice.h:3942
#define FALSE
Definition: types.h:117
#define TRACE_LEVEL_VERBOSE
Definition: storswtr.h:30
VOID BeginScan(__out_opt PULONG ScanTag=NULL)
Definition: Header.h:8
Definition: devices.h:37
PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED m_EvtChildListDeviceReenumerated
VOID EndScan(__inout_opt PULONG ScanTag=NULL)
FxChildList * pList
#define ASSERTMSG(msg, exp)
Definition: nt_native.h:431
VOID ProcessModificationsLocked(__inout PLIST_ENTRY FreeListHead)
FORCEINLINE size_t WDF_ALIGN_SIZE_UP(_In_ size_t Length, _In_ size_t AlignTo)
Definition: wdfcore.h:129
KSPIN_LOCK m_ListLock
FxChildList * GetParentList(VOID)
VOID MarkDisposeOverride(__in FxObjectLockState State=ObjectLock)
Definition: fxobject.hpp:1101
PVOID __inline GetObjectHandle(VOID)
Definition: fxobject.hpp:603
#define __out
Definition: dbghelp.h:62
FORCEINLINE VOID KeInitializeSpinLock(_Out_ PKSPIN_LOCK SpinLock)
Definition: kefuncs.h:238
struct _DEVICE_RELATIONS * PDEVICE_RELATIONS
friend struct FxDeviceDescriptionEntry
_Inout_ PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription
Definition: wdfchildlist.h:255
unsigned char BOOLEAN
FxChildListModificationState m_ModificationState
PFN_WDF_CHILD_LIST_CREATE_DEVICE m_Method
Definition: fxchildlist.hpp:61
#define COVERAGE_TRAP()
Definition: fxmacros.hpp:246
VOID PostParentToD0(VOID)
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
VOID GetAddressDescriptionFromEntry(__in FxDeviceDescriptionEntry *Entry, __out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription)
BOOLEAN IsStaticList(VOID)
__inline VOID Clear()
Definition: mxeventkm.h:102
FxChildListDescriptionState m_DescriptionState
FxTransactionedEntry m_TransactionLink
UCHAR m_EnumRetries
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define PtrToUlong(u)
Definition: config.h:107
MxEvent m_ScanEvent
FxDevice * pDevice
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
__inline NTSTATUS FxVerifierCheckIrqlLevel(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in KIRQL Irql)
Definition: fxverifier.h:158
WDF_EXTERN_C_START enum _WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS
BOOLEAN m_IsAdded
GLsizeiptr size
Definition: glext.h:5919
PFX_DRIVER_GLOBALS pFxDriverGlobals
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
MdDeviceObject __inline GetPhysicalDevice(VOID)
Definition: fxdevice.hpp:228
#define ASSERT(a)
Definition: mode.c:45
VOID CancelScan(__in BOOLEAN EndTheScan, __inout_opt PULONG ScanTag)
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
_Must_inspect_result_ NTSTATUS GetAddressDescription(__in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, __out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription)
PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER m_AddressDescription
FxChildListCreateDeviceCallback m_EvtCreateDevice
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
_In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR Iterator
Definition: wdfchildlist.h:653
#define ObDereferenceObject
Definition: obfuncs.h:203
VOID IndicateWakeStatus(__in NTSTATUS WakeWakeStatus)
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
WDFCHILDLIST GetHandle(VOID)
PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE m_EvtIdentificationDescriptionCompare
_In_ PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription
Definition: wdfchildlist.h:124
__inline FxPkgPdo * GetPdoPkg(VOID)
Definition: fxdevice.hpp:1254
BOOLEAN IsDeviceRemoved(VOID)
ULONG m_AddressDescriptionSize
VOID Initialize(__in PWDF_CHILD_LIST_CONFIG Config)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
__inline FxDriver * GetDriver(VOID)
Definition: fxdevice.hpp:164
char * PBOOLEAN
Definition: retypes.h:11
_Must_inspect_result_ NTSTATUS Add(__in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, __in_opt PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription, __in_opt PULONG ScanTag=NULL)
__inline WDF_DEVICE_PNP_STATE GetDevicePnpState()
Definition: fxdevice.hpp:1149
ULONG m_ScanCount
VOID MarkNoDeleteDDI(__in FxObjectLockState State=ObjectLock)
Definition: fxobject.hpp:1118
#define __inout
Definition: dbghelp.h:50
VOID DrainFreeListHead(__inout PLIST_ENTRY FreeListHead)
FxDeviceDescriptionEntry(__inout FxChildList *DeviceList, __in ULONG AddressDescriptionSize, __in ULONG IdentificationDescriptionSize)
Definition: fxchildlist.cpp:31
Definition: typedefs.h:119
VOID ReenumerateEntry(__inout FxDeviceDescriptionEntry *Entry)
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
_Must_inspect_result_ _In_ WDFDEVICE Device
Definition: wdfchildlist.h:474
PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN m_Method
Definition: fxchildlist.hpp:86
_Must_inspect_result_ FxDeviceDescriptionEntry * Clone(__inout PLIST_ENTRY FreeListHead)
FxPkgPnp * m_PkgPnp
Definition: fxdevice.hpp:670
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_CHILD_LIST_CONFIG Config
Definition: wdfchildlist.h:474
MdDeviceObject __inline GetSafePhysicalDevice(VOID)
Definition: fxdevice.hpp:1005
FxCollectionEntry * cur
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_CHILD_LIST_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFCHILDLIST * ChildList
Definition: wdfchildlist.h:474
#define TRACINGPNP
Definition: dbgtrace.h:67
static FxDeviceDescriptionEntry * _FromModificationLink(__in PLIST_ENTRY Link)
VOID NotifyDeviceRemove(__inout PLONG ChildCount)
VOID NTAPI IoInvalidateDeviceRelations(IN PDEVICE_OBJECT DeviceObject, IN DEVICE_RELATION_TYPE Type)
Definition: pnpmgr.c:2419
FxDeviceDescriptionEntry * m_Description
Definition: fxpkgpdo.hpp:40
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
#define InterlockedIncrement
Definition: armddk.h:53
VOID MarkDescriptionNotPresentWorker(__inout FxDeviceDescriptionEntry *DescriptionEntry, __in BOOLEAN ModificationCanBeQueued)
FxChildListState m_State
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
ULONG GetScanCount(VOID)
static FxDeviceDescriptionEntry * _FromDescriptionLink(__in PLIST_ENTRY Link)
_Must_inspect_result_ NTSTATUS VerifyDescriptionEntry(__in PLIST_ENTRY Entry)
SINGLE_LIST_ENTRY * pCur
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
BOOLEAN IsDeviceReportedMissing(VOID)
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
size_t m_TotalDescriptionSize
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
#define STATUS_INVALID_DEVICE_OBJECT_PARAMETER
Definition: ntstatus.h:915
_Must_inspect_result_ NTSTATUS UpdateAsMissing(__in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Description)
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
static _Must_inspect_result_ NTSTATUS _CreateAndInit(__out FxChildList **ChildList, __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PWDF_OBJECT_ATTRIBUTES ListAttributes, __in size_t TotalDescriptionSize, __in CfxDevice *Device, __in PWDF_CHILD_LIST_CONFIG ListConfig, __in BOOLEAN Static=FALSE)
#define STATUS_RETRY
Definition: udferr_usr.h:182
PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE m_EvtIdentificationDescriptionDuplicate
virtual VOID RemoveChildList(__inout FxChildList *List)
Definition: fxdevicekm.cpp:441
VOID CopyId(__out PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Dest, __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Source)
virtual VOID AddChildList(__inout FxChildList *List)
Definition: fxdevicekm.cpp:431
VOID DeleteFromFailedCreate(VOID)
Definition: fxobject.cpp:391
static _Must_inspect_result_ NTSTATUS _ComputeTotalDescriptionSize(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PWDF_CHILD_LIST_CONFIG Config, __in size_t *TotalDescriptionSize)
#define ObReferenceObject
Definition: obfuncs.h:204
BOOLEAN CreateDevice(__inout FxDeviceDescriptionEntry *Entry, __inout PBOOLEAN InvalidateRelations)
unsigned int ULONG
Definition: retypes.h:1
struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER * PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
ULONG m_IdentificationDescriptionSize
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
VOID DeviceSurpriseRemoved(VOID)
#define STATUS_SUCCESS
Definition: shellext.h:65
void exit(int exitcode)
Definition: _exit.c:33
GLfloat GLfloat p
Definition: glext.h:8902
static _Must_inspect_result_ NTSTATUS _ValidateConfig(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PWDF_CHILD_LIST_CONFIG Config, __in size_t *TotalDescriptionSize)
VOID UpdateAddressDescriptionFromEntry(__inout FxDeviceDescriptionEntry *Entry, __in PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription)
PLIST_ENTRY pEntry
Definition: fxioqueue.cpp:4484
PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER m_IdentificationDescription
BOOLEAN CompareId(__in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Lhs, __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Rhs)
#define __in
Definition: dbghelp.h:35
signed int * PLONG
Definition: retypes.h:5
WDFDEVICE GetNextStaticDevice(__in WDFDEVICE PreviousDevice, __in ULONG Flags)
static SERVICE_STATUS status
Definition: service.c:31
VOID BeginIteration(__inout PWDF_CHILD_LIST_ITERATOR Iterator)
BOOLEAN ReenumerateEntryLocked(__inout FxDeviceDescriptionEntry *Entry, __in BOOLEAN FromQDR)
base of all file and directory entries
Definition: entries.h:82
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
description Header IdentificationDescriptionSize
BOOLEAN m_StaticList
FxVerifierDbgBreakPoint(pFxDriverGlobals)
#define DO_NOTHING()
Definition: mxgeneral.h:32
VOID InitIterator(__inout PWDF_CHILD_LIST_ITERATOR Iterator)
Definition: ps.c:97