ReactOS  0.4.15-dev-2991-g632fa1c
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 
415 VOID
418  )
419 {
420  //
421  // Driver cannot call WdfObjectDelete on this handle
422  //
423  MarkNoDeleteDDI();
424 
425  m_IdentificationDescriptionSize = Config->IdentificationDescriptionSize;
426  m_AddressDescriptionSize = Config->AddressDescriptionSize;
427 
428  m_EvtCreateDevice.m_Method = Config->EvtChildListCreateDevice;
429  m_EvtScanForChildren.m_Method = Config->EvtChildListScanForChildren;
430 
431  m_EvtIdentificationDescriptionDuplicate = Config->EvtChildListIdentificationDescriptionDuplicate;
432  m_EvtIdentificationDescriptionCopy = Config->EvtChildListIdentificationDescriptionCopy;
433  m_EvtIdentificationDescriptionCleanup = Config->EvtChildListIdentificationDescriptionCleanup;
434  m_EvtIdentificationDescriptionCompare = Config->EvtChildListIdentificationDescriptionCompare;
435 
436  m_EvtAddressDescriptionDuplicate = Config->EvtChildListAddressDescriptionDuplicate;
437  m_EvtAddressDescriptionCopy = Config->EvtChildListAddressDescriptionCopy;
438  m_EvtAddressDescriptionCleanup = Config->EvtChildListAddressDescriptionCleanup;
439 
440  m_EvtChildListDeviceReenumerated = Config->EvtChildListDeviceReenumerated;
441 
442  //
443  // Add this ChildList to the parent device's list of children lists.
444  //
445  m_Device->AddChildList(this);
446  m_IsAdded = TRUE;
447 }
448 
449 WDFDEVICE
451  VOID
452  )
453 {
454  return m_Device->GetHandle();
455 }
456 
457 FxDevice*
460  )
461 {
463  FxDevice* device;
465  KIRQL irql;
466 
467  device = NULL;
468 
470 
472  Info->IdentificationDescription);
473 
474  if (pEntry != NULL && pEntry->m_ModificationState == ModificationInsert) {
476  }
477  else {
479  Info->IdentificationDescription);
480 
481  if (pEntry != NULL) {
482  if (pEntry->m_DescriptionState == DescriptionPresentNeedsInstantiation) {
484  }
485  else {
487  device = pEntry->m_Pdo;
488  }
489  }
490  else {
492  }
493  }
494 
495  if (pEntry != NULL && Info->AddressDescription != NULL) {
496  CopyAddress(Info->AddressDescription,
497  pEntry->m_AddressDescription);
498  }
499 
501 
502  Info->Status = status;
503 
504  return device;
505 }
506 
508 NTSTATUS
512  )
513 {
516  KIRQL irql;
517 
519 
522 
523  if (pEntry == NULL) {
526  }
527 
528  if (pEntry != NULL) {
529  CopyAddress(AddressDescription, pEntry->m_AddressDescription);
531  }
532  else {
534  }
535 
537 
538  return status;
539 }
540 
541 VOID
545  )
546 {
547  KIRQL irql;
548 
550  CopyAddress(AddressDescription, Entry->m_AddressDescription);
552 }
553 
554 VOID
556  __out_opt PULONG ScanTag
557  )
558 {
561  KIRQL irql;
562 
564 
565  // KeClearEvent is faster than KeResetEvent for putting event to not-signaled state
566  m_ScanEvent.Clear();
567  m_ScanCount++;
568 
571  "Begin scan on WDFCHILDLIST %p, scan count %d",
573 
574  if (ScanTag != NULL) {
575  if (m_ScanTag != NULL) {
577  }
578 
579  *ScanTag = ScanTagActive;
580  m_ScanTag = ScanTag;
581  }
582 
583  //
584  // Start by walking over all entries and setting their FoundInLastScan
585  // fields to FALSE. We need to set both present items in the Desc list
586  // and inserts in the Mod list. It's actually easier just to walk over
587  // everything.
588  //
591  ple = ple->Flink) {
593  pEntry->m_FoundInLastScan = FALSE;
594  }
595 
598  ple = ple->Flink) {
600  pEntry->m_FoundInLastScan = FALSE;
601  }
602 
604 }
605 
606 VOID
608  __inout_opt PULONG ScanTag
609  )
610 {
611  PLIST_ENTRY pCur, pNext;
612  LIST_ENTRY freeHead;
614  KIRQL irql;
615 
616  InitializeListHead(&freeHead);
617 
619 
620  if (ScanTag != NULL) {
621  if (*ScanTag != ScanTagActive) {
622  ASSERT(*ScanTag == ScanTagCancelled);
624  return;
625  }
626 
627  *ScanTag = ScanTagFinished;
628  m_ScanTag = NULL;
629  }
630 
631  m_ScanCount--;
632 
635  "End scan on WDFCHILDLIST %p, scan count %d",
637 
638  if (m_ScanCount == 0) {
639  //
640  // Walk over all modification entries and remove any pending insert that
641  // wasn't seen in the scan. Note that MarkDescriptionNotPresentWorker will
642  // enqueue the entry to be freed later.
643  //
644  // Also, convert any clones of devices not reported as present to
645  // removal modifications so that the original is still reported missing.
646  //
649  pCur = pNext) {
650 
651  pNext = pCur->Flink;
652 
654 
657  "entry %p modified in last scan, "
658  "mod state %!FxChildListModificationState!,"
659  "desc state %!FxChildListDescriptionState!",
660  pEntry, pEntry->m_ModificationState,
661  pEntry->m_DescriptionState);
662 
663  if (pEntry->m_FoundInLastScan == FALSE) {
664  switch (pEntry->m_ModificationState) {
665  case ModificationInsert:
666  //
667  // Insertion that never made through to the end of a scan.
668  //
670  break;
671 
672  case ModificationClone:
675  "clone of PDO WDFDEVICE %p, !devobj %p dropped because "
676  "it is missing", pEntry->m_Pdo->GetHandle(),
677  pEntry->m_Pdo->GetDeviceObject());
678 
679  //
680  // We were asked for a clone in the middle of a scan and the
681  // device was not reported, so it is now missing. Convert
682  // the clone modification to a remove modification.
683  //
684  pEntry->m_ModificationState = ModificationRemoveNotify;
685 
686  //
687  // Remove the modification from the current mod list. It
688  // will be re-added below when we iterate over the
689  // descriptions list.
690  //
691  RemoveEntryList(&pEntry->m_ModificationLink);
692  InitializeListHead(&pEntry->m_ModificationLink);
693 
694  //
695  // We can only have been cloning a device which is present
696  // and not yet reported missing to the OS.
697  //
698  ASSERT(pEntry->m_DescriptionState ==
700  break;
701  }
702  }
703  }
704 
705  //
706  // Walk over all desc entries and remove anything that wasn't found in the
707  // scan. Since MarkDescriptionNotPresentWorker doesn't drain the
708  // modifications, we don't have to worry about any entries disappearing.
709  //
712  pCur = pCur->Flink) {
713 
715 
716  if (pEntry->m_PendingDeleteOnScanEnd) {
717  //
718  // The entry was pnp removed but was not removed from list
719  // because scan count was > 0. It is safe to remove and delete
720  // it now.
721 
722  // Update the current pointer before the entry is removed.
723  pCur = pCur->Blink;
724 
725  RemoveEntryList(&pEntry->m_DescriptionLink);
726  InsertTailList(&freeHead, &pEntry->m_DescriptionLink);
727  pEntry = NULL;
728  continue;
729  }
730  else if (pEntry->IsPresent() && pEntry->m_FoundInLastScan == FALSE) {
731  if (pEntry->m_Pdo != NULL) {
734  "marking PDO WDFDEVICE %p, !devobj %p as not present",
735  pEntry->m_Pdo->GetHandle(),
736  pEntry->m_Pdo->GetDeviceObject());
737 
738  }
739  else {
742  "marking PDO (entry %p) which needs instantiation as "
743  "not present", pEntry);
744  }
745 
747  }
748  }
749 
750  //
751  // Attempt to drain any mods we made.
752  //
753  ProcessModificationsLocked(&freeHead);
754 
755  //
756  // We need to check m_KnownPdo here because if this
757  // object is attached to a PDO, the PDO's devobj could be in a state where
758  // PnP does not know it is a PDO yet. m_KnownPdo
759  // is set when the PDO receives a start device and by the time start
760  // device arrives, we definitely know the PDO is known the PnP.
761  //
762  // No need to hold a lock while checking m_KnownPdo
763  // because if miss the transition from FALSE to TRUE, relations will
764  // automaticaly be invalidated by the cause of that transition (start
765  // device arrival). PnP automatically sends a QDR after a successful
766  // start.
767  //
768 
769  if (m_InvalidationNeeded) {
770  PDEVICE_OBJECT pdo;
771 
772  //
773  // This does the m_KnownPdo check.
774  //
776 
777  if (pdo != NULL) {
780  }
781  }
782 
783  m_ScanEvent.Set();
784  }
785 
787 
788  //
789  // Free structures outside of any internal WDF lock
790  //
791  DrainFreeListHead(&freeHead);
792 }
793 
794 VOID
796  __in BOOLEAN EndTheScan,
797  __inout_opt PULONG ScanTag
798  )
799 {
800  *ScanTag = ScanTagCancelled;
801 
802  if (EndTheScan) {
803  EndScan(ScanTag);
804  }
805 }
806 
807 VOID
810  )
811 {
813 
814  if (Iterator->Flags & WdfRetrievePendingChildren) {
815  Iterator->Reserved[ModificationIndex] = ULongToPtr(1);
816  }
817 }
818 
819 VOID
822  )
823 {
824  KIRQL irql;
825 
826  //
827  // Almost the same semantic as BeginScan except we don't mark all of the
828  // children as missing when we start.
829  //
831 
833  //
834  // Set the scanevent to non-signaled state. Some code paths such as
835  // PDO eject will wait for the completion of child list iteration or scan
836  // so that a QDR that follows eject is guaranteed to pick up the change in
837  // PDO state that the code path made. Note that scan and iteration can be
838  // nested and in that case this event will be clear each time but it will be
839  // set (signalled) only after all the iteration and scan opeartions have
840  // completed.
841  //
842  m_ScanEvent.Clear();
843  m_ScanCount++;
844 
846  "Begin iteration on WDFCHILDLIST %p, scan count %d",
848 
850 }
851 
852 VOID
855  )
856 {
858  "end iteration on WDFCHILDLIST");
859 
860  //
861  // Semantic is exactly the same as EndScan. Basically, all changes are
862  // delayed until there are no more active scans, so the end of an interation
863  // is the same as the end of a scan.
864  //
865  EndScan();
866 
867  RtlZeroMemory(&Iterator->Reserved[0], sizeof(Iterator->Reserved));
868 }
869 
871 NTSTATUS
873  __out WDFDEVICE* Device,
876  )
877 {
882  ULONG cur, i;
883  KIRQL irql;
884  BOOLEAN found;
885 
886  pEntry = NULL;
888 
890 
891  ASSERT(m_ScanCount > 0);
892  if (m_ScanCount == 0) {
894 
897  "WDFCHILDLIST %p cannot retrieve next device if the list is not "
898  "locked for iteration, %!STATUS!", GetHandle(), status);
899 
900  goto Done;
901  }
902 
903  ple = (PLIST_ENTRY) Iterator->Reserved[DescriptionIndex];
904 
905  if (ple != NULL) {
908  if (!NT_SUCCESS(status)) {
909  goto Done;
910  }
911  }
912 
913  found = FALSE;
914 
915  //
916  // Try to find the next entry
917  //
918  for (ple = ple->Flink; ple != &m_DescriptionListHead; ple = ple->Flink) {
920 
921  if (pEntry->MatchStateToFlags(Iterator->Flags)) {
922  //
923  // An item was found
924  //
925  found = TRUE;
926 
927  //
928  // Call the caller's compare function to further refine the match
929  // if necessary.
930  //
931  if (Info != NULL &&
932  Info->EvtChildListIdentificationDescriptionCompare != NULL) {
933 
934  found = Info->EvtChildListIdentificationDescriptionCompare(
935  GetHandle(),
936  Info->IdentificationDescription,
937  pEntry->m_IdentificationDescription);
938  }
939 
940  if (found) {
941  break;
942  }
943  }
944  }
945 
946  if (found) {
947  //
948  // We can safely store the description entry because we are
949  // guaranteed it will stay in the description list until m_ScanCount
950  // reaches zero. In that case, the caller would need to call
951  // EndIteration
952  //
953  Iterator->Reserved[DescriptionIndex] = ple;
954 
955  if (pEntry->m_Pdo != NULL) {
956  *Device = pEntry->m_Pdo->GetHandle();
958  }
959  else {
961  }
962 
963  if (Info != NULL) {
964  if (Info->IdentificationDescription != NULL) {
965  CopyId(Info->IdentificationDescription,
966  pEntry->m_IdentificationDescription);
967  }
968  if (Info->AddressDescription != NULL) {
969  CopyAddress(Info->AddressDescription,
970  pEntry->m_AddressDescription);
971  }
972 
973  Info->Status = dstatus;
974  }
975 
977  }
978  else {
979  Iterator->Reserved[DescriptionIndex] = NULL;
980  ple = NULL;
982  }
983  }
984 
986 
987  if ((Iterator->Flags & WdfRetrievePendingChildren) == 0 ||
988  cur == 0) {
989  goto Done;
990  }
991 
992 
993  //
994  // Walk the modification list. Since this list can change from call to call
995  // to GetNextDevice we can't rely on the previous entry still being present
996  // so we must use an index into the list. This is not guaranteed to
997  // enumerate all pending additions, but it should be good enough.
998  //
999  found = FALSE;
1000 
1001  for (i = 1, ple = m_ModificationListHead.Flink;
1003  ple = ple->Flink) {
1004 
1006 
1007  if (pEntry->m_ModificationState == ModificationInsert) {
1008  i++;
1009 
1010  if (i > cur) {
1011  found = TRUE;
1012 
1013  if (Info != NULL &&
1014  Info->EvtChildListIdentificationDescriptionCompare != NULL) {
1015 
1016  found = Info->EvtChildListIdentificationDescriptionCompare(
1017  GetHandle(),
1018  Info->IdentificationDescription,
1019  pEntry->m_IdentificationDescription);
1020  }
1021 
1022  if (found) {
1023  //
1024  // Store the next item number
1025  //
1026  Iterator->Reserved[ModificationIndex] = ULongToPtr(i);
1027 
1028  if (Info != NULL) {
1029  if (Info->IdentificationDescription != NULL) {
1030  CopyId(Info->IdentificationDescription,
1031  pEntry->m_IdentificationDescription);
1032  }
1033  if (Info->AddressDescription != NULL) {
1034  CopyAddress(Info->AddressDescription,
1035  pEntry->m_AddressDescription);
1036  }
1037 
1039  }
1040 
1042  break;
1043  }
1044  }
1045  }
1046  }
1047 
1048  if (found == FALSE) {
1049  Iterator->Reserved[ModificationIndex] = ULongToPtr(0);
1050  }
1051 
1052 Done:
1054 
1055  return status;
1056 }
1057 
1058 WDFDEVICE
1060  __in WDFDEVICE PreviousDevice,
1061  __in ULONG Flags
1062  )
1063 {
1064  FxStaticChildDescription *pStatic;
1066  WDFDEVICE result;
1067  PLIST_ENTRY ple;
1068  KIRQL irql;
1069  BOOLEAN isNext;
1070 
1072 
1073  result = NULL;
1074 
1075  if (PreviousDevice == NULL) {
1076  //
1077  // No previous handle, we want the first device we find
1078  //
1079  isNext = TRUE;
1080  }
1081  else {
1082  //
1083  // We have a previuos handle, find it in the list first before setting
1084  // isNext.
1085  //
1086  isNext = FALSE;
1087  }
1088 
1090 
1091  ASSERT(m_ScanCount > 0);
1092  if (m_ScanCount == 0) {
1093  goto Done;
1094  }
1095 
1096  //
1097  // Try to find the next entry
1098  //
1102  ple = ple->Flink) {
1104 
1105  //
1106  // If the entry is marked pending delete, skip it, because the
1107  // relationship between entry and its PDO has been removed and PDO
1108  // may have actually been deleted by this time. The only reason
1109  // this entry is here is because there is still a scan going on
1110  // and the entry can't be removed in the midst of a scan.
1111  //
1112  if (pEntry->m_PendingDeleteOnScanEnd) {
1113  continue;
1114  }
1115 
1116  pStatic = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
1118  Header);
1119 
1120  //
1121  // Only return a handle if it is in a state in which the caller is
1122  // interested in hearing about.
1123  //
1124  if (isNext && pEntry->MatchStateToFlags(Flags)) {
1125  result = pStatic->Pdo->GetHandle();
1126  break;
1127  }
1128  else if (pStatic->Pdo->GetHandle() == PreviousDevice) {
1129  isNext = TRUE;
1130  }
1131  }
1132  }
1133 
1134  //
1135  // We have taken care of all the other states (reported, pending removal,
1136  // removed) in the previuos loop.
1137  //
1138  if (result == NULL && (Flags & WdfRetrievePendingChildren)) {
1139  //
1140  // Walk the modification list. Since this list can change from call to
1141  // call, there is no way to definitively give the driver a snapshot of
1142  // this list of modifications.
1143  //
1146  ple = ple->Flink) {
1147 
1149 
1150  if (pEntry->m_PendingDeleteOnScanEnd) {
1151  continue;
1152  }
1153 
1154  pStatic = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
1156  Header);
1157 
1158  //
1159  // Only return a handle if it is in a state in which the caller is
1160  // interested in hearing about.
1161  //
1162  if (isNext && pEntry->m_ModificationState == ModificationInsert) {
1163  result = pStatic->Pdo->GetHandle();
1164  break;
1165  }
1166  else if (pStatic->Pdo->GetHandle() == PreviousDevice) {
1167  isNext = TRUE;
1168  }
1169  }
1170  }
1171 
1172 Done:
1174 
1175  return result;
1176 }
1177 
1179 NTSTATUS
1182  )
1183 {
1185  LIST_ENTRY freeHead;
1186  NTSTATUS status;
1187  KIRQL irql;
1188 
1189  //
1190  // Assume success
1191  //
1193  InitializeListHead(&freeHead);
1194 
1196 
1198 
1199  if (pEntry != NULL) {
1200 
1201 
1202 
1203 
1204 
1205 
1206 
1207 
1209  }
1210  else {
1212 
1213  if (pEntry != NULL) {
1214  if (pEntry->IsPresent()) {
1216  }
1217  }
1218  else {
1219  //
1220  // Couldn't find anything
1221  //
1223  }
1224  }
1225 
1226  ProcessModificationsLocked(&freeHead);
1227 
1229 
1230  DrainFreeListHead(&freeHead);
1231 
1232  return status;
1233 }
1234 
1236 NTSTATUS
1239  )
1240 /*++
1241 
1242 Routine Description:
1243  Same as UpdateAsMissing except instead of a device description, we have the
1244  device itself.
1245 
1246 Arguments:
1247  Device - the device to mark as missing
1248 
1249 Return Value:
1250  NTSTATUS
1251 
1252  --*/
1253 {
1255  LIST_ENTRY freeHead, *ple;
1256  KIRQL irql;
1257  BOOLEAN found;
1258  CfxDevice *pdo;
1259 
1260  found = FALSE;
1261  pdo = NULL;
1262  InitializeListHead(&freeHead);
1263 
1265 
1268  ple = ple->Blink) {
1269 
1271 
1272  //
1273  // Static PDO may not be populated in m_Pdo yet, so check the PDO
1274  // from id description.
1275  //
1276  if (m_StaticList) {
1277  pdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
1279  Header)->Pdo;
1280  }
1281  else {
1282  pdo = pEntry->m_Pdo;
1283  }
1284 
1285  if (pdo == Device) {
1286  found = TRUE;
1288  break;
1289  }
1290  }
1291 
1292  if (found == FALSE) {
1295  ple = ple->Blink) {
1296 
1298 
1299  //
1300  // Static PDO may not be populated in m_Pdo yet, so check the PDO
1301  // from id description.
1302  //
1303  if (m_StaticList) {
1304  pdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
1306  Header)->Pdo;
1307  }
1308  else {
1309  pdo = pEntry->m_Pdo;
1310  }
1311 
1312  if (pdo == Device) {
1313  found = TRUE;
1314 
1315  if (pEntry->IsPresent()) {
1317  }
1318 
1319  break;
1320  }
1321  }
1322  }
1323 
1324  ProcessModificationsLocked(&freeHead);
1325 
1327 
1328  DrainFreeListHead(&freeHead);
1329 
1330  if (found) {
1331  return STATUS_SUCCESS;
1332  }
1333  else {
1334  return STATUS_NO_SUCH_DEVICE;
1335  }
1336 }
1337 
1338 BOOLEAN
1341  __in BOOLEAN FromQDR
1342  )
1343 {
1344  BOOLEAN result;
1345 
1346  //
1347  // Check to see if there are modifications pending
1348  //
1349  if (IsListEmpty(&Entry->m_ModificationLink) && Entry->IsPresent()) {
1350  //
1351  // No mods pending...
1352  //
1353 
1354  //
1355  // We can only go down this path if the device was reported to the system
1356  // b/c the stack on our PDO is the one invoking this call.
1357  //
1358  ASSERT(Entry->m_DescriptionState == DescriptionInstantiatedHasObject);
1359 
1360  if (FromQDR == FALSE) {
1361  //
1362  // The entry has not been reported as missing by the driver, try to
1363  // clone it and insert a modification.
1364  //
1365  Entry->m_ModificationState = ModificationClone;
1366  InsertTailList(&m_ModificationListHead, &Entry->m_ModificationLink);
1367  }
1368 
1371  "Inserting clone modification for PDO WDFDEVICE %p, !devobj %p",
1372  Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject());
1373 
1374  result = TRUE;
1375  }
1376  else {
1377  //
1378  // If there is a pending modification, we don't do anything.
1379  // If the device is already not present, we don't do anything.
1380  //
1381  // ModficiationRemove or
1382  // ModficiationRemoveNotify: we would be reenumerating a device which
1383  // is being removed which is not what we want
1384  //
1385  // ModificationClone: we would be cloning a clone which is not what
1386  // we want either
1387  //
1390  "Requested reenumeration for PDO WDFDEVICE %p, !devobj %p"
1391  " no possible (pending mod %d, currently present %d)",
1392  Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject(),
1393  IsListEmpty(&Entry->m_ModificationLink), Entry->IsPresent());
1394 
1395  result = FALSE;
1396  }
1397 
1398  return result;
1399 }
1400 
1401 VOID
1404  )
1405 {
1406  LIST_ENTRY freeHead;
1407  KIRQL irql;
1408 
1409  InitializeListHead(&freeHead);
1410 
1413  ProcessModificationsLocked(&freeHead);
1415 
1416  DrainFreeListHead(&freeHead);
1417 }
1418 
1419 
1420 VOID
1422  __in_opt PULONG ScanTag
1423  )
1424 {
1425  PLIST_ENTRY pCur, pNext;
1426  LIST_ENTRY freeHead;
1428  KIRQL irql;
1429 
1431 
1432  if (ScanTag != NULL) {
1433  if (*ScanTag != ScanTagActive) {
1434  ASSERT(*ScanTag == ScanTagCancelled);
1436  return;
1437  }
1438  }
1439 
1440  //
1441  // Walk over all mod entries and ensure any inserts are still marked
1442  // present.
1443  //
1446  pCur = pNext) {
1447 
1448  pNext = pCur->Flink;
1449 
1451 
1452  if (pEntry->m_ModificationState == ModificationInsert) {
1453  pEntry->m_FoundInLastScan = TRUE;
1454  }
1455  }
1456 
1457  //
1458  // Walk over all desc entries and ensure they are marked present.
1459  //
1462  pCur = pCur->Flink) {
1463 
1465 
1466  if (pEntry->IsPresent()) {
1467  ASSERT(pEntry->m_ModificationState != ModificationRemoveNotify);
1468 
1469  if (pEntry->m_ModificationState != ModificationRemove) {
1470  pEntry->m_FoundInLastScan = TRUE;
1471  }
1472  }
1473  }
1474 
1475  //
1476  // Attempt to drain any mods we made.
1477  //
1478  InitializeListHead(&freeHead);
1479  ProcessModificationsLocked(&freeHead);
1480 
1482 
1483  DrainFreeListHead(&freeHead);
1484 }
1485 
1487 NTSTATUS
1491  __in_opt PULONG ScanTag
1492  )
1493 {
1494  LIST_ENTRY freeHead;
1495  KIRQL irql;
1496  NTSTATUS status;
1498  BOOLEAN allocNewEntry;
1499 
1500  if (ScanTag != NULL) {
1501  if (*ScanTag != ScanTagActive) {
1502  ASSERT(*ScanTag == ScanTagCancelled);
1503 
1504  //
1505  // The descriptions are duplicated if needed, so no need to clean
1506  // them up
1507  //
1508  // CleanupDescriptions(IdentificationDescription,
1509  // AddressDescription);
1510 
1511  return STATUS_CANCELLED;
1512  }
1513  }
1514 
1516  allocNewEntry = FALSE;
1517  InitializeListHead(&freeHead);
1518 
1520 
1523  );
1524 
1525  if (pEntry != NULL) {
1526  switch (pEntry->m_ModificationState) {
1527  case ModificationInsert:
1528  if (HasAddressDescriptions()) {
1529  CopyAddress(pEntry->m_AddressDescription,
1531  }
1532 
1533  //
1534  // There is already a pending insert operation. All we need do is
1535  // update the stored description.
1536  //
1537  pEntry->m_FoundInLastScan = TRUE;
1538 
1540  break;
1541 
1542  case ModificationRemove:
1544  //
1545  // We found a pending remove. Therefore we need to add an insert
1546  // operation to the end of the mod list.
1547  //
1548  allocNewEntry = TRUE;
1549  break;
1550 
1551  default:
1552  ASSERTMSG("Invalid description modification state\n", FALSE);
1553  break;
1554  }
1555  }
1556  else {
1557  //
1558  // There are no matching modifications queued in the list. Go examine
1559  // the main list. We can't modify any of the child links right now
1560  // because the list might be locked down, but it is scannable!
1561  //
1564  );
1565 
1566  if (pEntry != NULL && pEntry->IsPresent()) {
1567  //
1568  // This is an update. Enqueue it through this node.
1569  //
1570  ASSERT(pEntry->m_ModificationState == ModificationUnspecified);
1571 
1572  if (HasAddressDescriptions()) {
1573  CopyAddress(pEntry->m_AddressDescription,
1575  }
1576 
1577  pEntry->m_FoundInLastScan = TRUE;
1579  }
1580  else {
1581  //
1582  // Either no entry was found, or a "missing" entry was identified
1583  // instead. In both cases we need to add an insert operation to the
1584  // end of the modification list.
1585  //
1586  allocNewEntry = TRUE;
1587  }
1588  }
1589 
1590  if (allocNewEntry) {
1591 
1592  pEntry =
1597 
1598  if (pEntry != NULL) {
1599  status = DuplicateId(pEntry->m_IdentificationDescription,
1601 
1603  status = DuplicateAddress(pEntry->m_AddressDescription,
1605  }
1606 
1607  if (NT_SUCCESS(status)) {
1608  pEntry->m_FoundInLastScan = TRUE;
1610  &pEntry->m_ModificationLink);
1611 
1612  if (m_StaticList) {
1613  FxDevice* pPdo;
1614 
1615  pPdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
1617  Header)->Pdo;
1618 
1619  //
1620  // The device is no longer deletable by the driver writer
1621  //
1622  pPdo->MarkNoDeleteDDI();
1623 
1624  //
1625  // Plug in the description like we do for dynamic PDOs in
1626  // FxPkgPdo::Initialize.
1627  //
1629 
1630  //
1631  // Let the device know it was inserted into the list. This
1632  // used to know in pPdo::DeleteObject how to proceed.
1633  //
1635  }
1636  }
1637  else {
1638  InsertTailList(&freeHead, &pEntry->m_DescriptionLink);
1639  }
1640  }
1641  else {
1643  }
1644  }
1645 
1646  ProcessModificationsLocked(&freeHead);
1647 
1649 
1650  DrainFreeListHead(&freeHead);
1651 
1652  return status;
1653 }
1654 
1655 VOID
1659  )
1660 {
1661  KIRQL irql;
1662 
1664  CopyAddress(Entry->m_AddressDescription, AddressDescription);
1666 
1667 
1668 
1669 
1670 
1671 
1672 }
1673 
1674 BOOLEAN
1676  __inout PLIST_ENTRY FreeListHead,
1678  __in BOOLEAN FromQDR
1679  )
1680 {
1681  FxDeviceDescriptionEntry* pClone;
1682  BOOLEAN invalidateRelations;
1683 
1686  "attempting to clone PDO WDFDEVICE %p, !devobj %p, From QDR %d",
1687  Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject(), FromQDR);
1688 
1689  invalidateRelations = FALSE;
1690 
1691  pClone = Entry->Clone(FreeListHead);
1692 
1693  if (pClone != NULL) {
1694  //
1695  // Check to see if the driver writer OKs the cloning, aka
1696  // reenumeration.
1697  //
1700  GetHandle(),
1701  Entry->m_Pdo->GetHandle(),
1702  Entry->m_AddressDescription,
1703  pClone->m_AddressDescription) == FALSE){
1704  //
1705  // The clone will be freed later by the caller by placing
1706  // it on the free list.
1707  //
1708  InsertTailList(FreeListHead, &pClone->m_DescriptionLink);
1709  }
1710  else {
1713  "clone successful (new entry is %p), marking PDO "
1714  "WDFDEVICE %p, !devobj %p as missing", pClone,
1715  Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject());
1716 
1717  //
1718  // Setup the state of the clone
1719  //
1722 
1723  //
1724  // This is important that this is last. If a subsequent
1725  // modification arrives for this device, we want to find the
1726  // clone before the old device. Since all changes search the
1727  // list backwards, inserting at the tail accomplishes this.
1728  //
1730  &pClone->m_DescriptionLink);
1731 
1732  if (FromQDR == FALSE) {
1733  Entry->m_DescriptionState = DescriptionNotPresent;
1734  invalidateRelations = TRUE;
1735  }
1736  }
1737  }
1738  else {
1739  //
1740  // Could not allocate a clone, do not anything.
1741  //
1742  DO_NOTHING();
1743  }
1744 
1745  //
1746  // Convert the original device's modification state back to a
1747  // unspecified in all cases.
1748  //
1749  Entry->m_ModificationState = ModificationUnspecified;
1750 
1751  return invalidateRelations;
1752 }
1753 
1754 VOID
1756  __inout PLIST_ENTRY FreeListHead
1757  )
1758 {
1760  PLIST_ENTRY pCur, pNext;
1761  BOOLEAN invalidateRelations;
1762 
1763  //
1764  // If the list is locked or there are still active scans, we must not process
1765  // any modifications.
1766  //
1767  if (m_State != ListUnlocked || m_ScanCount > 0) {
1770  "Not processing modifications on WDFCHILDLIST %p (list state %d, "
1771  "scan count %d)", GetObjectHandle(), m_State, m_ScanCount);
1772  return;
1773  }
1774 
1777  "Begin processing modifications on WDFCHILDLIST %p", GetObjectHandle());
1778 
1779  //
1780  // First do the mod updates. As quick as possible. Note that we need to
1781  // update
1782  //
1785  pCur = pNext) {
1786 
1787  pNext = pCur->Flink;
1788 
1790 
1791  switch (pEntry->m_ModificationState) {
1793 
1794 
1795 
1796 
1797 
1798 
1799 
1800 
1801 
1802 
1803 
1804 
1805 
1806 
1807 
1808  pEntry->m_ModificationState = ModificationRemove;
1809  break;
1810 
1811  default:
1812  break;
1813  }
1814  }
1815 
1816  invalidateRelations = FALSE;
1819 
1822 
1823  ASSERT(pEntry->m_ModificationState == ModificationInsert ||
1824  pEntry->m_ModificationState == ModificationClone ||
1825  pEntry->m_ModificationState == ModificationRemove);
1826 
1829  "entry %p, mod state is %!FxChildListModificationState!",
1830  pEntry, pEntry->m_ModificationState);
1831 
1832  switch (pEntry->m_ModificationState) {
1833  case ModificationRemove:
1834  //
1835  // Remove's are stacked on top of the entry they need to take out.
1836  //
1837  ASSERT(pEntry->IsPresent());
1838 
1839  pEntry->m_ModificationState = ModificationUnspecified;
1840 
1843  "processing remove on entry %p, description state is "
1844  "%!FxChildListDescriptionState!",
1845  pEntry, pEntry->m_DescriptionState);
1846 
1847  switch (pEntry->m_DescriptionState) {
1849  //
1850  // We got to the entry before a DO could be created for it or
1851  // an instantiation failed. If deleeted before creation, the
1852  // list entry points to itself. If the instantiation failed,
1853  // the list entry is in the description list and must be
1854  // removed from it.
1855  //
1856  // Mark it for deletion now (outside of the lock being held).
1857  //
1860  "entry %p never reported to pnp, mark for deletion", pEntry);
1861 
1862  RemoveEntryList(&pEntry->m_DescriptionLink);
1863  InsertTailList(FreeListHead, &pEntry->m_DescriptionLink);
1864  break;
1865 
1869  "committing PDO WDFDEVICE %p, !devobj %p as not present",
1870  pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject());
1871 
1872  pEntry->m_DescriptionState = DescriptionNotPresent;
1873  invalidateRelations = TRUE;
1874  break;
1875 
1876  default:
1877  ASSERTMSG("Invalid description state\n", FALSE);
1878  break;
1879  }
1880 
1881  break;
1882 
1883  case ModificationInsert:
1884  //
1885  // CurEntry is our entry to insert into the list. We simply "move"
1886  // the mod entries to desc entries.
1887  //
1888  ASSERT(pEntry->m_DescriptionState == DescriptionUnspecified);
1889  pEntry->m_DescriptionState = DescriptionPresentNeedsInstantiation;
1890 
1893  "marking entry %p as needing instantiation", pEntry);
1894 
1895  InsertTailList(&m_DescriptionListHead, &pEntry->m_DescriptionLink);
1896  pEntry->m_ModificationState = ModificationUnspecified;
1897  invalidateRelations = TRUE;
1898  break;
1899 
1900  case ModificationClone:
1901  invalidateRelations = CloneEntryLocked(FreeListHead, pEntry, FALSE);
1902  break;
1903 
1904  default:
1905  ASSERTMSG("Invalid description modification state\n", FALSE);
1906  break;
1907  }
1908  }
1909 
1910  if (invalidateRelations) {
1911  PDEVICE_OBJECT pdo;
1912 
1913  if (m_ScanCount) {
1915  }
1916  else if ((pdo = m_Device->GetSafePhysicalDevice()) != NULL) {
1917  //
1918  // See previous usage of m_Device->m_KnownPdo for
1919  // comments on why a lock is not necessary when reading its value.
1920  //
1923  }
1924  else {
1926  }
1927  }
1928 
1931  "end processing modifications on WDFCHILDLIST %p", GetObjectHandle());
1932 }
1933 
1934 VOID
1936  __inout FxDeviceDescriptionEntry* DescriptionEntry,
1937  __in BOOLEAN ModificationCanBeQueued
1938  )
1939 /*++
1940 
1941 Routine Description:
1942 
1943  This worker function marks the passed in mod or desc entry in the device
1944  list "not present". The change is enqueued in the mod list but the mod
1945  list is not drained.
1946 
1947 Arguments:
1948 
1949  DescriptionEntry - Entry to be marked as "not present".
1950 
1951  ModificationCanBeQueued - whether the caller allows for this description
1952  to be a modification already queued on the modification list
1953 
1954 Assumes:
1955  DescriptionEntry->IsPresent() == TRUE
1956 
1957 Return Value:
1958  None
1959 
1960 --*/
1961 {
1962  BOOLEAN queueMod;
1963 
1964  ASSERT(DescriptionEntry->IsPresent());
1965 
1966  queueMod = FALSE;
1967 
1968  if (ModificationCanBeQueued) {
1969  if (IsListEmpty(&DescriptionEntry->m_ModificationLink)) {
1970  queueMod = TRUE;
1971  }
1972  else {
1973  //
1974  // If the modification is queued, it must be removal
1975  //
1976  ASSERT(DescriptionEntry->m_ModificationState ==
1978  ASSERT(DescriptionEntry->m_FoundInLastScan == FALSE);
1979  }
1980  }
1981  else {
1982  queueMod = TRUE;
1983  }
1984 
1985  if (queueMod) {
1986  ASSERT(IsListEmpty(&DescriptionEntry->m_ModificationLink));
1987  ASSERT(DescriptionEntry->m_ModificationState == ModificationUnspecified);
1988 
1989  //
1990  // Add a removal modification entry into the modification list.
1991  // The ModificationRemoveNotify state will be converted into
1992  // ModificationRemove later while the list lock is still being held.
1993  //
1994  DescriptionEntry->m_ModificationState = ModificationRemoveNotify;
1995  DescriptionEntry->m_FoundInLastScan = FALSE;
1996 
1998  &DescriptionEntry->m_ModificationLink);
1999  }
2000 }
2001 
2002 VOID
2004  __inout PLIST_ENTRY FreeListHead,
2005  __inout FxDeviceDescriptionEntry* ModificationEntry
2006  )
2007 /*++
2008 
2009 Routine Description:
2010 
2011  This worker function marks the passed in mod or desc entry in the device
2012  list "not present". The change is enqueued in the mod list but the mod
2013  list is not drained.
2014 
2015 Arguments:
2016 
2017  FreeListHead - Free list of entries.
2018 
2019  ModificationEntry - Entry to be marked as "not present".
2020 
2021 Return Value:
2022  None
2023 
2024 --*/
2025 {
2026  switch (ModificationEntry->m_ModificationState) {
2027  case ModificationInsert:
2028  //
2029  // This one was never reported to the OS. Remove it now.
2030  //
2031  RemoveEntryList(&ModificationEntry->m_ModificationLink);
2032  InitializeListHead(&ModificationEntry->m_ModificationLink);
2033 
2034  if (IsStaticList()) {
2035  //
2036  // There is a corner case of a static PDO being added and
2037  // immediately marked as missing before it has a chance to move to
2038  // description list. This case is handled here by marking the
2039  // modification state to ModificationNeedsPnpRemoval. Fx cannot just
2040  // delete the description because there is a driver-created PDO
2041  // associated with the description and it needs to be cleaned up.
2042  //
2043  ModificationEntry->m_ModificationState = ModificationNeedsPnpRemoval;
2044  ASSERT(ModificationEntry->m_DescriptionState == DescriptionUnspecified);
2045  }
2046 
2047  ASSERT(IsListEmpty(&ModificationEntry->m_DescriptionLink));
2048  InsertTailList(FreeListHead, &ModificationEntry->m_DescriptionLink);
2049  break;
2050 
2051  case ModificationClone:
2052  //
2053  // In between the PDOs stack asking for a reenumeration and applying
2054  // this change, the bus driver has reported the child as missing.
2055  // Convert the clone modification to a removal modification.
2056  //
2057 
2058  //
2059  // MarkDescriptionNotPresentWorker expects that m_ModificationEntry is
2060  // not in any list and points to itself.
2061  //
2062  RemoveEntryList(&ModificationEntry->m_ModificationLink);
2063  InitializeListHead(&ModificationEntry->m_ModificationLink);
2064 
2065  MarkDescriptionNotPresentWorker(ModificationEntry, FALSE);
2066  break;
2067 
2068  default:
2069  DO_NOTHING();
2070  break;
2071  }
2072 }
2073 
2074 VOID
2076  __inout PLIST_ENTRY FreeListHead
2077  )
2078 {
2080  FxDevice* pPdo;
2081  PLIST_ENTRY pCur;
2082 
2083  while (!IsListEmpty(FreeListHead)) {
2084  pCur = RemoveHeadList(FreeListHead);
2086 
2088 
2089  //
2090  // If this is a static list and the entry has not yet been instantiated,
2091  // tell PnP to remove the device.
2092  //
2093  // There is a corner case of a static PDO being added and
2094  // immediately marked as missing before it has a chance to move to
2095  // description list. This case is handled here by checking the
2096  // modification state of ModificationNeedsPnpRemoval. Fx cannot just
2097  // delete the description because there is a driver-created PDO
2098  // associated with the description and it needs to be cleaned up.
2099  //
2100  if (m_StaticList &&
2101  (pEntry->m_DescriptionState == DescriptionPresentNeedsInstantiation ||
2102  pEntry->m_ModificationState == ModificationNeedsPnpRemoval )) {
2103 
2104  pPdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription,
2106  Header)->Pdo;
2107 
2108  //
2109  // The pnp removal path expects that there is no modifcation pending
2110  // when removing the description.
2111  //
2112  if (pEntry->m_ModificationState == ModificationNeedsPnpRemoval) {
2113  ASSERT(pEntry->m_DescriptionState == DescriptionUnspecified);
2114  ASSERT(IsListEmpty(&pEntry->m_ModificationLink));
2115 
2116  pEntry->m_ModificationState = ModificationUnspecified;
2117  }
2118 
2119  //
2120  // Change the state to reported missing (which is what we are basically
2121  // simulating here anyways) so that when we process the entry again
2122  // when the PDO really goes away we cleanup the entry.
2123  //
2124  // Also, when posting PnpEventRemove to the child, child will
2125  // call FxDeviceDescriptionEntry::IsDeviceRemoved which checks for
2126  // reported missing before reporting if the device has been removed
2127  // (and we want the device to be reported as removed).
2128  //
2129  pEntry->m_DescriptionState = DescriptionReportedMissing;
2130 
2131  //
2132  // Not yet reported to PnP, so it should be in the initial state
2133  //
2135 
2136  //
2137  // m_Description should be set when the FxPkgPdo was created
2138  //
2140 
2141  //
2142  // Since the pPdo->m_PkgPnp->m_DeviceRemoveProcessed == NULL, the
2143  // pnp state machine will delete the PDO. We are simulating the same
2144  // situation where an FDO is in the remove path and is telling each
2145  // of its removed PDOs to delete themselves.
2146  //
2148  }
2149  else {
2150  CleanupDescriptions(pEntry->m_IdentificationDescription,
2151  pEntry->m_AddressDescription);
2152 
2153  delete pEntry;
2154  }
2155  }
2156 }
2157 
2161  )
2162 {
2163  PLIST_ENTRY ple;
2165 
2168  ple = ple->Blink) {
2169 
2171 
2172  if (CompareId(pEntry->m_IdentificationDescription, Id)) {
2173  return pEntry;
2174  }
2175  }
2176 
2177  return NULL;
2178 }
2179 
2183  )
2184 {
2185  PLIST_ENTRY ple;
2187 
2190  ple = ple->Blink) {
2191 
2193 
2194  if (CompareId(pEntry->m_IdentificationDescription, Id)) {
2195  return pEntry;
2196  }
2197  }
2198 
2199  return NULL;
2200 }
2201 
2203 NTSTATUS
2206  )
2207 {
2208  if (Entry == &m_DescriptionListHead) {
2209  return STATUS_SUCCESS;
2210  }
2211  else {
2212  PLIST_ENTRY ple;
2213 
2216  ple = ple->Flink) {
2217  if (Entry == ple) {
2218  return STATUS_SUCCESS;
2219  }
2220  }
2221 
2222  return STATUS_INVALID_PARAMETER;
2223  }
2224 }
2225 
2227 NTSTATUS
2230  )
2231 {
2232  if (Entry == &m_ModificationListHead) {
2233  return STATUS_SUCCESS;
2234  }
2235  else {
2236  PLIST_ENTRY ple;
2237 
2240  ple = ple->Flink) {
2241  if (Entry == ple) {
2242  return STATUS_SUCCESS;
2243  }
2244  }
2245 
2246  return STATUS_INVALID_PARAMETER;
2247  }
2248 }
2249 
2250 BOOLEAN
2253  __inout PBOOLEAN InvalidateRelations
2254  )
2255 {
2257  NTSTATUS status;
2258  KIRQL irql;
2259 
2260  init.CreatedOnStack = TRUE;
2261  init.SetPdo(m_Device);
2262  init.Pdo.DescriptionEntry = Entry;
2263 
2264  if (m_StaticList) {
2265  init.CreatedDevice =
2266  CONTAINING_RECORD(Entry->m_IdentificationDescription,
2268  Header)->Pdo;
2269  }
2270  else {
2271  //
2272  // This description needs a device, create it now.
2273  //
2275  GetHandle(), Entry->m_IdentificationDescription, &init);
2276 
2277  if (status == STATUS_RETRY) {
2278  if (init.CreatedDevice != NULL) {
2279  //
2280  // Destroy any allocations assocated with the device.
2281  //
2282  init.CreatedDevice->Destroy();
2283  }
2284 
2285  *InvalidateRelations = TRUE;
2286 
2287  return FALSE;
2288  }
2289 
2290  if (NT_SUCCESS(status)) {
2291  //
2292  // Make sure that a framework device was actually created
2293  //
2294  if (init.CreatedDevice == NULL) {
2295  //
2296  // Driver didn't actually create the device, even though its
2297  // EvtChildListCreateDevice returned a successful return code.
2298  // Change the status to indicate an error, so that we enter the
2299  // error handling code below.
2300  //
2303  "EvtChildListCreateDevice returned a successful status "
2304  "%!STATUS! but did not create a device object", status);
2305 
2307 
2309  }
2310  }
2311 
2312  if (!NT_SUCCESS(status)) {
2313  if (init.CreatedDevice != NULL) {
2315  //
2316  // Set to missing so that when the pnp machine evaluates whether the
2317  // PDO has been reported missing or not, it chooses missing and
2318  // deletes the PDO immediately.
2319  //
2320  Entry->m_DescriptionState = DescriptionReportedMissing;
2321 
2322  if (Entry->m_ModificationState != ModificationUnspecified) {
2323  //
2324  // Cannot be ModificationInsert since this device ID is already
2325  // in the list.
2326  //
2327  // Cannot be ModificationClone since the FDO for this device
2328  // is the only one who can ask for that and since PDO creation
2329  // failed, there is no FDO.
2330  //
2331  // Cannot be ModificationRemove because the list is locked
2332  // against changes and ModificationRemoveNotify becomes
2333  // ModificationRemove only after the list has been unlocked.
2334  //
2335  ASSERT(Entry->m_ModificationState == ModificationRemoveNotify);
2336 
2337  //
2338  // Remove the modification from the list. The call to
2339  // DeleteDeviceFromFailedCreate below will destroy this
2340  // Entry due to the pnp state machine deleting the PDO.
2341  //
2342  RemoveEntryList(&Entry->m_ModificationLink);
2343  }
2345 
2346  ASSERT(init.CreatedDevice->IsPnp());
2347  ASSERT(init.CreatedDevice->GetDevicePnpState() == WdfDevStatePnpInit);
2348  ASSERT(init.CreatedDevice->GetPdoPkg()->m_Description != NULL);
2349 
2350  ASSERT(Entry->m_Pdo == NULL);
2351 
2354  "WDFDEVICE %p !devobj %p created, but EvtChildListCreateDevice "
2355  "returned status %!STATUS!", init.CreatedDevice->GetHandle(),
2356  init.CreatedDevice->GetDeviceObject(), status);
2357 
2358  //
2359  // Simulate a remove event coming to the device. After this call
2360  // returns, init.CreatedDevice is no longer a valid pointer!
2361  //
2362  // Please note that DeleteDeviceFromFailedCreate just returns
2363  // the passed status back unless device is a filter, in which
2364  // case it changes it to success.
2365  //
2366  // It is not really the status of DeleteDeviceFromFailedCreate
2367  // operation, which is why we don't check it.
2368  //
2369  (void) init.CreatedDevice->DeleteDeviceFromFailedCreate(
2370  status,
2371  TRUE);
2372 
2373  init.CreatedDevice = NULL;
2374  }
2375  else {
2376  LIST_ENTRY freeHead;
2377 
2378  InitializeListHead(&freeHead);
2379 
2380  //
2381  // Add a modification that this entry is now gone. If there is
2382  // an active scan and it has added this device, there would
2383  // be no entry in the modification case list because the add
2384  // would have updated the description entry.
2385  //
2388  ProcessModificationsLocked(&freeHead);
2390 
2391  //
2392  // Free structures outside of any internal WDF lock
2393  //
2394  DrainFreeListHead(&freeHead);
2395  }
2396 
2397  return FALSE;
2398  }
2399  }
2400 
2401  //
2402  // Assign m_Pdo here once we have a fully baked and created device. We only
2403  // assign m_Pdo after we have completely initalized device because we check
2404  // for m_Pdo in PostParentToD0.
2405  //
2406  Entry->m_Pdo = init.CreatedDevice;
2407  Entry->m_DescriptionState = DescriptionInstantiatedHasObject;
2408 
2409  return TRUE;
2410 }
2411 
2413 NTSTATUS
2415  __inout PDEVICE_RELATIONS *DeviceRelations
2416  )
2417 {
2418  LIST_ENTRY freeHead;
2419  PLIST_ENTRY ple, pNext;
2421  PDEVICE_RELATIONS pPriorRelations, pNewRelations;
2423  BOOLEAN needToReportMissingChildren, invalidateRelations, cleanupRelations;
2424  ULONG additionalCount, totalCount, i;
2425  size_t size;
2426  NTSTATUS status;
2427  KIRQL irql;
2429 
2431 
2432  pNewRelations = NULL;
2433  invalidateRelations = FALSE;
2434  cleanupRelations = TRUE;
2435  InitializeListHead(&freeHead);
2437 
2438  //
2439  // Get the count of DO's we will need to add. While we're at it, free any
2440  // extensions that never got a chance for a DO, and note extensions that
2441  // will need to wait for a remove IRP.
2442  //
2444 
2446 
2447  additionalCount = 0;
2448  needToReportMissingChildren = FALSE;
2449 
2452  ple = ple->Flink) {
2453 
2455 
2456  switch (pEntry->m_DescriptionState) {
2457 
2460  //
2461  // We'll be needing a DO here.
2462  //
2463  additionalCount++;
2464  break;
2465 
2466  case DescriptionNotPresent:
2467  //
2468  // We will now report the description as missing
2469  //
2472  "PDO WDFDEVICE %p !devobj %p in a not present state, need to "
2473  "report as missing",
2474  pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject());
2475 
2476  needToReportMissingChildren = TRUE;
2477  break;
2478 
2480  //
2481  // Already reported missing in a previous handling of QDR
2482  //
2483  break;
2484 
2485  default:
2486  ASSERTMSG("Invalid description state\n", FALSE);
2487  break;
2488  }
2489  }
2490 
2492 
2493  pPriorRelations = *DeviceRelations;
2494 
2495  //
2496  // If we have
2497  // 1) no devices in the list AND
2498  // a) we have nothing to report OR
2499  // b) we have something to report and there are previous relations (which
2500  // if left unchanged will be used to report our missing devices)
2501  //
2502  // THEN nothing else to do except marking the NotPresent children as
2503  // missing, unlock the list and return the special return
2504  // code STATUS_NOT_SUPPORTED indicating this condition.
2505  //
2506  if (additionalCount == 0 &&
2507  (needToReportMissingChildren == FALSE || pPriorRelations != NULL)) {
2508  //
2509  // We have nothing to add, nor subtract from prior allocations. Note
2510  // the careful logic with counting missing children - the OS does not
2511  // treat no list and an empty list identically. As such we must be
2512  // sure to return some kind of list in the case where we reported
2513  // something previously.
2514  //
2515  // Mark the NotPresent children as Missing
2516  // We can walk the ChildList without holding the spinlock because we set
2517  // m_State to ListLockedForEnum.
2518  //
2519  if (needToReportMissingChildren) {
2522  ple = pNext) {
2523  pNext = ple->Flink;
2524 
2526 
2527  if (pEntry->m_DescriptionState == DescriptionNotPresent) {
2528  //
2529  // We will now report the description as missing
2530  //
2533  "PDO WDFDEVICE %p !devobj %p reported as missing to pnp",
2534  pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject());
2535 
2536  pEntry->m_DescriptionState = DescriptionReportedMissing;
2537  pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked;
2538  }
2539  }
2540  }
2541  else {
2544  "Nothing to report on WDFCHILDLIST %p, returning early", GetHandle());
2545  }
2546 
2547  cleanupRelations = FALSE;
2549  goto Done;
2550  }
2551 
2552  //
2553  // Adjust the count for any existing relations.
2554  //
2555  totalCount = additionalCount;
2556  if (pPriorRelations != NULL) {
2557  totalCount += pPriorRelations->Count;
2558  }
2559 
2560  size = _ComputeRelationsSize(totalCount);
2561 
2562  pNewRelations = (PDEVICE_RELATIONS)
2564 
2565  if (pNewRelations == NULL) {
2566  //
2567  // We can't add our information.
2568  //
2570  "Could not allocate relations for %d devices",
2571  totalCount);
2572 
2573  //
2574  // Just like above, STATUS_NOT_SUPPORTED is a special value indicating
2575  // to the caller that the QDR has not been handled and that the caller
2576  // should not change the status or the existing relations in the irp.
2577  //
2578  cleanupRelations = FALSE;
2580 
2581  m_EnumRetries++;
2583  invalidateRelations = TRUE;
2584  }
2585  else {
2586  if (needToReportMissingChildren) {
2589  "WDFCHILDLIST %p could not allocate relations required for "
2590  "reporting children as missing after max retries",
2591  GetHandle());
2592  }
2593 
2596  "WDFCHILDLIST %p retried %d times to report relations, but "
2597  "failed each time", GetHandle(), FX_CHILD_LIST_MAX_RETRIES);
2598  }
2599 
2600  if (pPriorRelations == NULL) {
2601  //
2602  // If the prior relations are NULL we can just return failure and
2603  // not affect anyone else's state that had previous thought they
2604  // committed a relations structure back to pnp (which we tried to
2605  // update but could not b/c of no memory).
2606  //
2607  // By returning failure that is != STATUS_NOT_SUPPORTED, the pnp
2608  // manager will not process a change in the relations.
2609  //
2611  }
2612  else {
2613  //
2614  // Do *not* throw away the old list and return error because that
2615  // will put the driver which created the existing relations into an
2616  // inconsistent state with respect to the pnp manager state if we
2617  // fail it here and the pnp manager never seeds the changes.
2618  //
2619  // Instead, we must process the failure locally and mark each object
2620  // which is already reported as present as missing.
2621  //
2624  ple = pNext) {
2625 
2626  pNext = ple->Flink;
2628 
2629  switch (pEntry->m_DescriptionState) {
2631  //
2632  // This description can stay in this state b/c we will just
2633  // ask for another QDR.
2634  //
2635  break;
2636 
2640  "PDO WDFDEVICE %p !devobj %p being marked as missing "
2641  "because of failure to allocate device relations and "
2642  "an already existing relations %p",
2643  pEntry->m_Pdo->GetHandle(),
2644  pEntry->m_Pdo->GetDeviceObject(), pPriorRelations);
2645 
2647  if (m_StaticList == FALSE) {
2652  "PDO WDFDEVICE %p !devobj %p being cloned "
2653  "because of the failure to allocate device "
2654  "relations",
2655  pEntry->m_Pdo->GetHandle(),
2656  pEntry->m_Pdo->GetDeviceObject());
2657 
2658  (void) CloneEntryLocked(&freeHead, pEntry, TRUE);
2659  }
2660  }
2661  else {
2665  "PDO WDFDEVICE %p !devobj %p is a statically "
2666  "enumerated PDO therefore can not be cloned and is "
2667  "being marked missing because of failure to "
2668  "allocate device relations. It will be surprise "
2669  "removed by pnp manager. Bus driver may continue "
2670  "to function normally but will lose this child PDO",
2671  pEntry->m_Pdo->GetHandle(),
2672  pEntry->m_Pdo->GetDeviceObject());
2673  }
2674  pEntry->m_DescriptionState = DescriptionReportedMissing;
2675  pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked;
2677  break;
2678 
2679  case DescriptionNotPresent:
2680  //
2681  // We will now report the description as missing
2682  //
2685  "PDO WDFDEVICE %p !devobj %p reported as missing to pnp "
2686  "(by using existing relations)",
2687  pEntry->m_Pdo->GetHandle(),
2688  pEntry->m_Pdo->GetDeviceObject());
2689 
2690  pEntry->m_DescriptionState = DescriptionReportedMissing;
2691  pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked;
2692  break;
2693  }
2694  }
2695  }
2696 
2697  goto Done;
2698  }
2699 
2700  RtlZeroMemory(pNewRelations, size);
2701 
2702  if (pPriorRelations != NULL && pPriorRelations->Count > 0) {
2705  "WDFCHILDLIST %p prior relations %p contained %d objects",
2706  GetHandle(), pPriorRelations, pPriorRelations->Count
2707  );
2708 
2709  RtlCopyMemory(pNewRelations,
2710  pPriorRelations,
2711  _ComputeRelationsSize(pPriorRelations->Count));
2712  }
2713 
2714  //
2715  // We can walk the ChildList without holding the spinlock because we set
2716  // m_State to ListLockedForEnum.
2717  //
2719 
2722  ple = pNext) {
2723  pNext = ple->Flink;
2724 
2726 
2727  switch (pEntry->m_DescriptionState) {
2729  //
2730  // This extension needs a device handle. Create one now.
2731  //
2733  "Creating PDO device object from reported device");
2734  if (CreateDevice(pEntry, &invalidateRelations) == FALSE) {
2735  break;
2736  }
2737 
2740  "PDO created successfully, WDFDEVICE %p !devobj %p",
2741  pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject());
2742 
2743  // || || Fall through || ||
2744  // \/ \/ \/ \/
2746 
2748  "Reporting PDO WDFDEVICE %p !devobj %p",
2749  pEntry->m_Pdo->GetHandle(),
2750  pEntry->m_Pdo->GetDeviceObject());
2751 
2752  pDevice = pEntry->m_Pdo->GetDeviceObject();
2754  pNewRelations->Objects[pNewRelations->Count] = pDevice;
2755  pNewRelations->Count++;
2756  break;
2757 
2758  case DescriptionNotPresent:
2759  //
2760  // We will now report the description as missing
2761  //
2764  "PDO WDFDEVICE %p !devobj %p reported as missing to pnp",
2765  pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject());
2766 
2767  pEntry->m_DescriptionState = DescriptionReportedMissing;
2768  pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked;
2769 
2770  break;
2771 
2773  break;
2774 
2775  default:
2776  ASSERTMSG("Invalid description state\n", FALSE);
2777  break;
2778  }
2779  }
2780 
2781 Done:
2783 
2784  //
2785  // Make sure that the description we just dequeued is not on the modification
2786  // list.
2787  //
2789  ProcessModificationsLocked(&freeHead);
2790 
2791  if (NT_SUCCESS(status)) {
2792  m_EnumRetries = 0;
2793  }
2794 
2796 
2797  if (invalidateRelations) {
2798  //
2799  // We failed for some reason or other. Queue up a new attempt.
2800  //
2801  // NOTE: no need to check m_Device->m_KnownPdo here
2802  // because we are in the middle of a QDR for m_Device which means
2803  // that it, or its stack, is already known to PnP.
2804  //
2806  }
2807 
2808  DrainFreeListHead(&freeHead);
2809 
2810  if (cleanupRelations) {
2811  if (pPriorRelations != NULL) {
2814  "Freeing prior relations %p", pPriorRelations);
2815 
2816  ExFreePool(pPriorRelations);
2817  pPriorRelations = NULL;
2818  }
2819 
2820  if (!NT_SUCCESS(status) && pNewRelations != NULL) {
2821  for(i = 0; i < pNewRelations->Count; i++) {
2822  ObDereferenceObject(pNewRelations->Objects[i]);
2823  }
2824 
2825  ExFreePool(pNewRelations);
2826  pNewRelations = NULL;
2827  }
2828 
2829  *DeviceRelations = pNewRelations;
2830  }
2831 
2832  return status;
2833 }
2834 
2835 VOID
2837  VOID
2838  )
2839 {
2840  PLIST_ENTRY ple, pNext;
2841  KIRQL irql;
2843  LIST_ENTRY freeHead;
2844 
2845  InitializeListHead(&freeHead);
2846 
2847  //
2848  // Prevent modification list processing so that we can walk the
2849  // description list safely.
2850  //
2854 
2855  //
2856  // Invoke the ReportedMissing callback if present for children reported
2857  // missing.
2858  //
2861  ple = pNext) {
2862  pNext = ple->Flink;
2863 
2865 
2866  if (pEntry->m_ReportedMissingCallbackState == CallbackNeedsToBeInvoked) {
2867  (pEntry->m_Pdo->GetPdoPkg())->m_DeviceReportedMissing.Invoke(
2868  pEntry->m_Pdo->GetHandle());
2869 
2870  pEntry->m_ReportedMissingCallbackState = CallbackInvoked;
2871  }
2872  }
2873 
2876  ProcessModificationsLocked(&freeHead);
2878 
2879  DrainFreeListHead(&freeHead);
2880 }
2881 
2882 VOID
2884  VOID
2885  )
2886 {
2888  PLIST_ENTRY ple;
2889  KIRQL irql;
2890 
2894  ple = ple->Flink) {
2895 
2897 
2898  if (pEntry->m_PendingDeleteOnScanEnd) {
2899  COVERAGE_TRAP();
2900  continue;
2901  }
2902 
2903  if (pEntry->m_Pdo != NULL) {
2904  pEntry->m_Pdo->m_PkgPnp->PowerProcessEvent(PowerParentToD0);
2905  }
2906  }
2908 }
2909 
2910 VOID
2913  )
2914 /*++
2915 
2916 Routine Description:
2917  Propagates the wait wake status to all the child PDOs. This will cause any
2918  pended wait wake requests to be completed with the given wait wake status.
2919 
2920 Arguments:
2921  WaitWakeStatus - The NTSTATUS value to use for compeleting any pended wait
2922  wake requests on the child PDOs.
2923 
2924 Return Value:
2925  None
2926 
2927  --*/
2928 {
2930  PLIST_ENTRY ple;
2931  KIRQL irql;
2932 
2936  ple = ple->Flink) {
2937 
2939 
2940  if (pEntry->m_PendingDeleteOnScanEnd) {
2941  COVERAGE_TRAP();
2942  continue;
2943  }
2944 
2945  if (pEntry->m_Pdo != NULL) {
2946  ASSERT(pEntry->m_Pdo->m_PkgPnp->m_SharedPower.m_WaitWakeOwner == TRUE);
2947  pEntry->m_Pdo->m_PkgPnp->PowerIndicateWaitWakeStatus(WaitWakeStatus);
2948  }
2949  }
2951 }
2952 
2953 VOID
2955  VOID
2956  )
2957 /*++
2958 
2959 Routine Description:
2960  Notification through IFxStateChangeNotification that the parent device is
2961  being surprise removed
2962 
2963 Arguments:
2964  None
2965 
2966 Return Value:
2967  None
2968 
2969  --*/
2970 {
2971  PLIST_ENTRY pCur, pNext;
2972  LIST_ENTRY freeHead;
2974  KIRQL irql;
2975 
2976  InitializeListHead(&freeHead);
2977 
2979 
2981 
2982  //
2983  // Walk over all mod entries and remove any pending inserts. Note that
2984  // MarkModificationNotPresentWorker will add any such INSERTs found in the
2985  // mod list to the free list.
2986  //
2989  pCur = pNext) {
2990 
2991  pNext = pCur->Flink;
2992 
2994 
2995  if (pEntry->m_ModificationState == ModificationInsert) {
2997  }
2998  }
2999 
3000  //
3001  // Walk over all desc entries and remove them. Since
3002  // MarkDescriptionNotPresentWorker doesn't drain the mods,
3003  // we don't have to worry about any entries disappearing.
3004  //
3007  pCur = pCur->Flink) {
3008 
3010 
3011  if (pEntry->IsPresent()) {
3013  }
3014  }
3015 
3016  //
3017  // Attempt to drain any mods we made.
3018  //
3019  ProcessModificationsLocked(&freeHead);
3020 
3021  //
3022  // Walk over all desc entries and advance them to missing.
3023  //
3026  pCur = pCur->Flink) {
3027 
3029 
3030  if (pEntry->m_DescriptionState == DescriptionNotPresent) {
3031  pEntry->m_DescriptionState = DescriptionReportedMissing;
3032  }
3033  }
3034 
3036 
3037  DrainFreeListHead(&freeHead);
3038 }
3039 
3040 VOID
3042  __inout PLONG ChildCount
3043  )
3044 /*++
3045 
3046 Routine Description:
3047  Notification through IFxStateChangeNotification that the parent device is
3048  being removed.
3049 
3050 Arguments:
3051  None
3052 
3053 Return Value:
3054  None
3055 
3056  --*/
3057 {
3058  PLIST_ENTRY pCur;
3059  LIST_ENTRY freeHead;
3061  KIRQL irql;
3062 
3064  "WDFCHILDLIST %p: removing children", GetHandle());
3065 
3066  InitializeListHead(&freeHead);
3067  pEntry = NULL;
3068 
3070 
3071  //
3072  // Surprise remove handling covers the first stage of processing. This will
3073  // process the modification list, esp the insert modifications which will
3074  // be cleaned up.
3075  //
3077 
3079 
3080  ProcessModificationsLocked(&freeHead);
3081 
3083 
3084  for ( ; ; ) {
3085 
3086  //
3087  // Find the first child which was not surprise removed. If surprise
3088  // removed and not yet removed, then there is an outstanding handle
3089  // which has not yet been closed.
3090  //
3093  pCur = pCur->Flink) {
3094 
3096 
3097  ASSERT(pEntry->m_DescriptionState == DescriptionReportedMissing);
3098 
3099  if (pEntry->m_ProcessingSurpriseRemove == FALSE) {
3100  break;
3101  }
3102  }
3103 
3104  //
3105  // If we are at the end of the list, we are done
3106  //
3107  if (pCur == &m_DescriptionListHead) {
3108  break;
3109  }
3110 
3112  "Removing entry %p, WDFDEVICE %p, PDO %p",
3113  pEntry, pEntry->m_Pdo->GetHandle(),
3114  pEntry->m_Pdo->GetPhysicalDevice());
3115 
3116  ASSERT(pEntry->m_ModificationState == ModificationUnspecified);
3117  RemoveEntryList(&pEntry->m_DescriptionLink);
3118  InitializeListHead(&pEntry->m_DescriptionLink);
3119 
3121 
3122  //
3123  // Go through FxPkgPdo to handle cleanup. CleanupOrphanedDevice will
3124  // free this entry.
3125  //
3126  ASSERT(pEntry->m_Pdo != NULL);
3127  ASSERT(pEntry->m_PendingDeleteOnScanEnd == FALSE);
3128 
3129  pEntry->m_Pdo->SetParentWaitingOnRemoval();
3130  InterlockedIncrement(ChildCount);
3131 
3132  //
3133  // Start the child going away
3134  //
3135  pEntry->m_Pdo->m_PkgPnp->PnpProcessEvent(PnpEventParentRemoved);
3136 
3138  }
3139 
3141  ProcessModificationsLocked(&freeHead);
3142 
3144 
3145  DrainFreeListHead(&freeHead);
3146 }
3147 
3149 NTSTATUS
3151  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
3153  __in size_t* TotalDescriptionSize
3154  )
3155 {
3156  NTSTATUS status;
3157 
3158  if (Config == NULL) {
3161  "Invalid Config, NULL is not allowed, %!STATUS!", status);
3162  return status;
3163  }
3164 
3165  if (Config->Size != sizeof(WDF_CHILD_LIST_CONFIG)) {
3168  "Config->Size incorrect, expected %d, got %d, %!STATUS!",
3169  sizeof(WDF_CHILD_LIST_CONFIG), Config->Size, status);
3170  return status;
3171  }
3172  if (Config->IdentificationDescriptionSize == 0) {
3175  "Config->IdentificationDescriptionSize must be non zero, "
3176  "%!STATUS!", status);
3177  return status;
3178  }
3179  if (Config->EvtChildListCreateDevice == NULL) {
3182  "Config->EvtChildListCreateDevice, NULL is not allowed, "
3183  "%!STATUS!", status);
3184  return status;
3185  }
3186 
3187  return _ComputeTotalDescriptionSize(FxDriverGlobals,
3188  Config,
3189  TotalDescriptionSize);
3190 }
3191 
3193 NTSTATUS
3195  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
3197  __in size_t* TotalDescriptionSize
3198  )
3199 {
3200  size_t addressAligned, idAligned;
3201  NTSTATUS status;
3202 
3203  *TotalDescriptionSize = 0;
3204 
3205  //
3206  // FxDeviceDescriptionEntry::operator new() will allocate a block of memory
3207  // that is
3208  // size =
3209  // WDF_ALIGN_SIZE_UP(sizeof(FxDeviceDescriptionEntry), sizeof(PVOID)) +
3210  // WDF_ALIGN_SIZE_UP(AddressDescriptionSize, sizeof(PVOID)) +
3211  // WDF_ALIGN_SIZE_UP(IdentificationDescriptionSize, sizeof(PVOID));
3212  //
3213  // Validate the size now beforehand, not every we allocate
3214  //
3215  //
3216  // Test for overflow
3217  //
3218  idAligned = WDF_ALIGN_SIZE_UP(Config->IdentificationDescriptionSize,
3219  sizeof(PVOID));
3220  if (idAligned < Config->IdentificationDescriptionSize) {
3223  "Config->IdentificationDescriptionSize %d too large"
3224  "%!STATUS!", Config->IdentificationDescriptionSize,
3225  status);
3226  return status;
3227  }
3228 
3229  addressAligned = WDF_ALIGN_SIZE_UP(Config->AddressDescriptionSize,
3230  sizeof(PVOID));
3231  if (addressAligned < Config->AddressDescriptionSize) {
3234  "Config->AddressDescriptionSize %d too large, %!STATUS!",
3235  Config->AddressDescriptionSize, status);
3236  return status;
3237  }
3238 
3239  status = RtlSizeTAdd(
3241  idAligned,
3242  TotalDescriptionSize
3243  );
3244  if (!NT_SUCCESS(status)) {
3246  FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
3247  "Could not add ID description size to block size, %!STATUS!",
3248  status);
3249  return status;
3250  }
3251 
3252  status = RtlSizeTAdd(*TotalDescriptionSize,
3253  addressAligned,
3254  TotalDescriptionSize);
3255  if (!NT_SUCCESS(status)) {
3257  FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
3258  "Could not add address description size to block size, %!STATUS!",
3259  status);
3260  return status;
3261  }
3262 
3263  return STATUS_SUCCESS;
3264 }
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
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:2163
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
if(dx==0 &&dy==0)
Definition: linetemp.h:174
#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:44
VOID CancelScan(__in BOOLEAN EndTheScan, __inout_opt PULONG ScanTag)
#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
#define _Must_inspect_result_
Definition: ms_sal.h:558
_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:2342
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