ReactOS 0.4.16-dev-336-gb667d82
fxpkgpnp.cpp
Go to the documentation of this file.
1/*++
2
3
4Copyright (c) Microsoft. All rights reserved.
5
6Module Name:
7
8 FxPkgPnp.cpp
9
10Abstract:
11
12 This module implements the pnp IRP handlers for the driver framework.
13
14Author:
15
16
17
18Environment:
19
20 Both kernel and user mode
21
22Revision History:
23
24
25
26
27
28--*/
29
30#include "pnppriv.hpp"
31
32#include <initguid.h>
33#include <wdmguid.h>
34
35extern "C" {
36
37#if defined(EVENT_TRACING)
38#include "FxPkgPnp.tmh"
39#endif
40
41}
42
43/* dc7a8e51-49b3-4a3a-9e81-625205e7d729 */
45 0xdc7a8e51, 0x49b3, 0x4a3a, { 0x9e, 0x81, 0x62, 0x52, 0x05, 0xe7, 0xd7, 0x29 }
46};
47
49 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
52 ) :
53 FxPackage(FxDriverGlobals, Device, Type)
54{
55 ULONG i;
56
60
61 //
62 // Initialize the structures to the default state and then override the
63 // non WDF std default values to the unsupported / off values.
64 //
72
82 ;
83
86
95 ;
96
99
103
105 for (i = 0; i < PowerSystemMaximum; i++) {
107 }
108
112
123
128
129 //
130 // We only set the pending child count to 1 once we know we have successfully
131 // created an FxDevice and initialized it fully. If we delete an FxDevice
132 // which is half baked, it cannot have any FxChildLists which have any
133 // pending children on them.
134 //
136
138
141
142 m_Failed = FALSE;
144
148
153
157
159
161
164
172
176
178
179#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
180 //
181 // Interrupt APIs for Vista and forward
182 //
185
186 //
187 // Interrupt APIs for Windows 8 and forward
188 //
191
192#endif
193
195
197}
198
200{
202
204
205 //
206 // We should either have zero pending children or we never made it out of
207 // the init state during a failed WDFDEVICE create or failed EvtDriverDeviceAdd
208 //
211
212
214 while (ple != NULL) {
216
218
219 //
220 // Advance to the next before deleting the current
221 //
222 ple = ple->Next;
223
224 //
225 // No longer in the list
226 //
227 pDI->m_Entry.Next = NULL;
228
229 delete pDI;
230 }
232
233 if (m_DmaEnablerList != NULL) {
234 delete m_DmaEnablerList;
236 }
237
238 if (m_RemovalDeviceList != NULL) {
239 delete m_RemovalDeviceList;
241 }
242
246 }
247
248 if (m_PnpStateCallbacks != NULL) {
249 delete m_PnpStateCallbacks;
250 }
251
254 }
255
258 }
259
263 }
264
265 if (m_EnumInfo != NULL) {
266 delete m_EnumInfo;
268 }
269
270 if (m_Resources != NULL) {
271 m_Resources->RELEASE(this);
273 }
274
275 if (m_ResourcesRaw != NULL) {
276 m_ResourcesRaw->RELEASE(this);
278 }
279
281}
282
285 VOID
286 )
287{
289
290 //
291 // All of the interrupts were freed during this object's dispose path. This
292 // is because all of the interrupts were attached as children to this object.
293 //
294 // It is safe to just reinitialize the list head.
295 //
297
299
300 //
301 // A derived class can insert an embedded FxQueryInterface into the QI list,
302 // so clear out the list before the destructor chain runs. (The derived
303 // class will be destructed first, as such, the embedded FxQueryInterface
304 // will also destruct first and complain it is still in a list.
305 //
307
308 //
309 // Clear out the head while holding the lock so that we synchronize against
310 // processing a QI while deleting the list.
311 //
313
315
316 while (ple != NULL) {
317 FxQueryInterface* pQI;
318
320
321 //
322 // Advance before we potentiall free the structure
323 //
324 ple = ple->Next;
325
326 //
327 // FxQueryInterface's destructor requires Next be NULL
328 //
329 pQI->m_Entry.Next = NULL;
330
331 if (pQI->m_EmbeddedInterface == FALSE) {
332 delete pQI;
333 }
334 }
335
336#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
338#endif
339
340 //
341 // Call up the hierarchy
342 //
343 return FxPackage::Dispose(); // __super call
344}
345
346
351 )
352
353/*++
354
355Routine Description:
356
357 This function initializes state associated with an instance of FxPkgPnp.
358 This differs from the constructor because it can do operations which
359 will fail, and can return failure. (Constructors can't fail, they can
360 only throw exceptions, which we can't deal with in this kernel mode
361 environment.)
362
363Arguments:
364
365 DeviceInit - Struct that the driver initialized that contains defaults.
366
367Returns:
368
369 NTSTATUS
370
371--*/
372
373{
376
378
379 m_ReleaseHardwareAfterDescendantsOnFailure = (DeviceInit->ReleaseHardwareOrderOnFailure ==
381
383 if (!NT_SUCCESS(status)) {
386 "Could not initialize QueryInterfaceLock for "
387 "WDFDEVICE %p, %!STATUS!",
389 return status;
390 }
391
393 if (!NT_SUCCESS(status)) {
396 "Could not initialize DeviceInterfaceLock for "
397 "WDFDEVICE %p, %!STATUS!",
399 return status;
400 }
401
402 //
403 // Initialize preallocated events for UM
404 // (For KM, events allocated on stack are used since event initialization
405 // doesn't fail in KM)
406 //
407#if (FX_CORE_MODE==FX_CORE_USER_MODE)
408
410 if (!NT_SUCCESS(status)) {
413 "Could not initialize cleanup event for "
414 "WDFDEVICE %p, %!STATUS!",
416 return status;
417 }
418
420 if (!NT_SUCCESS(status)) {
423 "Could not initialize remove event for "
424 "WDFDEVICE %p, %!STATUS!",
426 return status;
427 }
428#endif
429
430 if (DeviceInit->IsPwrPolOwner()) {
433
436 }
437
439 if (!NT_SUCCESS(status)) {
440 return status;
441 }
442
443#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
445#endif
446 }
447
448 //
449 // we will change the access flags on the object later on when we build up
450 // the list from the wdm resources
451 //
454 m_Device,
457 if (!NT_SUCCESS(status)) {
458 return status;
459 }
460
463 m_Device);
464
465 //
466 // This should never fail
467 //
469 if (!NT_SUCCESS(status)) {
472 return status;
473 }
474
475 m_Resources->ADDREF(this);
476
477 //
478 // we will change the access flags on the object later on when we build up
479 // the list from the wdm resources
480 //
483 m_Device,
486 if (!NT_SUCCESS(status)) {
487 return status;
488 }
489
492 m_Device);
493
494 //
495 // This should never fail
496 //
498 if (!NT_SUCCESS(status)) {
501 return status;
502 }
503
504 m_ResourcesRaw->ADDREF(this);
505
506 status = RegisterCallbacks(&DeviceInit->PnpPower.PnpPowerEventCallbacks);
507 if (!NT_SUCCESS(status)) {
508 return status;
509 }
510
511 if (IsPowerPolicyOwner()) {
512 RegisterPowerPolicyCallbacks(&DeviceInit->PnpPower.PolicyEventCallbacks);
513 }
514
515 return status;
516}
517
522 )
523
524/*++
525
526Routine Description:
527
528 This is the main dispatch handler for the pnp package. This method is
529 called by the framework manager when a PNP or Power IRP enters the driver.
530 This function will dispatch the IRP to a function designed to handle the
531 specific IRP.
532
533Arguments:
534
535 Device - a pointer to the FxDevice
536
537 Irp - a pointer to the FxIrp
538
539Returns:
540
541 NTSTATUS
542
543--*/
544
545{
547 FxIrp irp(Irp);
548
549#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
551#endif
552
554
555 switch (irp.GetMinorFunction()) {
564 case IRP_MN_EJECT:
568 "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! IRP 0x%p",
572 break;
573
577 "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! "
578 "type %!DEVICE_RELATION_TYPE! IRP 0x%p",
583 break;
584
585 default:
588 "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! IRP 0x%p",
592 break;
593 }
594
596 status = (*GetDispatchPnp()[irp.GetMinorFunction()])(this, &irp);
597 }
598 else {
599 //
600 // For Pnp IRPs we don't understand, just forget about them
601 //
603 }
604 }
605 else {
606 //
607 // If this isn't a PnP Irp, it must be a power irp.
608 //
609 switch (irp.GetMinorFunction()) {
610 case IRP_MN_WAIT_WAKE:
611 case IRP_MN_SET_POWER:
615 "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! "
616 "IRP 0x%p for %!SYSTEM_POWER_STATE! (S%d)",
622 }
623 else {
626 "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! "
627 "IRP 0x%p for %!DEVICE_POWER_STATE!",
632 }
633 break;
634
635 default:
638 "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! IRP 0x%p",
642 break;
643 }
644
646
649 }
650 else {
651 //
652 // For Power IRPs we don't understand, just forget about them
653 //
655 }
656 }
657
658 return status;
659}
660
663 __in PNP_DEVICE_STATE PnpDeviceState
664 )
665
666/*++
667
668Routine Description:
669
670 This function handled IRP_MN_QUERY_DEVICE_STATE. Most of the bits are
671 just copied from internal Framework state.
672
673Arguments:
674
675 PnpDeviceState - Bitfield that will be returned to the sender of the IRP.
676
677Returns:
678
679 NTSTATUS
680
681--*/
682
683{
684 LONG state;
685
687
688 //
689 // Return device state set by driver.
690 //
691 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
693 state,
694 Disabled);
695 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
697 state,
698 DontDisplayInUI);
699 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
701 state,
702 Failed);
703 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
705 state,
706 NotDisableable);
707 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
709 state,
710 Removed);
711 SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
713 state,
714 ResourcesChanged);
715
717 LONG caps;
718
719 //
720 // Mask off all caps except for NoDispalyInUI
721 //
723
724 //
725 // If the driver didn't specify pnp state, see if they specified no
726 // display as a capability. For raw PDOs and just usability, it is not
727 // always clear to the driver writer that they must set both the pnp cap
728 // and the pnp state for the no display in UI property to stick after
729 // the device has been started.
730 //
731 if (caps == FxPnpCapNoDisplayInUITrue) {
732 PnpDeviceState |= PNP_DEVICE_DONT_DISPLAY_IN_UI;
733 }
734 else if (caps == FxPnpCapNoDisplayInUIFalse) {
735 PnpDeviceState &= ~PNP_DEVICE_DONT_DISPLAY_IN_UI;
736 }
737 }
738
739 //
740 // Return device state maintained by frameworks.
741 //
742 if (IsInSpecialUse()) {
743 PnpDeviceState |= PNP_DEVICE_NOT_DISABLEABLE;
744 }
745
746 //
747 // If there is an internal failure, then indicate that up to pnp.
748 //
750 PnpDeviceState |= PNP_DEVICE_FAILED;
751 }
752
753 return PnpDeviceState;
754}
755
760 )
761/*++
762
763Routine Description:
764 Handles a query device relations for the bus relations type (all other types
765 are handled by HandleQueryDeviceRelations). This function will call into
766 each of the device's FxChildList objects to process the request.
767
768Arguments:
769 Irp - the request contain the query device relations
770
771Return Value:
772 NTSTATUS
773
774 --*/
775{
777 PDEVICE_RELATIONS pRelations;
779 NTSTATUS status, listStatus;
780 BOOLEAN changed;
781
782 //
783 // Before we do anything, callback into the driver
784 //
786
787 //
788 // Default to success unless list processing fails
789 //
791
792 //
793 // Keep track of changes made by any list object. If anything changes,
794 // remember it for post-processing.
795 //
796 changed = FALSE;
797
798 pRelations = (PDEVICE_RELATIONS) Irp->GetInformation();
799
800 if (m_EnumInfo != NULL) {
802
803 pList->LockForEnum(GetDriverGlobals());
804 }
805 else {
806 pList = NULL;
807 }
808
809 ple = NULL;
810 while (pList != NULL && (ple = pList->GetNextEntry(ple)) != NULL) {
811 FxChildList* pChildList;
812
813 pChildList = FxChildList::_FromEntry(ple);
814
815 //
816 // ProcessBusRelations will free and reallocate pRelations if necessary
817 //
818 listStatus = pChildList->ProcessBusRelations(&pRelations);
819
820 //
821 // STATUS_NOT_SUPPORTED is a special value. It indicates that the call
822 // to ProcessBusRelations did not modify pRelations in any way.
823 //
824 if (listStatus == STATUS_NOT_SUPPORTED) {
825 continue;
826 }
827
828
829 if (!NT_SUCCESS(listStatus)) {
832 "WDFDEVICE %p, WDFCHILDLIST %p returned %!STATUS! from "
833 "processing bus relations",
834 m_Device->GetHandle(), pChildList->GetHandle(), listStatus);
835 status = listStatus;
836 break;
837 }
838
839 //
840 // We updated pRelations, change the status later
841 //
842 changed = TRUE;
843 }
844
845 //
846 // By checking for NT_SUCCESS(status) below we account for
847 // both the cases - list changed, as well as list unchanged but possibly
848 // children being reported missing (that doesn't involve list change).
849 //
850 if (NT_SUCCESS(status)) {
851
852 ple = NULL;
853 while (pList != NULL && (ple = pList->GetNextEntry(ple)) != NULL) {
854 FxChildList* pChildList;
855
856 pChildList = FxChildList::_FromEntry(ple);
857
858 //
859 // invoke the ReportedMissing callback for for children that are
860 // being reporte missing
861 //
862 pChildList->InvokeReportedMissingCallback();
863 }
864 }
865
866 if (pList != NULL) {
867 pList->UnlockFromEnum(GetDriverGlobals());
868 }
869
870 if (NT_SUCCESS(status) && changed == FALSE) {
871 //
872 // Went through the entire list of FxChildList objects, but no object
873 // modified the pRelations, so restore the caller's NTSTATUS.
874 //
875 status = Irp->GetStatus();
876 }
877
878 //
879 // Re-set the relations into the structure so that any changes that any call
880 // to FxChildList::ProcessBusRelations takes effect and is reported.
881 //
882 Irp->SetInformation((ULONG_PTR) pRelations);
883 Irp->SetStatus(status);
884
887 "WDFDEVICE %p, returning %!STATUS! from processing bus relations",
889 );
890
891 if (NT_SUCCESS(status) && pRelations != NULL) {
892 ULONG i;
893
896 "WDFDEVICE %p returning %d devices in relations %p",
897 m_Device->GetHandle(), pRelations->Count, pRelations
898 );
899
900 //
901 // Try to not consume an IFR entry per DO reported. Instead, report up
902 // to 4 at a time.
903 //
904 for (i = 0; i < pRelations->Count && GetDriverGlobals()->FxVerboseOn; i += 4) {
905 if (i + 3 < pRelations->Count) {
908 "PDO %p PDO %p PDO %p PDO %p",
909 pRelations->Objects[i],
910 pRelations->Objects[i+1],
911 pRelations->Objects[i+2],
912 pRelations->Objects[i+3]
913 );
914 }
915 else if (i + 2 < pRelations->Count) {
918 "PDO %p PDO %p PDO %p",
919 pRelations->Objects[i],
920 pRelations->Objects[i+1],
921 pRelations->Objects[i+2]
922 );
923 }
924 else if (i + 1 < pRelations->Count) {
927 "PDO %p PDO %p",
928 pRelations->Objects[i],
929 pRelations->Objects[i+1]
930 );
931 }
932 else {
935 "PDO %p",
936 pRelations->Objects[i]
937 );
938 }
939 }
940 }
941
942 return status;
943}
944
949 )
950{
952
953 //
954 // Probably is a better check then this to see if the driver set the bus
955 // information
956 //
957 if (m_BusInformation.BusTypeGuid.Data1 != 0x0) {
958 PPNP_BUS_INFORMATION pBusInformation;
960
964
965 if (pBusInformation != NULL) {
966 //
967 // Initialize the PNP_BUS_INFORMATION structure with the data
968 // from PDO properties.
969 //
970 RtlCopyMemory(pBusInformation,
972 sizeof(PNP_BUS_INFORMATION));
973
974 Irp->SetInformation((ULONG_PTR) pBusInformation);
976 }
977 else {
978 Irp->SetInformation(NULL);
980
983 "WDFDEVICE %p could not allocate PNP_BUS_INFORMATION string, "
984 " %!STATUS!", m_Device->GetHandle(), status);
985 }
986 }
987 else {
988 status = Irp->GetStatus();
989 }
990
991 return status;
992}
993
999 )
1000/*++
1001
1002Routine Description:
1003 Handles the query device relations request for all relation types *except*
1004 for bus relations (HandleQueryBusRelations handles that type exclusively).
1005
1006 This function will allocate a PDEVICE_RELATIONS structure if the passed in
1007 FxRelatedDeviceList contains any devices to add to the relations list.
1008
1009Arguments:
1010 Irp - the request
1011
1012 List - list containing devices to report in the relations
1013
1014Return Value:
1015 NTSTATUS
1016
1017 --*/
1018{
1019 PDEVICE_RELATIONS pPriorRelations, pNewRelations;
1022 ULONG count;
1023 size_t size;
1025 BOOLEAN retry;
1027
1028 if (List == NULL) {
1029 //
1030 // Indicate that we didn't modify the irp at all since we have no list
1031 //
1032 return STATUS_NOT_SUPPORTED;
1033 }
1034
1036 type = Irp->GetParameterQDRType();
1038
1039 //
1040 // Notify driver that he should re-scan for device relations.
1041 //
1043
1044 pPriorRelations = (PDEVICE_RELATIONS) Irp->GetInformation();
1045 retry = FALSE;
1046
1047 count = 0;
1048
1049 List->LockForEnum(pFxDriverGlobals);
1050
1051 //
1052 // Count how many entries there are in the list
1053 //
1054 for (entry = NULL; (entry = List->GetNextEntry(entry)) != NULL; count++) {
1055 DO_NOTHING();
1056 }
1057
1058 //
1059 // If we have
1060 // 1) no devices in the list AND
1061 // a) we have nothing to report OR
1062 // b) we have something to report and there are previous relations (which
1063 // if left unchanged will be used to report our missing devices)
1064 //
1065 // THEN we have nothing else to do, just return
1066 //
1067 if (count == 0 &&
1068 (List->m_NeedReportMissing == 0 || pPriorRelations != NULL)) {
1069 List->UnlockFromEnum(pFxDriverGlobals);
1070 return STATUS_NOT_SUPPORTED;
1071 }
1072
1073 if (pPriorRelations != NULL) {
1074 //
1075 // Looks like another driver in the stack has already added some
1076 // entries. Make sure we allocate space for these additional entries.
1077 //
1078 count += pPriorRelations->Count;
1079 }
1080
1081 //
1082 // Allocate space for the device relations structure (which includes
1083 // space for one PDEVICE_OBJECT, and then allocate enough additional
1084 // space for the extra PDEVICE_OBJECTS we need.
1085 //
1086 // (While no FxChildList objects are used in this function, this static
1087 // function from the class computes what we need.)
1088 //
1090
1093
1094 if (pNewRelations == NULL) {
1095 //
1096 // Dereference any previously reported relations before exiting. They
1097 // are dereferenced here because the PNP manager will see error and not
1098 // do anything while the driver which added these objects expects the
1099 // pnp manager to do the dereference. Since this device is changing the
1100 // status, it must act like the pnp manager.
1101 //
1102 if (pPriorRelations != NULL) {
1103 ULONG i;
1104
1105 for (i = 0; i < pPriorRelations->Count; i++) {
1106 Mx::MxDereferenceObject(pPriorRelations->Objects[i]);
1107 }
1108 }
1109
1110 if (List->IncrementRetries() < 3) {
1111 retry = TRUE;
1112 }
1113
1115
1118 "WDFDEVICE %p could not allocate device relations for type %d string, "
1119 " %!STATUS!", m_Device->GetHandle(), type, status);
1120
1121 goto Done;
1122 }
1123
1124 RtlZeroMemory(pNewRelations, size);
1125
1126 //
1127 // If there was an existing device relations structure, copy
1128 // the entries to the new structure.
1129 //
1130 if (pPriorRelations != NULL && pPriorRelations->Count > 0) {
1132 pNewRelations,
1133 pPriorRelations,
1135 );
1136 }
1137
1138 //
1139 // Walk the list and return the relations here
1140 //
1141 for (entry = NULL;
1142 (entry = List->GetNextEntry(entry)) != NULL;
1143 pNewRelations->Count++) {
1144 MdDeviceObject pdo;
1145
1146 pdo = entry->GetDevice();
1147
1150 }
1151
1152 //
1153 // Add it to the DEVICE_RELATIONS structure. Pnp dictates that each
1154 // PDO in the list be referenced.
1155 //
1156 pNewRelations->Objects[pNewRelations->Count] = reinterpret_cast<PDEVICE_OBJECT>(pdo);
1158 }
1159
1160Done:
1161 if (NT_SUCCESS(status)) {
1162 List->ZeroRetries();
1163 }
1164
1165 List->UnlockFromEnum(GetDriverGlobals());
1166
1167 if (pPriorRelations != NULL) {
1168 MxMemory::MxFreePool(pPriorRelations);
1169 }
1170
1171 if (retry) {
1172 MxDeviceObject physicalDeviceObject(
1174 );
1175
1176 physicalDeviceObject.InvalidateDeviceRelations(type);
1177 }
1178
1179 Irp->SetStatus(status);
1180 Irp->SetInformation((ULONG_PTR) pNewRelations);
1181
1182 return status;
1183}
1184
1188 VOID
1189 )
1190
1191/*++
1192
1193Routine Description:
1194
1195 This function does any initialization to this object which must be done
1196 after the underlying device object has been attached to the device stack,
1197 i.e. you can send IRPs down this stack now.
1198
1199Arguments:
1200
1201 none
1202
1203Returns:
1204
1205 NTSTATUS
1206
1207--*/
1208
1209{
1211
1213 if (!NT_SUCCESS(status)) {
1215 "PnP State Machine init failed, %!STATUS!",
1216 status);
1217 return status;
1218 }
1219
1221 if (!NT_SUCCESS(status)) {
1223 "Power State Machine init failed, %!STATUS!",
1224 status);
1225 return status;
1226 }
1227
1229 if (!NT_SUCCESS(status)) {
1231 "Power Policy State Machine init failed, %!STATUS!",
1232 status);
1233 return status;
1234 }
1235
1236 return status;
1237}
1238
1239VOID
1242 )
1243/*++
1244
1245Routine Description:
1246 Finish initializing the object. All initialization up until this point
1247 could fail. This function cannot fail, so all it can do is assign field
1248 values and take allocations from DeviceInit.
1249
1250Arguments:
1251 DeviceInit - device initialization structure that the driver writer has
1252 initialized
1253
1254Return Value:
1255 None
1256
1257 --*/
1258
1259{
1260 //
1261 // Reassign the state callback arrays away from the init struct.
1262 // Set the init field to NULL so that it does not attempt to free the array
1263 // when it is destroyed.
1264 //
1265 m_PnpStateCallbacks = DeviceInit->PnpPower.PnpStateCallbacks;
1266 DeviceInit->PnpPower.PnpStateCallbacks = NULL;
1267
1268 m_PowerStateCallbacks = DeviceInit->PnpPower.PowerStateCallbacks;
1269 DeviceInit->PnpPower.PowerStateCallbacks = NULL;
1270
1271 m_PowerPolicyStateCallbacks = DeviceInit->PnpPower.PowerPolicyStateCallbacks;
1272 DeviceInit->PnpPower.PowerPolicyStateCallbacks = NULL;
1273
1274 //
1275 // Bias the count towards one so that we can optimize the synchronous
1276 // cleanup case when the device is being destroyed.
1277 //
1279
1280 //
1281 // Now "Add" this device in the terms that the PnP state machine uses. This
1282 // will be in the context of an actual AddDevice function for FDOs, and
1283 // something very much like it for PDOs.
1284 //
1285 // Important that the posting of the event is after setting of the state
1286 // callback arrays so that we can guarantee that any state transition
1287 // callback will be made.
1288 //
1290}
1291
1292VOID
1294 VOID
1295 )
1296{
1299 "WDFDEVICE %p, !devobj %p processing delayed deletion from pnp state "
1300 "machine", m_Device->GetHandle(), m_Device->GetDeviceObject());
1301
1303 DeleteDevice();
1304}
1305
1306VOID
1310 )
1311
1312/*++
1313
1314Routine Description:
1315
1316 This function marks the device as capable of handling the paging path,
1317 hibernation or crashdumps. Any device that is necessary for one of these
1318 three things will get notification. It is then responsible for forwarding
1319 the notification to its parent. The Framework handles that. This
1320 function just allows a driver to tell the Framework how to respond.
1321
1322
1323Arguments:
1324
1325 FileType - identifies which of the special paths the device is in
1326 Supported - Yes or No
1327
1328Returns:
1329
1330 void
1331
1332--*/
1333
1334{
1335 switch (FileType) {
1338 case WdfSpecialFileDump:
1339 case WdfSpecialFileBoot:
1341 break;
1342
1343 default:
1345 "Invalid special file type %x", FileType);
1346 }
1347}
1348
1354 )
1355
1356/*++
1357
1358Routine Description:
1359
1360 This driver may be sent IRP_MN_QUERY_INTERFACE, which is a way of getting
1361 a direct-call table from some driver in a device stack. In some cases, the
1362 right response is to turn around and send a similar query to the device's
1363 parent. This function does that.
1364
1365
1366Arguments:
1367
1368 Device - This WDFDEVICE.
1369 Irp - The IRP that was sent to us.
1370
1371Returns:
1372
1373 NTSTATUS
1374
1375--*/
1376
1377{
1378 MdIrp pFwdIrp;
1380 NTSTATUS prevStatus;
1382
1383 prevStatus = Irp->GetStatus();
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396 pTopOfStack.SetObject(Device->m_ParentDevice->GetAttachedDeviceReference());
1397
1398 pFwdIrp = FxIrp::AllocateIrp(pTopOfStack.GetStackSize());
1399
1400 if (pFwdIrp != NULL) {
1401 FxAutoIrp fxFwdIrp(pFwdIrp);
1402
1403 //
1404 // The worker routine copies stack parameters to forward-Irp, sends it
1405 // down the stack synchronously, then copies back the stack parameters
1406 // from forward-irp to original-irp
1407 //
1409
1410 if (fxFwdIrp.GetStatus() != STATUS_NOT_SUPPORTED) {
1411 status = fxFwdIrp.GetStatus();
1412 }
1413 else {
1414 status = prevStatus;
1415 }
1416
1417 Irp->SetStatus(status);
1418 Irp->SetInformation(fxFwdIrp.GetInformation());
1419 }
1420 else {
1422
1424 Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1425 "WDFDEVICE %p could not allocate IRP to send QI to parent !devobj "
1426 "%p, %!STATUS!", Device->GetHandle(), pTopOfStack.GetObject(),
1427 status);
1428 }
1429
1430 pTopOfStack.DereferenceObject();
1431
1432 return status;
1433}
1434
1438 __inout FxIrp* Irp,
1440 )
1441{
1443
1445
1446 //
1447 // Send the request down the stack first. If someone lower handles it
1448 // or failed trying to, just return their status
1449 //
1451
1453 //
1454 // Success or failure trying to handle it
1455 //
1456 return status;
1457 }
1458
1459 //
1460 // The semantic of this QI is that it sent down while processing start or
1461 // a device usage notification on the way *up* the stack. That means that
1462 // by the time the QI gets to the lower part of the stack, the power thread
1463 // will have already been allocated and exported.
1464 //
1466
1467 if (Irp->GetParameterQueryInterfaceVersion() == 1 &&
1468 Irp->GetParameterQueryInterfaceSize() >=
1470 //
1471 // Expose the interface to the requesting driver.
1472 //
1474
1476
1477 //
1478 // Caller assumes a reference has been taken.
1479 //
1482 );
1483 }
1484 else {
1486 }
1487
1488 return status;
1489}
1490
1494 __inout FxIrp* Irp,
1496 )
1497
1498/*++
1499
1500Routine Description:
1501
1502 This driver may be sent IRP_MN_QUERY_INTERFACE, which is a way of getting
1503 a direct-call table from some driver in a device stack. This function
1504 looks into a list of interfaces that the driver has registered and, if
1505 the interface that is being sought is present, it answers the IRP.
1506
1507Arguments:
1508
1509 Irp - The IRP that was sent to us.
1510 CompleteRequest - tells the caller whether the IRP should be completed
1511
1512Returns:
1513
1514 NTSTATUS
1515
1516--*/
1517
1518{
1520 const GUID* pInterfaceType;
1522 FxQueryInterface *pQI;
1523 PVOID pFound;
1524 PINTERFACE pExposedInterface;
1525 PVOID pExposedInterfaceSpecificData;
1526 BOOLEAN sendToParent;
1527
1529
1531
1532 pFound = NULL;
1533 pQI = NULL;
1534 pExposedInterface = NULL;
1535 pExposedInterfaceSpecificData = NULL;
1536 sendToParent = FALSE;
1537
1538 pInterfaceType = Irp->GetParameterQueryInterfaceType();
1539 //
1540 // The power thread is special cased because it has a different semantic
1541 // then the usual QI irp that we expose to the driver writer. In this case,
1542 // we want to fill in the interface if the lower stack does not support it.
1543 //
1544 if (FxIsEqualGuid(pInterfaceType, &GUID_POWER_THREAD_INTERFACE)) {
1546 }
1547 else if (FxIsEqualGuid(pInterfaceType, &GUID_REENUMERATE_SELF_INTERFACE_STANDARD)) {
1548 if (m_Device->IsPdo()) {
1549 return ((FxPkgPdo*) this)->HandleQueryInterfaceForReenumerate(
1551 }
1552 }
1553
1554 status = Irp->GetStatus();
1555
1556 //
1557 // Walk the interface collection and return the appropriate interface.
1558 //
1560
1561 for (ple = m_QueryInterfaceHead.Next; ple != NULL; ple = ple->Next) {
1563
1564 if (FxIsEqualGuid(Irp->GetParameterQueryInterfaceType(),
1565 &pQI->m_InterfaceType)) {
1566
1567 pExposedInterface = Irp->GetParameterQueryInterfaceInterface();
1568 pExposedInterfaceSpecificData =
1569 Irp->GetParameterQueryInterfaceInterfaceSpecificData();
1570
1571 if (pQI->m_Interface != NULL) {
1572 //
1573 // NOTE: If a driver has exposed the same interface GUID with
1574 // different sizes as a ways of versioning, then the driver
1575 // writer can specify the minimum size and version number
1576 // and then fill in the remaining fields in the callback
1577 // below.
1578 //
1579 if (pQI->m_Interface->Size <= Irp->GetParameterQueryInterfaceSize() &&
1580 pQI->m_Interface->Version <= Irp->GetParameterQueryInterfaceVersion()) {
1581
1582 if (pQI->m_ImportInterface == FALSE) {
1583 //
1584 // Expose the interface to the requesting driver.
1585 //
1586 RtlCopyMemory(pExposedInterface,
1587 pQI->m_Interface,
1588 pQI->m_Interface->Size);
1589 }
1590 else {
1591 //
1592 // The interface contains data which the driver wants
1593 // before copying over its information, so don't do a
1594 // copy and let the event callback do the copy
1595 //
1596 DO_NOTHING();
1597 }
1598 }
1599 else {
1601 break;
1602 }
1603 }
1604
1605 callback.m_Method = pQI->m_ProcessRequest.m_Method;
1606 sendToParent = pQI->m_SendQueryToParentStack;
1607 pFound = pQI;
1608
1610 break;
1611 }
1612 }
1613
1615
1616 if (!NT_SUCCESS(status) || pFound == NULL) {
1617 goto Done;
1618 }
1619
1620 //
1621 // Let the driver see the interface before it is handed out.
1622 //
1623 status = callback.Invoke(m_Device->GetHandle(),
1624 (LPGUID) Irp->GetParameterQueryInterfaceType(),
1625 pExposedInterface,
1626 pExposedInterfaceSpecificData);
1627
1628 //
1629 // STATUS_NOT_SUPPORTED is a special cased error code which indicates that
1630 // the QI should travel down the rest of the stack.
1631 //
1633 goto Done;
1634 }
1635
1636 //
1637 // If it is meant for the parent, send it down the parent stack
1638 //
1639 if (sendToParent) {
1641 goto Done;
1642 }
1643
1644 //
1645 // Reference the interface before returning it to the requesting driver.
1646 // If this is an import interface, the event callback is free to not fill
1647 // in the InterfaceReference function pointer.
1648 //
1649 if (pExposedInterface->InterfaceReference != NULL) {
1650 pExposedInterface->InterfaceReference(pExposedInterface->Context);
1651 }
1652
1653 //
1654 // If we are not a PDO in the stack, then send the fully formatted QI request
1655 // down the stack to allow others to filter the interface.
1656 //
1657 if (m_Device->IsPdo() == FALSE) {
1659
1660 Irp->SetStatus(status);
1661 Irp->CopyCurrentIrpStackLocationToNext();
1662 status = Irp->SendIrpSynchronously(m_Device->GetAttachedDevice());
1663 }
1664
1665Done:
1666 if (pFound != NULL) {
1668 }
1669
1670 return status;
1671}
1672
1676 VOID
1677 )
1678{
1681
1683
1685
1687 &deviceObject,
1689 &caps);
1690
1691 if (NT_SUCCESS(status)) {
1692 ULONG states, i;
1693
1694 ASSERT(caps.DeviceCaps.DeviceWake <= 0xFF && caps.DeviceCaps.SystemWake <= 0xFF);
1695
1696 m_SystemWake = (BYTE) caps.DeviceCaps.SystemWake;
1697
1698 //
1699 // Initialize the array of wakeable D-states to say that all system
1700 // states down to the one identified in the caps can generate wake.
1701 // This will be overridden below if the BIOS supplied more information.
1702 //
1703 // Compatibility Note: Non-ACPI bus drivers (root-enumerated drivers)
1704 // or other bus drivers that haven't set the power settings correctly
1705 // for their PDO may end up with a valid value for DeviceWake in the
1706 // device capabilities but a value of PowerSystemUnspecified for
1707 // SystemWake, in which case a call to WdfDeviceAssignS0IdleSettings or
1708 // WdfDeviceAssignSxWakeSettings DDIs will fail on 1.11+ resulting in
1709 // device compat issues. The failure is expected and right thing to do
1710 // but has compatibility implications - drivers that worked earlier now
1711 // fail on 1.11. Note that earlier versions of WDF did not have
1712 // m_DeviceWake as an array and stored just the capabilities->DeviceWake
1713 // value without regard to the SystemWake but the current implementation
1714 // introduces dependency on systemWake value). So for compat reasons,
1715 // for pre-1.11 compiled drivers we initilaize the array with DeviceWake
1716 // value ignoring SystemWake, removing any dependency of DeviceWake
1717 // on SystemWake value and thus preserving previous behavior for
1718 // pre-1.11 compiled drivers.
1719 //
1721
1723
1724 for (i = PowerSystemWorking; i <= m_SystemWake; i++) {
1725
1726 //
1727 // Note that this cast is hiding a conversion between two slightly
1728 // incompatible types. DeviceWake is in terms of DEVICE_POWER_STATE
1729 // which is defined this way:
1730 //
1731 // typedef enum _DEVICE_POWER_STATE {
1732 // PowerDeviceUnspecified = 0,
1733 // PowerDeviceD0,
1734 // PowerDeviceD1,
1735 // PowerDeviceD2,
1736 // PowerDeviceD3,
1737 // PowerDeviceMaximum
1738 // } DEVICE_POWER_STATE, *PDEVICE_POWER_STATE;
1739 //
1740 // m_DeviceWake is defined in terms of DEVICE_WAKE_DEPTH which is
1741 // defined this way:
1742 //
1743 // typedef enum _DEVICE_WAKE_DEPTH {
1744 // DeviceWakeDepthNotWakeable = 0,
1745 // DeviceWakeDepthD0,
1746 // DeviceWakeDepthD1,
1747 // DeviceWakeDepthD2,
1748 // DeviceWakeDepthD3hot,
1749 // DeviceWakeDepthD3cold,
1750 // DeviceWakeDepthMaximum
1751 // } DEVICE_WAKE_DEPTH, *PDEVICE_WAKE_DEPTH;
1752 //
1753 // The result is that the conversion below will map D3 onto D3hot,
1754 // which is a safe assumption to start with, one which may be
1755 // overridden later.
1756 //
1758 m_DeviceWake[i - PowerSystemWorking] = (BYTE) caps.DeviceCaps.DeviceWake;
1759 }
1760 }
1761 else {
1762 //
1763 // See comments above for information on mapping of device power
1764 // state to device wake depth.
1765 //
1768 (BYTE) caps.DeviceCaps.DeviceWake);
1769 }
1770
1771 //
1772 // Capture the S -> D state mapping table as a ULONG for use in the
1773 // power policy owner state machine when the machine moves into Sx and
1774 // the device is not armed for wake and has set an IdealDxStateForSx
1775 // value
1776 //
1777 states = 0x0;
1778
1779 for (i = 0; i < ARRAY_SIZE(caps.DeviceCaps.DeviceState); i++) {
1780 _SetPowerCapState(i, caps.DeviceCaps.DeviceState[i], &states);
1781 }
1782
1784
1785 //
1786 // Query for the D3cold support interface. If present, it will tell
1787 // us specifically which D-states will work for generating wake signals
1788 // from specific S-states.
1789 //
1790 // Earlier versions of WDF didn't make this query, so for compatibility,
1791 // we only make it now if the driver was built against WDF 1.11 or
1792 // later. In truth, this just shifts the failure from initialization
1793 // time to run time, because the information that we're presumably
1794 // getting from the BIOS with this interrogation is saying that the
1795 // code in earlier verisions of WDF would have blindly enabled a device
1796 // for wake which simply wasn't capable of generating its wake signal
1797 // from the chosen D-state. Thus the device would have been put into
1798 // a low power state and then failed to resume in response to its wake
1799 // signal.
1800 //
1801
1802 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) {
1803
1804 //
1805 // Cycle through all the system states that this device can wake
1806 // from. There's no need to look at deeper sleep states than
1807 // m_SystemWake because the driver will not arm for wake in
1808 // those states.
1809 //
1810 for (i = PowerSystemWorking; i <= m_SystemWake; i++) {
1813 }
1814 }
1815 }
1816 }
1817
1818 return status;
1819}
1820
1826 )
1827/*++
1828
1829Routine Description:
1830 This method is called in response to a PnP StartDevice IRP coming down the
1831 stack.
1832
1833Arguments:
1834 This - device instance
1835 Irp - a pointer to the FxIrp
1836
1837Returns:
1838 STATUS_PENDING
1839
1840--*/
1841{
1842 This->SetPendingPnpIrp(Irp);
1843 This->PnpProcessEvent(PnpEventStartDevice);
1844
1845 return STATUS_PENDING;
1846}
1847
1853 )
1854
1855/*++
1856
1857Routine Description:
1858
1859 Pnp callback querying to see if the device can be stopped.
1860
1861 The Framework philosophy surrounding Query Stop (and Query Remove) is that
1862 it's impossible to really know if you can stop unless you've tried to stop.
1863 This may not always be true, but it's hard to find a general strategy that
1864 works that is less conservative. Furthermore, I couldn't find good examples
1865 of drivers that would really benefit from continuing to handle requests
1866 until the actual Stop IRP arrived, particularly when you consider that
1867 most QueryStops are followed immediately by Stops.
1868
1869 So this function sends an event to the PnP State machine that begins the
1870 stopping process. If it is successful, then ultimately the QueryStop IRP
1871 will be successfully completed.
1872
1873Arguments:
1874
1875 This - a pointer to the PnP package
1876
1877 Irp - a pointer to the FxIrp
1878
1879Return Value:
1880
1881 STATUS_PENDING
1882
1883 --*/
1884
1885{
1886 //
1887 // Keep this IRP around, since we're going to deal with it later.
1888 //
1889 This->SetPendingPnpIrp(Irp);
1890
1891 //
1892 // Now run the state machine on this thread.
1893 //
1894 This->PnpProcessEvent(PnpEventQueryStop);
1895
1896 return STATUS_PENDING;
1897}
1898
1904 )
1905/*++
1906
1907Routine Description:
1908
1909 This routine is invoked in response to a query stop failing, somewhere in
1910 the stack. Note that we can receive a cancel stop without being in the
1911 query stop state if a driver above us in the stack failed the query stop.
1912
1913 Again, this function just exists to bridge the gap between the WDM IRPs
1914 and the PnP state machine. This function does little more than send an
1915 event to the machine.
1916
1917Arguments:
1918
1919 This - the package
1920
1921 Irp - a pointer to the FxIrp
1922
1923Returns:
1924
1925 STATUS_PENDING
1926
1927--*/
1928{
1929 //
1930 // Seed the irp with success
1931 //
1932 Irp->SetStatus(STATUS_SUCCESS);
1933
1934 //
1935 // Pend it and transition the state machine
1936 //
1937 This->SetPendingPnpIrp(Irp);
1938 This->PnpProcessEvent(PnpEventCancelStop);
1939
1940 return STATUS_PENDING;
1941}
1942
1948 )
1949/*++
1950
1951Routine Description:
1952
1953 This method is invoked in response to a Pnp StopDevice IRP.
1954
1955Arguments:
1956
1957 Irp - a pointer to the FxIrp
1958
1959Returns:
1960
1961 STATUS_PENDING
1962
1963--*/
1964{
1965 //
1966 // Seed the irp with success
1967 //
1968 Irp->SetStatus(STATUS_SUCCESS);
1969
1970 //
1971 // Pend and transition the state machine
1972 //
1973 This->SetPendingPnpIrp(Irp);
1974 This->PnpProcessEvent(PnpEventStop);
1975
1976 return STATUS_PENDING;
1977}
1978
1984 )
1985/*++
1986
1987Routine Description:
1988
1989 Again, the Framework handles QueryRemove by stopping everything going on
1990 related to the device and then asking the driver whether it can be
1991 removed. This function just kicks the state machine. Final completion
1992 of the IRP will come (much) later.
1993
1994Arguments:
1995
1996 This - the package
1997
1998 Irp - a pointer to the FxIrp
1999
2000Returns:
2001
2002 STATUS_PENDING
2003
2004--*/
2005{
2006 //
2007 // By default we handle this state.
2008 //
2009 Irp->SetStatus(STATUS_SUCCESS);
2010
2011 //
2012 // Keep this IRP around, since we're going to deal with it later.
2013 //
2014 This->SetPendingPnpIrp(Irp);
2015
2016 //
2017 // Now run the state machine on this thread.
2018 //
2019 This->PnpProcessEvent(PnpEventQueryRemove);
2020
2021 return STATUS_PENDING;
2022}
2023
2029 )
2030
2031/*++
2032
2033Routine Description:
2034
2035 Notification of a previous remove being canceled. Kick the state machine.
2036
2037Arguments:
2038
2039 This - the package
2040
2041 Irp - FxIrp representing the notification
2042
2043Return Value:
2044
2045 STATUS_PENDING
2046
2047 --*/
2048
2049{
2050 //
2051 // Seed the irp with success
2052 //
2053 Irp->SetStatus(STATUS_SUCCESS);
2054
2055 //
2056 // Pend it and transition the state machine
2057 //
2058
2059 This->SetPendingPnpIrp(Irp);
2060 This->PnpProcessEvent(PnpEventCancelRemove);
2061
2062 return STATUS_PENDING;
2063}
2064
2065VOID
2067 __in BOOLEAN CleanupPnp
2068 )
2069{
2070#if (FX_CORE_MODE==FX_CORE_USER_MODE)
2072#else
2073 FxCREvent eventOnStack;
2074 eventOnStack.Initialize();
2075 FxCREvent * event = eventOnStack.GetSelfPointer();
2076#endif
2077
2078 //
2079 // Order of shutdown is important here.
2080 // o Pnp initiates events to power policy.
2081 // o Power policy initiates events to power and device-power-requirement
2082 // o Power does not initiate any events
2083 // o Device-power-requirement does not initiate any events
2084 //
2085 // By shutting them down in the order in which they send events, we can
2086 // guarantee that no new events will be posted into the subsidiary state
2087 // machines.
2088 //
2089
2090 //
2091 // This will shut off the pnp state machine and synchronize any outstanding
2092 // threads of execution.
2093 //
2094 if (CleanupPnp && m_PnpMachine.SetFinished(
2095 event
2096 ) == FALSE) {
2099 "WDFDEVICE %p, !devobj %p waiting for pnp state machine to finish",
2101
2102 //
2103 // Process the event *before* completing the irp so that this event is in
2104 // the queue before the device remove event which will be processed
2105 // right after the start irp has been completed.
2106 //
2107 event->EnterCRAndWaitAndLeave();
2108 }
2109
2110 //
2111 // Even though event is a SynchronizationEvent, so we need to reset it for
2112 // the next wait because SetFinished will set it if even if the transition
2113 // to the finished state is immediate
2114 //
2115 event->Clear();
2116
2120 "WDFDEVICE %p, !devobj %p waiting for pwr pol state machine to finish",
2122
2123 event->EnterCRAndWaitAndLeave();
2124 }
2125
2126 //
2127 // See previous comment about why we Clear()
2128 //
2129 event->Clear();
2130
2134 "WDFDEVICE %p, !devobj %p waiting for pwr state machine to finish",
2136
2137 event->EnterCRAndWaitAndLeave();
2138 }
2139
2140 if (IsPowerPolicyOwner()) {
2141 //
2142 // See previous comment about why we Clear()
2143 //
2144 event->Clear();
2145
2147 m_DevicePowerRequirementMachine) {
2148
2150 m_DevicePowerRequirementMachine->SetFinished(event)) {
2151
2154 "WDFDEVICE %p, !devobj %p waiting for device power "
2155 "requirement state machine to finish",
2158
2159 event->EnterCRAndWaitAndLeave();
2160 }
2161 }
2162
2164 }
2165
2166 //
2167 // Release the power thread if we have one either through creation or query.
2168 // Since the power policy state machine is off, we should no longer need
2169 // a dedicated thread.
2170 //
2171 // *** NOTE ***
2172 // The power thread must be released *BEFORE* sending the irp down the stack
2173 // because this can happen
2174 // 1) this driver is not the power thread owner, but the last client
2175 // 2) we send the pnp irp first
2176 // 3) the power thread owner waits on this thread for all the clients to go
2177 // away, but this device still has a reference on it
2178 // 4) this device will not release the reference b/c the owner is waiting
2179 // in the same thread.
2180 //
2182
2183 //
2184 // Deref the reenumeration interface
2185 //
2187}
2188
2189VOID
2191 __in MxEvent * WaitEvent
2192 )
2193/*++
2194
2195Routine Description:
2196 The device failed creation in some stage. It is assumed that the device has
2197 enough state that it can survive a transition through the pnp state machine
2198 (which means that pointers like m_PkgIo are valid and != NULL). When this
2199 function returns, it will have deleted the owning FxDevice.
2200
2201Arguments:
2202 WaitEvent - Event on which RemoveProcessed wait will be performed
2203
2204 We can't initialize this event on stack as the initialization
2205 can fail in user-mode. We can't have Initialize method
2206 preinitailize this event either as this function may get called
2207 before initialize (or in case of initialization failure).
2208
2209 Hence the caller preallocates the event and passes to this
2210 function.
2211
2212 Caller must initialize this event as SynchronizationEvent
2213 and it must be unsignalled.
2214Return Value:
2215 None
2216
2217 --*/
2218{
2220
2221 //
2222 // Caller must initialize the event as Synchronization event and it should
2223 // be passed as non-signalled. But we Clear it just to be sure.
2224 //
2225 WaitEvent->Clear();
2226
2227 ADDREF(WaitEvent);
2228
2230 m_DeviceRemoveProcessed = WaitEvent;
2231
2232 //
2233 // Simulate a remove event coming to the device. After this call returns
2234 // m_Device is still valid and must be deleted.
2235 //
2237
2238 //
2239 // No need to wait in a critical region because we are in the context of a
2240 // pnp request which is in the system context.
2241 //
2242 WaitEvent->WaitFor(Executive, KernelMode, FALSE, NULL);
2244
2245 RELEASE(WaitEvent);
2246}
2247
2248VOID
2250 VOID
2251 )
2252/*++
2253
2254Routine Description:
2255 This routine will detach and delete the device object and free the memory
2256 for the device if there are no other references to it. Before calling this
2257 routine, the state machines should have been cleaned up and the power thread
2258 released.
2259
2260--*/
2261{
2262 //
2263 // This will detach and delete the device object
2264 //
2265 m_Device->Destroy();
2266
2267 //
2268 // If this is the last reference, this will free the memory for the device
2269 //
2271}
2272
2278 )
2279
2280/*++
2281
2282Routine Description:
2283
2284 Notification of a remove. Kick the state machine.
2285
2286Arguments:
2287
2288 This - the package
2289
2290 Irp - FxIrp representing the notification
2291
2292Return Value:
2293
2294 status
2295
2296 --*/
2297
2298{
2299#if (FX_CORE_MODE==FX_CORE_USER_MODE)
2300 MxEvent * event = This->m_RemoveEventUm.GetSelfPointer();
2301#else
2302 MxEvent eventOnStack;
2303 eventOnStack.Initialize(SynchronizationEvent, FALSE);
2304 MxEvent * event = eventOnStack.GetSelfPointer();
2305#endif
2306
2308
2310 This->m_Device->GetRemoveLock(),
2311 Irp->GetIrp());
2312
2313#if DBG
2315#else
2317#endif
2318
2319 //
2320 // Keep this object around after m_Device has RELEASE'ed its reference to
2321 // this package.
2322 //
2323 This->ADDREF(Irp);
2324
2325 //
2326 // Removes are always success
2327 //
2328 Irp->SetStatus(STATUS_SUCCESS);
2329
2330 ASSERT(This->m_DeviceRemoveProcessed == NULL);
2331 This->m_DeviceRemoveProcessed = event;
2332
2333 //
2334 // Post the event and wait for the FxDevice to destroy itself or determine
2335 // it has not been reported missing yet (for PDOs and bus filters).
2336 //
2337 This->PnpProcessEvent(PnpEventRemove);
2338
2340 This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
2341 "WDFDEVICE %p, !devobj %p waiting for remove event to finish processing",
2342 This->m_Device->GetHandle(), This->m_Device->GetDeviceObject());
2343
2344 //
2345 // No need to wait in a critical region because we are in the context of a
2346 // pnp request which is in the system context.
2347 //
2348 event->WaitFor(Executive, KernelMode, FALSE, NULL);
2349
2350 This->m_DeviceRemoveProcessed = NULL;
2351
2352 status = This->ProcessRemoveDeviceOverload(Irp);
2353
2354 //
2355 // Release the reference added at the top. This is most likely going to be
2356 // the last reference on the package for KMDF. For UMDF, host manages the
2357 // lifetime of FxDevice so this may not be the last release for UMDF.
2358 //
2359 This->RELEASE(Irp);
2360
2361 return status;
2362}
2363
2368 )
2369
2370/*++
2371
2372Routine Description:
2373
2374 Notification that the device has been surprise removed. Kick the state
2375 machine.
2376
2377Arguments:
2378
2379 Irp - pointer to FxIrp representing this notification
2380
2381Return Value:
2382
2383 STATUS_PENDING
2384
2385--*/
2386
2387{
2388 //
2389 // Package specific handling
2390 //
2391 Irp->SetStatus(STATUS_SUCCESS);
2394
2395 return STATUS_PENDING;
2396}
2397
2403 )
2404
2405/*++
2406
2407Routine Description:
2408
2409 This the first-level dispatch routine for IRP_MN_WAIT_WAKE. What one
2410 does with a WaitWake IRP depends very much on whether one is an FDO, a PDO
2411 or a filter. So dispatch immediately to a subclassable function.
2412
2413Arguments:
2414
2415 This - the package
2416
2417 Irp - pointer to FxIrp representing this notification
2418
2419Return Value:
2420
2421 status
2422
2423--*/
2424
2425{
2426 return This->DispatchWaitWake(Irp);
2427}
2428
2433 )
2434/*++
2435
2436Routine Description:
2437
2438 Handles wait wake requests in a generic fashion
2439
2440Arguments:
2441
2442
2443Return Value:
2444
2445 --*/
2446{
2447 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
2449 PIRP oldIrp;
2450 KIRQL irql;
2451
2452 if (IsPowerPolicyOwner()) {
2454 //
2455 // A power irp arrived, but we did not request it. log and bugcheck
2456 //
2459 "Received wait wake power irp %p on device %p, but the irp was "
2460 "not requested by the device (the power policy owner)",
2461 Irp->GetIrp(), m_Device->GetDeviceObject());
2462
2464 WDF_POWER_MULTIPLE_PPO, // specific type
2465 (ULONG_PTR)m_Device->GetDeviceObject(), //parm 2
2466 (ULONG_PTR)Irp->GetIrp()); // parm 3
2467
2468 /* NOTREACHED */
2469 }
2470
2471 //
2472 // We are no longer requesting a power irp because we received the one
2473 // we requested.
2474 //
2476 }
2477
2478 //
2479 // The Framework has the concept of a "Wait/Wake Owner." This is the layer
2480 // in the stack that is enabling and disabling wake at the bus level. This
2481 // is probably the PDO or a bus filter like ACPI.sys. This is distinct
2482 // from being the "Power Policy Owner," which would mean that this driver
2483 // is deciding what D-state is appropriate for the device, and also
2484 // sending Wait/Wake IRPs.
2485 //
2486
2489
2491 //
2492 // We only allow one pended wait wake irp in the stack at a time.
2493 // Fail this secondary wait wake request.
2494 //
2496
2499 "Failing wait wake irp %p with %!STATUS! because wait wake irp "
2500 "%p already pended",
2502 }
2503 else {
2504 MdCancelRoutine pRoutine;
2505
2506 //
2507 // No wait wake irp is currently in the stack, so attempt to set
2508 // a cancel routine and transition the power state machine into a
2509 // a state where it can arm the device at the bus level for this
2510 // child.
2511 //
2512 // The power state machine expects the wait wake irp to have a cancel
2513 // routine set in all states. For those states which require a
2514 // non cancelable irp, those states clear the cancel routine as
2515 // appropriate.
2516 //
2517 pRoutine = Irp->SetCancelRoutine(_PowerWaitWakeCancelRoutine);
2518#if DBG
2519 ASSERT(pRoutine == NULL);
2520#else
2521 UNREFERENCED_PARAMETER(pRoutine);
2522#endif
2524
2525 if (Irp->IsCanceled()) {
2528 "wait wake irp %p already canceled", Irp->GetIrp());
2529
2530 //
2531 // This IRP has already been cancelled, we must clear the cancel
2532 // routine before completing the IRP.
2533 //
2534 pRoutine = Irp->SetCancelRoutine(NULL);
2535
2536 if (pRoutine != NULL) {
2537 //
2538 // Our cancel routine will not be called
2539 //
2540#if DBG
2542#else
2543 UNREFERENCED_PARAMETER(pRoutine);
2544#endif
2545 Irp->SetStatus(STATUS_CANCELLED);
2547 }
2548 }
2549
2550 if (status == STATUS_PENDING) {
2551 //
2552 // Either we successfully set the cancel routine or the irp
2553 // was canceled and the cancel routine is about to run when
2554 // we drop the lock. If the routine is about to run, we still
2555 // need to setup m_SharedPower to values that it expects.
2556 //
2557 Irp->MarkIrpPending();
2558 m_SharedPower.m_WaitWakeIrp = Irp->GetIrp();
2559 }
2560 }
2562
2563 if (NT_SUCCESS(status)) {
2564 //
2565 // Post to the appropriate matchines
2566 //
2568
2569 if (IsPowerPolicyOwner()) {
2571 }
2572 }
2573 else {
2575 }
2576
2577 return status;
2578 }
2579 else if (IsPowerPolicyOwner()) {
2580 //
2581 // Try to set m_WaitWakeIrp to the new IRP value only if the current
2582 // value of m_WaitWakeIrp is NULL because there can only be one
2583 // active wait wake irp in the stack at a time. Since the power policy
2584 // state machine never sends more then one, this is really a guard
2585 // against some other device in the stack sending a wait wake irp to
2586 // this device in the wrong state.
2587 //
2590 Irp->GetIrp(),
2591 NULL
2592 );
2593
2594 //
2595 // If oldIrp is NULL then there was no previous irp and we successfully
2596 // exchanged the new PIRP value into m_WaitWakeIrp
2597 //
2598 if (oldIrp == NULL) {
2600
2601 //
2602 // NOTE: There is a built in race condition here that WDF cannot
2603 // solve with the given WDM primitives. After arming the
2604 // device for wake, there is a window where the wait wake irp
2605 // has not yet been processed by the wait wake owner. Until
2606 // the wake request is processed, wake events could be generated
2607 // and lost. There is nothing we can do about this until we
2608 // have synchronous "goto Dx and arm" command available.
2609 //
2610 Irp->CopyCurrentIrpStackLocationToNext();
2611 Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(),
2613 this);
2614
2615 //
2616 // Technically, there should be a PDO vs FDO overload here which
2617 // does the right thing w/regard to this request and if it is at the
2618 // bottom of the stack or not. But, by design, we check for
2619 // m_WaitWakeOwner first which has the direct side affect of making
2620 // it impossible for a PDO to get to this point.
2621 //
2622 ASSERT(m_Device->IsFdo());
2623
2624 status = Irp->PoCallDriver(m_Device->GetAttachedDevice());
2625
2626 //
2627 // Send the wake arrived after sending the request as commented above.
2628 // This window between sending the request and sending the event to
2629 // the state machine allows the wait owner to complete the request
2630 // immediately. When completed synchronously, it has an effect on
2631 // both wake scenarios:
2632 //
2633 // 1) wake from S0: the device never transitions to Dx and the idle
2634 // timer is resumed if no i/o is present
2635 //
2636 // 2) wake from sx: the device is disarmed for wake from Sx and
2637 // put into Dx with being armed for wake.
2638 //
2640 }
2641 else {
2643
2645 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
2646 "already have a ww irp %p, failing new ww irp %p with %!STATUS!",
2647 oldIrp, Irp->GetIrp(), status);
2648
2650 }
2651 }
2652 else {
2653 //
2654 // Not the power policy owner, not the wait wake irp owner, ignore the
2655 // irp
2656 //
2657 // This will release the remove lock.
2658 //
2660 }
2661
2662 return status;
2663}
2664
2669 )
2670{
2672
2673 //
2674 // Update the callback table.
2675 //
2676 m_DeviceD0Entry.m_Method = DispatchTable->EvtDeviceD0Entry;
2678 DispatchTable->EvtDeviceD0EntryPostInterruptsEnabled;
2680 DispatchTable->EvtDeviceD0ExitPreInterruptsDisabled;
2681 m_DeviceD0Exit.m_Method = DispatchTable->EvtDeviceD0Exit;
2682
2683 m_DevicePrepareHardware.m_Method = DispatchTable->EvtDevicePrepareHardware;
2684 m_DeviceReleaseHardware.m_Method = DispatchTable->EvtDeviceReleaseHardware;
2685
2686 m_DeviceQueryStop.m_Method = DispatchTable->EvtDeviceQueryStop;
2687 m_DeviceQueryRemove.m_Method = DispatchTable->EvtDeviceQueryRemove;
2688
2689 m_DeviceSurpriseRemoval.m_Method = DispatchTable->EvtDeviceSurpriseRemoval;
2690
2691 m_DeviceUsageNotification.m_Method = DispatchTable->EvtDeviceUsageNotification;
2692 m_DeviceUsageNotificationEx.m_Method = DispatchTable->EvtDeviceUsageNotificationEx;
2693 m_DeviceRelationsQuery.m_Method = DispatchTable->EvtDeviceRelationsQuery;
2694
2695 if (DispatchTable->EvtDeviceSelfManagedIoCleanup != NULL ||
2696 DispatchTable->EvtDeviceSelfManagedIoFlush != NULL ||
2697 DispatchTable->EvtDeviceSelfManagedIoInit != NULL ||
2698 DispatchTable->EvtDeviceSelfManagedIoSuspend != NULL ||
2699 DispatchTable->EvtDeviceSelfManagedIoRestart != NULL) {
2700
2702 this);
2703
2704 if (!NT_SUCCESS(status)) {
2705 return status;
2706 }
2707
2709 }
2710
2711 return STATUS_SUCCESS;
2712}
2713
2714VOID
2717 )
2718{
2720 Callbacks->EvtDeviceArmWakeFromS0;
2722 Callbacks->EvtDeviceArmWakeFromSx;
2724 Callbacks->EvtDeviceArmWakeFromSxWithReason;
2725
2727 Callbacks->EvtDeviceDisarmWakeFromS0;
2729 Callbacks->EvtDeviceDisarmWakeFromSx;
2730
2732 Callbacks->EvtDeviceWakeFromS0Triggered;
2734 Callbacks->EvtDeviceWakeFromSxTriggered;
2735}
2736
2739 __in const GUID* Guid,
2742 )
2743{
2744 // WDF_WMI_PROVIDER_CONFIG config;
2745 // NTSTATUS status;
2746
2747 // WDF_WMI_PROVIDER_CONFIG_INIT(&config, Guid);
2748
2749 // //
2750 // // We are assuming we are registering either for the wait wake or device
2751 // // timeout GUIDs which both operate on BOOLEANs. If we expand this API in
2752 // // the future, have the caller pass in a config structure for the provider
2753 // // GUID.
2754 // //
2755 // config.MinInstanceBufferSize = sizeof(BOOLEAN);
2756
2757 // status = m_Device->m_PkgWmi->AddPowerPolicyProviderAndInstance(
2758 // &config,
2759 // Callbacks,
2760 // Instance);
2761
2762 // if (status == STATUS_OBJECT_NAME_COLLISION) {
2763 // status = STATUS_SUCCESS;
2764 // }
2765
2766 // if (!NT_SUCCESS(status)) {
2767 // DoTraceLevelMessage(
2768 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2769 // "Failed to register WMI power GUID %!STATUS!", status);
2770 // }
2771 //
2772 // return status;
2774 return STATUS_SUCCESS;
2775}
2776
2780 )
2781/*++
2782
2783Routine Description:
2784
2785 Updates the S0 Idle settings for the device and then posts an update event
2786 to the power policy state machine. The first this function is called, the
2787 ability to allow the user to control this setting is set.
2788
2789Arguments:
2790
2791 Settings - The settings to apply.
2792
2793Return Value:
2794
2795 NTSTATUS
2796
2797 --*/
2798{
2799 DEVICE_POWER_STATE dxState;
2800 ULONG idleTimeout;
2802 BOOLEAN enabled, s0Capable, overridable, firstTime;
2803 WDF_TRI_STATE powerUpOnSystemWake;
2804 const LONGLONG negliblySmallIdleTimeout = -1; // 100 nanoseconds
2805
2806 s0Capable = FALSE;
2807 dxState = PowerDeviceD3;
2808 overridable = FALSE;
2809 firstTime = TRUE;
2810
2811 if (Settings->Enabled == WdfTrue) {
2812 enabled = TRUE;
2813
2814 } else if (Settings->Enabled == WdfUseDefault) {
2815 enabled = TRUE;
2816
2819
2820 //
2821 // Read registry. If registry value is not found, the value of "enabled"
2822 // remains unchanged
2823 //
2824 ReadRegistryS0Idle(&valueName, &enabled);
2825 }
2826 else {
2829 "If registry value WdfDefaultIdleInWorkingState was present, "
2830 "it was not read because DDI WdfDeviceAssignS0IdleSettings "
2831 "was not called at PASSIVE_LEVEL");
2832 }
2833 }
2834 else {
2835 enabled = FALSE;
2836 }
2837
2839 firstTime = FALSE;
2840 }
2841
2844 if (!NT_SUCCESS(status)) {
2845 return status;
2846 }
2847
2848 //
2849 // Do not set m_CapsQueried to TRUE yet because we will do that once we
2850 // know the entire stack has been built we will do the query again.
2851 //
2852 }
2853
2854 switch (Settings->IdleCaps) {
2856 case IdleCanWakeFromS0:
2857 s0Capable = TRUE;
2858
2859 if (Settings->DxState == PowerDeviceMaximum) {
2861
2862 //
2863 // Some bus drivers
2864
2865 // incorrectly report DeviceWake=D0 to
2866 // indicate that it does not support wake instead of specifying
2867 // PowerDeviceUnspecified and KMDF ends up requesting
2868 // a D0 irp when going to Dx. The check prevents this bug.
2869 //
2870 if (dxState < PowerDeviceD1 ||
2871 dxState > PowerDeviceD3 ||
2872 (dxState > PowerDeviceD2 && Settings->IdleCaps == IdleUsbSelectiveSuspend)
2873 ) {
2875
2878 "DeviceWake power state reported in device capabilities "
2879 "%!DEVICE_POWER_STATE! indicates that device can not signal"
2880 " a wake event, %!STATUS!",
2881 dxState, status);
2882 return status;
2883 }
2884 }
2885 else {
2886 DEVICE_POWER_STATE dxDeepest;
2887
2888 dxState = Settings->DxState;
2890
2891 if (dxState > dxDeepest) {
2893
2896 "DxState specified by driver %!DEVICE_POWER_STATE! cannot "
2897 "be lighter than lightest available device wake state"
2898 " %!DEVICE_POWER_STATE!, %!STATUS!", dxState,
2899 dxDeepest, status);
2900 return status;
2901 }
2902
2903 //
2904 // Can only perform wait wake from D2 on a USB device
2905 //
2906 if (dxState > PowerDeviceD2 &&
2907 Settings->IdleCaps == IdleUsbSelectiveSuspend) {
2909
2912 "DxState specified by driver %!DEVICE_POWER_STATE! cannot "
2913 "be lighter than PowerDeviceD2 for USB selective suspend "
2914 "%!STATUS!",
2915 dxState, status);
2916 return status;
2917 }
2918 }
2919
2920 if (Settings->IdleCaps == IdleUsbSelectiveSuspend) {
2922
2923 if (!NT_SUCCESS(status)) {
2926 "Failed to initialize USB selective suspend %!STATUS!",
2927 status);
2928 return status;
2929 }
2930 }
2931
2932 break;
2933
2935 s0Capable = FALSE;
2936
2937 if (Settings->DxState == PowerDeviceMaximum) {
2938 dxState = PowerDeviceD3;
2939 }
2940 else {
2941 dxState = Settings->DxState;
2942 }
2943
2944 break;
2945
2946 default:
2947 ASSERT(FALSE);
2948 break;
2949 }
2950
2951 if (Settings->IdleTimeout == IdleTimeoutDefaultValue) {
2952 idleTimeout = FxPowerPolicyDefaultTimeout;
2953 }
2954 else {
2955 idleTimeout = Settings->IdleTimeout;
2956 }
2957
2958 if (Settings->UserControlOfIdleSettings == IdleAllowUserControl) {
2959
2960 // status = UpdateWmiInstanceForS0Idle(AddInstance);
2961 // if (!NT_SUCCESS(status)) {
2962 // return status;
2963 // } __REACTOS__
2964
2965 if (Settings->Enabled == WdfUseDefault) {
2966 //
2967 // Read the registry entry for idle enabled if it's the first time.
2968 //
2969 if (firstTime && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
2971
2972 //
2973 // Read registry. If registry value is not found, the value of
2974 // "enabled" remains unchanged
2975 //
2976 ReadRegistryS0Idle(&valueName, &enabled);
2977 }
2978 else {
2979 //
2980 // Use the saved value for idle enabled.
2981 //
2983 }
2984 }
2985
2986 overridable = TRUE;
2987 }
2988 else if (Settings->UserControlOfIdleSettings == IdleDoNotAllowUserControl) {
2989 //
2990 // No user control
2991 //
2992 overridable = FALSE;
2993
2994 // (void) UpdateWmiInstanceForS0Idle(RemoveInstance); __REACTOS__
2995 }
2996
2997 //
2998 // !!!! DO NOT INTRODUCE FAILURES BEYOND THIS POINT !!!!
2999 //
3000 // We should not introduce any failures that are not due to driver errors
3001 // beyond this point. This is because we are going to commit the driver's
3002 // S0-idle settings now and any failure in the midst of that could leave us
3003 // in a bad state. Therefore, all failable code where the failure is beyond
3004 // the driver's control should be placed above this point.
3005 //
3006 // For example, a driver may want wake-from-S0 support, but the device may
3007 // not support it. We already checked for that failure above, before we
3008 // started committing any of the driver's S0-idle settings.
3009 //
3010 // Any failures below this point should only be due to driver errors, i.e.
3011 // the driver incorrectly calling the AssignS0IdleSettings DDI.
3012 //
3013
3014 if (firstTime) {
3017 }
3018
3019 //
3020 // IdleTimeoutType is available only on > 1.9
3021 //
3022#ifndef __REACTOS__
3024 if (firstTime) {
3025 if ((SystemManagedIdleTimeout == Settings->IdleTimeoutType) ||
3027 Settings->IdleTimeoutType)) {
3028 //
3029 // This is the first time S0-idle policy is being specified and
3030 // the caller has asked for the idle timeout to be determined
3031 // by the power manager.
3032 //
3034 m_TimeoutMgmt.UseSystemManagedIdleTimeout(
3036 );
3037 if (!NT_SUCCESS(status)) {
3038 return status;
3039 }
3040 }
3041 } else {
3042 //
3043 // This is not the first time S0-idle policy is being specified.
3044 // Verify that the caller is not trying to change their mind about
3045 // whether the idle timeout is determined by the power manager.
3046 //
3047 BOOLEAN currentlyUsingSystemManagedIdleTimeout;
3048 BOOLEAN callerWantsSystemManagedIdleTimeout;
3049
3050 currentlyUsingSystemManagedIdleTimeout =
3052 UsingSystemManagedIdleTimeout();
3053 callerWantsSystemManagedIdleTimeout =
3054 ((SystemManagedIdleTimeout == Settings->IdleTimeoutType) ||
3055 (SystemManagedIdleTimeoutWithHint == Settings->IdleTimeoutType));
3056
3057 //
3058 // UMDF currently does not implement
3059 // IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable. So
3060 // that method must be called only as part of the second check in
3061 // the "if" statement below. Since UMDF currently does not support
3062 // system managed idle timeout, the first check will always evaluate
3063 // to 'FALSE', so the second check never gets executed for UMDF.
3064 //
3065 if ((callerWantsSystemManagedIdleTimeout !=
3066 currentlyUsingSystemManagedIdleTimeout)
3067 &&
3069 ) {
3070
3074 "A previous call to assign S0-idle policy specified that "
3075 "the idle timeout %s be determined by the power manager. "
3076 "This decision cannot be changed. %!STATUS!",
3077 currentlyUsingSystemManagedIdleTimeout ?
3078 "should" :
3079 "should not",
3080 status);
3082 return status;
3083 }
3084 }
3085 }
3086#endif
3087
3088 if (Settings->IdleCaps == IdleCannotWakeFromS0) {
3089 //
3090 // PowerUpIdleDeviceOnSystemWake field added after v1.7.
3091 // By default KMDF uses an optimization where the device is not powered
3092 // up when resuming from Sx if it is idle. The field
3093 // PowerUpIdleDeviceOnSystemWake is used to turn off this optimization and allow
3094 // device to power up when resuming from Sx. Note that this optimization
3095 // is applicable only for IdleCannotWakeFromS0. In other cases the
3096 // device is always powered up in order to arm for wake.
3097 //
3098 powerUpOnSystemWake =
3100 Settings->PowerUpIdleDeviceOnSystemWake :
3102
3103 switch(powerUpOnSystemWake) {
3104 case WdfTrue:
3108 "Driver turned off S0Idle optimization. Device will be "
3109 "powered up on resume from Sx even when it is idle");
3110 break;
3111 case WdfFalse:
3115 "Driver turned on S0Idle optimization. Device will remain "
3116 "powered off if idle when resuming from Sx");
3117 break;
3118 case WdfUseDefault:
3119 DO_NOTHING();
3120 break;
3121 default:
3122 break;
3123 }
3124 }
3125
3126 if (FALSE ==
3128 {
3129 if (Settings->IdleCaps == IdleUsbSelectiveSuspend) {
3132 m_IdleSettings.UsbSSCapabilityKnown = TRUE;
3133
3134 } else if (Settings->IdleCaps == IdleCanWakeFromS0) {
3135
3137 m_IdleSettings.UsbSSCapabilityKnown = TRUE;
3138 }
3139 }
3140
3141 //
3142 // Wake FromS0Capable is set every time because we want to allow the driver
3143 // to swap between idle wake capable and idle not wake capable. This should
3144 // be allowed so that a scenario similar to the following can be implemented:
3145 //
3146 // a) when the device has an outstanding open, the device should arm itself
3147 // for wake when idle
3148 //
3149 // b) when the device does not have an outstanding open, the device should
3150 // be off and not armed.
3151 //
3152 // The only way to be off is to assign S0 wake settings, so the
3153 // WakeFromS0Capable field must change on each DDI call. This is not a
3154 // problem for the power policy state machine because it evaluates
3155 // WakeFromS0Capable state before enabling of idle. If we are not
3156 // WakeFromS0Capable and USB SS capable (ie a have a torn/unsynchronized
3157 // state) in m_IdleSettings, we will recover from it when processing
3158 // PwrPolS0IdlePolicyChanged in the state machine (b/c this event causes
3159 // both fields to be reevaluated).
3160 //
3162
3164
3166 m_IdleSettings.m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) {
3167 //
3168 // With system managed idle timeout, we don't want to apply an idle
3169 // timeout of our own on top of that. Effectively, our idle timeout is
3170 // 0.
3171 // But we apply a negligibly small timeout value as this allows us to
3172 // keep the same logic in the idle state machine, regardless of whether
3173 // we're using system-managed idle timeout or driver-managed idle
3174 // timeout.
3175 //
3176 if (firstTime) {
3178 m_PowerIdleMachine.m_PowerTimeout.QuadPart =
3179 negliblySmallIdleTimeout;
3180 }
3181
3182 if (SystemManagedIdleTimeoutWithHint == Settings->IdleTimeoutType) {
3183 //
3184 // We save the idle timeout hint, but we don't provide the hint to
3185 // the power framework immediately. This is because currently we may
3186 // or may not be registered with the power framework. Note that
3187 // WdfDeviceAssignS0IdleSettings might get called even when we are
3188 // not registered with the power framework.
3189 //
3190 // Therefore, we provide the hint to the power framework only when
3191 // we get to the WdfDevStatePwrPolStartingDecideS0Wake state. This
3192 // state is a good choice for providing the hint because:
3193 // 1. We know we would be registered with the power framework when
3194 // we are in this state.
3195 // 2. Any change in S0-idle settings causes us to go through this
3196 // state.
3197 //
3199 idleTimeout;
3200 }
3201
3202 } else {
3204 = WDF_REL_TIMEOUT_IN_MS(idleTimeout);
3205 }
3206
3207 //
3208 // If the driver is 1.11 or later, update the bus drivers with the client's
3209 // choice on the topic of D3hot or D3cold.
3210 //
3212 (Settings->ExcludeD3Cold != WdfUseDefault)) {
3214 BOOLEAN enableD3Cold;
3215
3217
3218 switch (Settings->ExcludeD3Cold) {
3219 case WdfFalse:
3220 enableD3Cold = TRUE;
3221 break;
3222 default:
3225 "Invalid tri-state value for ExcludeD3Cold %d",
3226 Settings->ExcludeD3Cold);
3228 case WdfTrue:
3229 enableD3Cold = FALSE;
3230 break;
3231 }
3232
3234 &deviceObject,
3236 enableD3Cold);
3237 }
3238
3240
3241 return STATUS_SUCCESS;
3242}
3243
3247 __in BOOLEAN ArmForWakeIfChildrenAreArmedForWake,
3248 __in BOOLEAN IndicateChildWakeOnParentWake
3249 )
3250/*++
3251
3252Routine Description:
3253
3254 Updates the Sx wake settings for the device. No event is posted to the
3255 state machine because this setting is statically checked when the machine
3256 is entering an Sx state (unlike S0 idle which can be checked at any time).
3257
3258 The first this function is called, the ability to allow the user to control
3259 this setting is set.
3260
3261Arguments:
3262
3263 Settings - the new settings to apply
3264
3265 ArmForWakeIfChildrenAreArmedForWake - Inidicates whether the device
3266 should arm for wake when one or more children are armed for wake
3267
3268 IndicateChildWakeOnParentWake - Indicates whether the device should
3269 propagate the wake status to its children
3270
3271Return Value:
3272
3273 NTSTATUS
3274
3275 --*/
3276{
3277 DEVICE_POWER_STATE dxState;
3279 BOOLEAN overridable, firstTime, enabled;
3280
3281 dxState = PowerDeviceD3;
3282 overridable = FALSE;
3283 firstTime = TRUE;
3284
3285 if (Settings->Enabled == WdfTrue) {
3286 enabled = TRUE;
3287
3288 }
3289 else if (Settings->Enabled == WdfUseDefault) {
3290 enabled = TRUE;
3291
3294
3295 //
3296 // Read registry. If registry value is not found, the value of "enabled"
3297 // remains unchanged
3298 //
3299 ReadRegistrySxWake(&valueName, &enabled);
3300 }
3301 else {
3304 "If registry value WdfDefaultWakeFromSleepState was present, "
3305 "it was not read because DDI WdfDeviceAssignSxWakeSettings "
3306 "was not called at PASSIVE_LEVEL");
3307 }
3308 }
3309 else {
3310 enabled = FALSE;
3311 }
3312
3314 firstTime = FALSE;
3315 }
3316
3319 if (!NT_SUCCESS(status)) {
3320 return status;
3321 }
3322
3323 //
3324 // Do not set m_CapsQueried to TRUE yet because we will do that once we
3325 // know the entire stack has been built we will do the query again.
3326 //
3327 }
3328
3329 if (Settings->DxState == PowerDeviceMaximum) {
3331
3332 //
3333 // Some bus drivers
3334
3335 // incorrectly report DeviceWake=D0 to
3336 // indicate that it does not support wake instead of specifying
3337 // PowerDeviceUnspecified and KMDF ends up requesting
3338 // a D0 irp when going to Dx. The check prevents this bug.
3339 //
3340 if (dxState < PowerDeviceD1 || dxState > PowerDeviceD3) {
3342
3345 "DeviceWake power state reported in device capabilities "
3346 "%!DEVICE_POWER_STATE! indicates that device can not signal a "
3347 "wake event, %!STATUS!",
3348 dxState, status);
3349 return status;
3350 }
3351 }
3352 else {
3353 DEVICE_POWER_STATE dxDeepest;
3354
3355 dxState = Settings->DxState;
3357
3358 if (dxState > dxDeepest) {
3362 "DxState specified by driver %!DEVICE_POWER_STATE! cannot be"
3363 " lighter than lightest available device wake state "
3364 "%!DEVICE_POWER_STATE!, %!STATUS!", dxState,
3365 dxDeepest, status);
3366 return status;
3367 }
3368 }
3369
3370 if (Settings->UserControlOfWakeSettings == WakeAllowUserControl) {
3371
3372 // status = UpdateWmiInstanceForSxWake(AddInstance); __REACTOS__
3373
3374 // if (!NT_SUCCESS(status)) {
3375 // return status;
3376 // }
3377
3378 if (Settings->Enabled == WdfUseDefault) {
3379 //
3380 // Read the registry entry for wake enabled if it's the first time.
3381 //
3382 if (firstTime && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
3384
3385 //
3386 // Read registry. If registry value is not found, the value of
3387 // "enabled" remains unchanged
3388 //
3389 ReadRegistrySxWake(&valueName, &enabled);
3390 }
3391 else {
3392 //
3393 // Use the saved value for wake enabled.
3394 //
3396 }
3397 }
3398
3399 overridable = TRUE;
3400 }
3401 else if (Settings->UserControlOfWakeSettings == WakeDoNotAllowUserControl) {
3402 //
3403 // No user control, just set to enabled
3404 //
3405 overridable = FALSE;
3406
3407 // (void) UpdateWmiInstanceForSxWake(RemoveInstance); __REACTOS__
3408 }
3409
3410 if (firstTime) {
3413
3414 //
3415 // If ArmForWakeIfChildrenAreArmedForWake setting is set to FALSE,
3416 // then we use the legacy framework behavior which did not depend
3417 // on the child device being capable of arming for wake or not.
3418 //
3420 ArmForWakeIfChildrenAreArmedForWake;
3421
3422 //
3423 // If IndicateChildWakeOnParentWake setting is set to FALSE, then
3424 // we use the legacy framework behavior wherein the wake status
3425 // is not propagated from the parent device to the child device.
3426 //
3428 IndicateChildWakeOnParentWake;
3429 }
3430
3432
3434
3435 return STATUS_SUCCESS;
3436}
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3457 __in FxWmiInstanceInternal* /* Instance */,
3458 __in ULONG /* OutBufferSize */,
3461 )
3462{
3463 *((BOOLEAN*) OutBuffer) =
3465 *BufferUsed = sizeof(BOOLEAN);
3466
3467 return STATUS_SUCCESS;
3468}
3469
3473 __in FxWmiInstanceInternal* /* Instance */,
3474 __in ULONG /* InBufferSize */,
3475 __in PVOID InBuffer
3476 )
3477{
3478 BOOLEAN value;
3479
3480
3481 //
3482 // FxWmiIrpHandler makes sure the buffer is at least one byte big, so we
3483 // don't check the buffer size.
3484 //
3485
3486 value = *(PBOOLEAN) InBuffer;
3487
3489
3490 return STATUS_SUCCESS;
3491}
3492
3496 __in FxWmiInstanceInternal* /* Instance */,
3499 __in PVOID InBuffer
3500 )
3501{
3502 BOOLEAN value;
3503
3504 if (DataItemId != 0) {
3506 }
3507
3508 if (InBufferSize < sizeof(BOOLEAN)) {
3510 }
3511
3512 value = *(BOOLEAN*) InBuffer;
3514
3515 return STATUS_SUCCESS;
3516}
3517
3521 __in FxWmiInstanceInternal* /* Instance */,
3522 __in ULONG /* OutBufferSize */,
3525 )
3526{
3527 *((BOOLEAN*) OutBuffer) =
3529 *BufferUsed = sizeof(BOOLEAN);
3530
3531 return STATUS_SUCCESS;
3532}
3533
3537 __in FxWmiInstanceInternal* /* Instance */,
3538 __in ULONG /* InBufferSize */,
3539 __in PVOID InBuffer
3540 )
3541{
3542 BOOLEAN value;
3543
3544 //
3545 // FxWmiIrpHandler makes sure that the buffer is at least one byte big, so
3546 // we don't check the buffer size
3547 //
3548 value = *(PBOOLEAN) InBuffer;
3549
3551
3552 return STATUS_SUCCESS;
3553}
3554
3558 __in FxWmiInstanceInternal* /* Instance */,
3561 __in PVOID InBuffer
3562 )
3563{
3564 BOOLEAN value;
3565
3566 if (DataItemId != 0) {
3568 }
3569
3570 if (InBufferSize < sizeof(BOOLEAN)) {
3572 }
3573
3574 value = *(BOOLEAN*) InBuffer;
3576
3577 return STATUS_SUCCESS;
3578}
3579
3583 __in SYSTEM_POWER_STATE QueryState
3584 )
3585/*++
3586
3587Framework Philosophy Discussion:
3588
3589 WDM sends IRP_MN_QUERY_POWER for system power states (where system power
3590 states are S0-working, S1-light-sleep, S2-deeper-sleep, S3-deepest-sleep,
3591 S4-hibernation, S5-soft-off.) The idea is that, if a driver can't support
3592 a particular state, it fails the query. The problem is that this idea is
3593 horribly broken.
3594
3595 The first problem is that WDM doesn't always send these IRPs. In some
3596 situations, (very low battery, system getting critically hot) WDM will
3597 attempt to preserve user data by sleeping or hibernating, rather than just
3598 crashing. This is good, but it makes a driver writer's life very difficult,
3599 since it means that you have to deal with being told to go to a particular
3600 state even if you think that your device won't be able to deal well with
3601 that state.
3602
3603 The second problem is that, by the time the system is going to sleep, the
3604 user probably isn't still looking at the screen. This is especially true
3605 for laptop computers, as the system is very likely sleeping because the
3606 user closed the clamshell lid. So any attempt to ask the user how to
3607 resolve a situation where a driver doesn't want to go to a low power state
3608 is futile. Furthermore, even when the screen is still available, users
3609 dislike it when they push the sleep button or the power button on their
3610 machines and the machines don't do what they were told to do.
3611
3612 The third problem is related to the second. While there may be completely
3613 legitimate reasons for the driver to want to delay or even to veto a
3614 transition into a sleep state, (an example of a valid scenario would be one
3615 in which the driver was involved in burning a CD, an operation which can't
3616 be interrupted,) there isn't any good way for a driver to interact with a
3617 user anyhow. (Which desktop is the right one to send messages to? What
3618 should the UI for problem resolution look like? How does a driver put up
3619 UI anyhow?)
3620
3621 All the driver really knows is that it will or won't be able to maintain
3622 device state, and it will or won't be able to get enough power to arm
3623 any wake events that it might want to deliver (like PME#.)
3624
3625 Consequently, the designers of the PnP/Power model in the Framework have
3626 decided that all QueryPower-Sx IRPs will be completed successfully
3627 except if the device cannot maintain enough power to trigger its wake
3628 signal *AND* if the system supports lighter sleep states than the
3629 one that is currently being queried. (If it does, then the kernel's power
3630 manager will turn right around and query for those, next.)
3631
3632 This story usually brings up a few objections:
3633
3634 1) My device is important! When it's operating, I don't want
3635 the machine to just fall asleep. I need to fail QueryPower-Sx to
3636 prevent that.
3637
3638 This objection is an unfortunate consequence of the existing DDK. There
3639 is a perfectly good API that allows a driver to say that the machine
3640 shouldn't just fall asleep. (See PoSetSystemState.) If a user presses
3641 a button telling the machine to go to sleep, then the driver has a
3642 responsibility to do that.
3643
3644 2) There are certain operations that just can't be interrupted!
3645
3646 While that's true, those operations started somewhere, probably in user-
3647 mode. Those same user-mode components would be much, much better suited
3648 toward negotiating with the user or with other components to figure out
3649 what to do when the uninterruptable must be interrupted. User-mode
3650 components get notification that the system is going to sleep and they
3651 can delay or veto the transition. Get over the idea that your driver
3652 needs to be involved, too.
3653
3654Routine Description:
3655
3656 Determines if for the passed in System state, if we can wake the machine
3657 from it. If the query state is the machine's minimum system state, then
3658 we always succeed it because we want the machine to go to at least some
3659 sleeping state. We always succeed hibernate and system off requests as well.
3660
3661Arguments:
3662
3663 QueryState - The proposed system state
3664
3665Return Value:
3666
3667 NT_SUCCESS if the queried state should be allowed, !NT_SUCCESS otherwise
3668
3669 --*/
3670{
3671 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
3673
3674 if (QueryState >= PowerSystemHibernate ||
3676 //
3677 // If the query is for the machine's minimum S state or we going into
3678 // hibernate or off, always succeed it.
3679 //
3681 }
3682 else {
3683
3684 //
3685 // On Windows Vista and above, its OK to return a failure status code
3686 // if the system is going into an S state at which the device cannot
3687 // wake the system.
3688 //
3690
3691 //
3692 // The S state the machine is going into is one where we can't
3693 // wake it up because our D state is too low for this S state.
3694 // Since this isn't the minimum S state the machine is capable
3695 // of, reject the current query.
3696 //
3698 FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGPNP,
3699 "failing system query power because the device cannot wake the "
3700 "machine from S%d",
3701 QueryState - 1);
3702
3704 }
3705
3706 return status;
3707}
3708
3709VOID
3712 )
3713{
3717}
3718
3719VOID
3722 )
3723/*++
3724
3725Routine Description:
3726 Sets the wake from Sx state
3727
3728 No need to post an event to the power policy state machine because we
3729 will not change any active due to a change in this setting. We only
3730 evaluate this state when going into Sx and once in this state we will not
3731 change our behavior until the next Sx, which will then evaluate this state.
3732
3733Arguments:
3734 State - New state
3735
3736Return Value:
3737 VOID
3738
3739 --*/
3740{
3743
3744 //
3745 // Since we are not posting an event to the power policy state machine, try
3746 // to write out the value now, otherwise it will be written when we
3747 // transition
3748 //
3752
3753 timeout = 0;
3754
3755 //
3756 // If the lock is already acquired on this thread, this will fail, which
3757 // is OK.
3758 //
3761 &timeout
3762 );
3763
3764 if (FxWaitLockInternal::IsLockAcquired(status)) {
3765 SaveState(TRUE);
3766
3769 );
3770 }
3771 }
3772}
3773
3774VOID
3777 )
3778/*++
3779
3780Routine Description:
3781 Marks the device as a victim of catastrophic failure, either in software
3782 or in hardware.
3783
3784 If AttemptToRestart is TRUE, then we should try to get the stack re-built
3785 after it has been torn down. This would typically be the case the failure
3786 was in the software, and possibly not be the case if the failure was in
3787 the hardware.
3788
3789Arguments:
3790 FailedAction - action to take once the stack has been removed
3791
3792Return Value:
3793 None
3794
3795 --*/
3796{
3798 MdDeviceObject pdo;
3799
3800#if (FX_CORE_MODE == FX_CORE_USER_MODE)
3801 if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(2, 15) == FALSE &&
3803
3807 "WdfDeviceFailedAttemptRestart is only available for UMDF 2.15 "
3808 "and later drivers. Reverting to WdfDeviceFailedNoRestart.");
3809 }
3810#endif
3811
3813
3814 //
3815 // This will cause the PnP manager to tear down this stack, even if
3816 // the PDO can't be surprise-removed.
3817 //
3818 m_Failed = TRUE;
3819
3821 //
3822 // Attempt to get the PDO surprise-removed.
3823 //
3825
3826 if (NT_SUCCESS(status)) {
3827 return;
3828 }
3829 }
3830
3831#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
3832 //
3833 // In between creating a PDO WDFDEVICE and it starting, if this DDI is called,
3834 // we will not have a valid PDO. Make sure it is valid before we proceed.
3835 //
3837
3838 if (pdo != NULL) {
3839 //
3840 // Now tell the PnP manager to re-query us for our state.
3841 //
3842 MxDeviceObject physicalDeviceObject(pdo);
3843
3844 physicalDeviceObject.InvalidateDeviceState(
3846 );
3847 }
3848#else // USER_MODE
3852#endif
3853}
3854
3860 )
3861{
3862 return This->PnpDeviceUsageNotification(Irp);
3863}
3864
3869 )
3870{
3872 FxRelatedDevice *pDependent;
3873 FxAutoIrp relatedIrp(NULL), parentIrp(NULL);
3874 MxDeviceObject topOfParentStack;
3877 MxDeviceObject pAttached;
3878 MdIrp pNewIrp;
3880 BOOLEAN inPath, supported;
3881 ULONG oldFlags;
3882 MxAutoWorkItem workItem;
3883
3885 "Entering DeviceUsageNotification handler");
3886
3888
3889 type = Irp->GetParameterUsageNotificationType();
3890 inPath = Irp->GetParameterUsageNotificationInPath();
3891 supported = FALSE;
3892
3895 "type %x, in path %x, can support paging %x, dump file %x, "
3896 "hiber file %x, boot file %x",
3897 type, inPath,
3902
3903
3906 if (inPath) {
3907 if (m_Device->IsFilter()) {
3908 //
3909 // Filters always support usage notifications
3910 //
3911 supported = TRUE;
3912 }
3913 else {
3914 supported = IsUsageSupported(type);
3915 }
3916 }
3917 else {
3918 //
3919 // We always handle notifications where we are out of the path
3920 //
3921 supported = TRUE;
3922 }
3923 }
3924
3925 if (supported == FALSE) {
3927
3930 "Usage type %x not supported, %!STATUS!", type, status);
3931
3932 return CompletePnpRequest(Irp, status);
3933 }
3934
3935 //
3936 // Usage notification IRP gets forwarded to parent stack or to
3937 // dependent stack. Since in such cases (with deep device tree) the stack
3938 // may run out quickly, ensure there is enough stack, otherwise use a
3939 // workitem.
3940 //
3942 (m_Device->IsPdo() ||
3944
3945 status = workItem.Allocate(m_Device->GetDeviceObject());
3946 if (!NT_SUCCESS(status)) {
3949 "WDFDEVICE %p !devobj %p could not allocate workitem "
3950 "to send usage notification type %d, inpath %d, %!STATUS!",
3953 type, inPath, status);
3954
3955 return CompletePnpRequest(Irp, status);
3956 }
3957 }
3958
3959 //
3960 // Usage notification is supported. Set the flags on the device object
3961 // before processing this any further and save the current flags on the
3962 // device object.
3963 //
3964 oldFlags = SetUsageNotificationFlags(type, inPath);
3965
3966 if (m_Device->IsPdo()) {
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979 topOfParentStack.SetObject(
3981
3982 pNewIrp = FxIrp::AllocateIrp(topOfParentStack.GetStackSize());
3983 if (pNewIrp != NULL) {
3984 parentIrp.SetIrp(pNewIrp);
3985
3986 //
3987 // parentIrp now owns the irp
3988 //
3989 pNewIrp = NULL;
3990
3991 status = SendDeviceUsageNotification(&topOfParentStack,
3992 &parentIrp,
3993 &workItem,
3994 Irp,
3995 FALSE);
3996 }
3997 else {
3999
4002 "WDFDEVICE %p could not allocate PIRP for parent !devobj %p to "
4003 "send usage notification type %d, inpath %d, %!STATUS!",
4004 m_Device->GetHandle(), topOfParentStack.GetObject(),
4005 type, inPath, status);
4006 }
4007 topOfParentStack.DereferenceObject();
4008 topOfParentStack.SetObject(NULL);
4009
4010 if (!NT_SUCCESS(status)) {
4012 "Exit %!STATUS!", status);
4013
4014 RevertUsageNotificationFlags(type, inPath, oldFlags);
4015 return CompletePnpRequest(Irp, status);
4016 }
4017 }
4018
4019 maxStack = 0;
4020 pDependent = NULL;
4021
4022 //
4023 // If the driver supports the given special file, lets notify dependent
4024 // stacks.
4025 //
4026
4027 //
4028 // LockForEnum will lock out new changes to the list until we unlock the list.
4029 // We remain at passive level once we are locked.
4030 //
4032 //
4033 // We capture the m_UsageDependentDeviceList pointer value so that we
4034 // always use the same pointer value and that we have matched actions
4035 // (lock for enum / unlock from enum). What we are trying to avoid is
4036 // this:
4037 // 1) we do not lock for enum because m_UsageDependentDeviceList == NULL
4038 // 2) in the middle of this function, m_UsageDependentDeviceList is
4039 // assigned a pointer value
4040 // 3) we try to unlock from enum later (or iterate, thinking the enum
4041 // lock is held) by checking m_UsageDependentDeviceList for NULL, and
4042 // now that is != NULL, use it.
4043 //
4044 // By capturing the pointer now, we either have a list or not and we don't
4045 // hit situations 2 or 3. So, the rule is every subseqeunt time we need
4046 // to check if there is valid m_UsageDependentDeviceList pointer, we
4047 // use pList, but when we use the list, we can use m_UsageDependentDeviceList
4048 // directly.
4049 //
4051
4053
4054 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4055
4056 MxDeviceObject deviceObject(pDependent->GetDevice());
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4071
4072 if (pAttached.GetStackSize() > maxStack) {
4073 maxStack = pAttached.GetStackSize();
4074 }
4075
4076 pAttached.DereferenceObject();
4077 }
4078 }
4079 else {
4080 pList = NULL;
4081 }
4082
4083 if (maxStack > 0) {
4084 //
4085 // If we have a maxStack size, we have a list as well
4086 //
4088
4089 //
4090 // Allocate one irp for all the stacks so that we don't have an
4091 // allocation later. This way, once we have the irp, we can send the
4092 // usage notification to all stacks reliably, as well as the reverting
4093 // of the notification if we encounter failure.
4094 //
4095 pNewIrp = FxIrp::AllocateIrp(maxStack);
4096 if (pNewIrp == NULL) {
4098
4101 "WDFDEVICE %p could not allocate IRP to send usage notifications"
4102 " to related stacks, type %d, inpath %d, status %!STATUS!",
4103 m_Device->GetHandle(), type, inPath, status);
4104 }
4105 else {
4106 MxDeviceObject dependentDevice;
4107
4108 //
4109 // relatedIrp will free the irp when it goes out of scope
4110 //
4111 relatedIrp.SetIrp(pNewIrp);
4112
4113 //
4114 // Walk our collection of dependent device stacks, and notify
4115 // each stack of the device notification. If any fail, notify
4116 // the stacks who already were told of the reverted behavior.
4117 //
4118 pDependent = NULL;
4119 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4120 dependentDevice.SetObject(pDependent->GetDevice());
4121 status = SendDeviceUsageNotification(&dependentDevice,
4122 &relatedIrp,
4123 &workItem,
4124 Irp,
4125 FALSE);
4126
4127 if (!NT_SUCCESS(status)) {
4128 FxRelatedDevice* pDependent2;
4129
4130 pDependent2 = NULL;
4131
4132 //
4133 // A device failed the device usage notification request.
4134 // Notify the stacks that didn't fail, so they can unwind
4135 // the operation.
4136 //
4137 while ((pDependent2 = m_UsageDependentDeviceList->GetNextEntry(pDependent2)) != NULL &&
4138 pDependent2 != pDependent) {
4139 dependentDevice.SetObject(pDependent2->GetDevice());
4140
4141 //
4142 // We're already in a failure path. We can't do anything
4143 // about yet another failure. So we ignore the return
4144 // value.
4145 //
4146 (void) SendDeviceUsageNotification(&dependentDevice,
4147 &relatedIrp,
4148 &workItem,
4149 Irp,
4150 TRUE);
4151 }
4152
4153 //
4154 // Now break out of our outter loop.
4155 //
4156 break;
4157 }
4158 }
4159 }
4160 }
4161
4162 //
4163 // If we are successful to this point, then send the IRP down the
4164 // stack.
4165 //
4166 if (NT_SUCCESS(status)) {
4167 BOOLEAN referenceSucceeded, sendDown;
4168
4169 referenceSucceeded = FALSE;
4170 sendDown = TRUE;
4171
4172 //
4173 // Make sure the stack is in D0 before sending down the request. This
4174 // will at least guarantee that all devices below this one are in D0
4175 // when the make the transition from power pageable to non or vice versa.
4176 //
4177 if (IsPowerPolicyOwner()) {
4179
4180 if (NT_SUCCESS(status)) {
4181 referenceSucceeded = TRUE;
4182 }
4183 else {
4184 Irp->SetStatus(status);
4185 sendDown = FALSE;
4186 }
4187 }
4188
4189 if (sendDown) {
4190 //
4191 // If we supported the usage, set the status to success, otherwise we
4192 // keep the status in the irp as it arrived to this device
4193 //
4194 if (supported) {
4195 Irp->SetStatus(status);
4196 }
4198 }
4199
4200 //
4201 // Transitioning from a thread which was power pagable to non power
4202 // pagable. We now need a power thread for the stack, ask for it.
4203 // Note that there is no need for power thread in case of "boot"
4204 // notification since boot notification doesn't require clearing device's
4205 // DO_POWER_PAGABLE flag (power thread is required when handling power
4206 // irp at dispatch level which can happen if the DO_POWER_PAGABLE flag
4207 // is cleared).
4208 //
4209 // NOTE: Once we have a power thread, we never go back to using work
4210 // items even though the stack may revert to power pagable.
4211 // This is an acceptable tradeoff between resource usage and
4212 // WDF complexity.
4213 //
4214 //
4215 if (NT_SUCCESS(status) &&
4216 inPath &&
4217 (HasPowerThread() == FALSE) &&
4219 ) {
4221
4222 if (!NT_SUCCESS(status)) {
4223 //
4224 // Keep status the same through out so we can set it back in
4225 // the irp when we are done.
4226 //
4227 if (m_Device->IsPdo()) {
4228 //
4229 // need to revert our parent's stack
4230 //
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243 topOfParentStack.SetObject(
4245
4246 //
4247 // Ignore the status because we can't do anything on failure
4248 //
4249 (void) SendDeviceUsageNotification(&topOfParentStack,
4250 &parentIrp,
4251 &workItem,
4252 Irp,
4253 TRUE);
4254
4255 topOfParentStack.DereferenceObject();
4256 }
4257 else {
4258 //
4259 // Notify the stack below us
4260 //
4261 Irp->CopyCurrentIrpStackLocationToNext();
4262 Irp->SetParameterUsageNotificationInPath(FALSE);
4263
4264 //
4265 // Required for pnp irps
4266 //
4267 Irp->SetStatus(STATUS_NOT_SUPPORTED);
4268
4269 //
4270 // Ignore the status because we can't do anything on failure
4271 //
4272 (void) Irp->SendIrpSynchronously(m_Device->GetAttachedDevice());
4273 }
4274
4275 Irp->SetStatus(status);
4276 }
4277 }
4278
4279 //
4280 // Now check whether the lower devices succeeded or failed. If they
4281 // failed, back out our changes and propogate the failure.
4282 //
4283 if (!NT_SUCCESS(status)) {
4284 //
4285 // Revert the flags set on the device object.
4286 //
4287 RevertUsageNotificationFlags(type, inPath, oldFlags);
4288
4289 //
4290 // Notify dependent stacks of the failure.
4291 //
4292 pDependent = NULL;
4293
4294 //
4295 // See pList initiatilazation as to why we compare pList for != NULL
4296 // and not m_UsageDependentDeviceList.
4297 //
4298 if (pList != NULL) {
4299 MxDeviceObject dependentDevice;
4300
4301 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4302 dependentDevice.SetObject(pDependent->GetDevice());
4303
4304 //
4305 // We're already in a failure path. We can't do anything
4306 // about yet another failure. So we ignore the return value.
4307 //
4308 (void) SendDeviceUsageNotification(&dependentDevice,
4309 &relatedIrp,
4310 &workItem,
4311 Irp,
4312 TRUE);
4313 }
4314 }
4315 }
4316
4317 //
4318 // By this point, we have propagated the notification to dependent devices
4319 // and lower stack, and if anyone failed during that time, we also
4320 // propagated failure to dependent stacks and lower stack.
4321 // If status is success at this point, invoke the driver's callback.
4322 //
4323 if (NT_SUCCESS(status)) {
4324 //
4325 // Invoke callback. Note that only one of the callbacks
4326 // DeviceUsageNotification or DeviceUsgeNotificationEx will get
4327 // invoked since only one of the callbacks at a time is supported.
4328 // We ensured that during registration of the callback.
4329 // Note that Ex callback will return success if driver did not
4330 // supply any callback.
4331 //
4334 inPath);
4335
4339 inPath
4340 );
4341
4342 if (!NT_SUCCESS(status)) {
4343 //
4344 // Driver's callback returned failure. We need to propagate
4345 // failure to lower stack and dependent stacks.
4346 //
4347 //
4348 // Keep status the same through out so we can set it back in
4349 // the irp when we are done.
4350 //
4351 if (m_Device->IsPdo()) {
4352 //
4353 // need to revert our parent's stack
4354 //
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367 topOfParentStack.SetObject(
4369
4370 //
4371 // Ignore the status because we can't do anything on failure
4372 //
4373 (void) SendDeviceUsageNotification(&topOfParentStack,
4374 &parentIrp,
4375 &workItem,
4376 Irp,
4377 TRUE);
4378
4379 topOfParentStack.DereferenceObject();
4380 }
4381 else {
4382 //
4383 // Notify the stack below us
4384 //
4385 Irp->CopyCurrentIrpStackLocationToNext();
4386 Irp->SetParameterUsageNotificationInPath(FALSE);
4387
4388 //
4389 // Required for pnp irps
4390 //
4391 Irp->SetStatus(STATUS_NOT_SUPPORTED);
4392
4393 //
4394 // Ignore the status because we can't do anything on failure
4395 //
4396 (void) Irp->SendIrpSynchronously(m_Device->GetAttachedDevice());
4397 }
4398
4399 Irp->SetStatus(status);
4400
4401 //
4402 // Revert the flags set on the device object.
4403 //
4404 RevertUsageNotificationFlags(type, inPath, oldFlags);
4405
4406 //
4407 // Notify dependent stacks of the failure.
4408 //
4409 pDependent = NULL;
4410
4411 //
4412 // See pList initiatilazation as to why we compare pList for != NULL
4413 // and not m_UsageDependentDeviceList.
4414 //
4415 if (pList != NULL) {
4416 MxDeviceObject dependentDevice;
4417
4418 while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4419 dependentDevice.SetObject(pDependent->GetDevice());
4420
4421 //
4422 // We're already in a failure path. We can't do anything
4423 // about yet another failure. So we ignore the return value.
4424 //
4425 (void) SendDeviceUsageNotification(&dependentDevice,
4426 &relatedIrp,
4427 &workItem,
4428 Irp,
4429 TRUE);
4430 }
4431 }
4432 }
4433
4434 if (NT_SUCCESS(status)) {
4435
4436 CommitUsageNotification(type, oldFlags);
4437
4438 //
4439 // If we are in the dump file path, we cannot idle out because we
4440 // can experience a crash dump at any time.
4441 //
4443 //
4444 // Add a reference everytime we are notified of being in the
4445 // path, no need to match the first inPath notification and the
4446 // last !inPath notification.
4447 //
4448 if (inPath) {
4449 NTSTATUS refStatus;
4450
4452
4453 //
4454 // Since our previous synchronous power reference succeeded,
4455 // an addtional reference while we are powered up should
4456 // never fail.
4457 //
4458 refStatus = PowerReference(FALSE);
4459#if DBG
4460 ASSERT(NT_SUCCESS(refStatus));
4461#else
4462 UNREFERENCED_PARAMETER(refStatus);
4463#endif
4464 }
4465 else {
4466 ASSERT(GetUsageCount(type) >= 0);
4468 }
4469 }
4470 }
4471 }
4472
4473 //
4474 // We no longer need to be in D0 if we don't have to be.
4475 //
4476 if (referenceSucceeded) {
4479 }
4480 }
4481
4482 //
4483 // See pList initiatilazation as to why we compare pList for != NULL
4484 // and not m_UsageDependentDeviceList.
4485 //
4486 if (pList != NULL) {
4488 }
4489
4491 "Exit %!STATUS!", status);
4492
4493 return CompletePnpRequest(Irp, status);
4494}
4495
4496ULONG
4499 __in BOOLEAN InPath
4500 )
4501/*++
4502
4503Routine Description:
4504
4505 This routine sets the usage notification flags on the device object (for
4506 non-boot usages) and updates the special file usage count .
4507
4508Arguments:
4509
4510 Type - the special file type - paging, hibernate, dump or boot file.
4511
4512 InPath - indicates whether the system is creating or removing the special
4513 file on the device.
4514
4515Return Value:
4516
4517 Returns the old flags on the device object.
4518
4519--*/
4520{
4521 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4522 ULONG oldFlags, newFlags;
4523
4524 oldFlags = m_Device->GetDeviceObjectFlags();
4525
4526 //
4527
4528 //
4530 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
4531 "Before: type %d, in path %d, special count %d, flags 0x%x, "
4532 "device %p (WDFDEVICE %p), is pageable capable %d",
4533 Type, InPath, GetUsageCount(Type), oldFlags,
4536
4537 //
4538 // Adjust our "special file count".
4539 //
4540 AdjustUsageCount(Type, InPath);
4541
4542 //
4543 // Boot notification doesn't require updating device flags.
4544 //
4546 return oldFlags;
4547 }
4548
4549 if (m_Device->IsFilter()) {
4550 //
4551 // Clear the previous flags and reset them to the attached
4552 // device's flags
4553 //
4554 newFlags = oldFlags & ~(DO_POWER_PAGABLE | DO_POWER_INRUSH);
4555 newFlags |= m_Device->GetAttachedDeviceObjectFlags() &
4557 m_Device->SetDeviceObjectFlags(newFlags);
4558 }
4559 else {
4560 if (InPath) {
4562 m_Device->GetDeviceObjectFlags() & ~DO_POWER_PAGABLE
4563 );
4564 }
4565 else {
4569 );
4570 }
4571 }
4572 }
4573
4574 return oldFlags;
4575}
4576
4577VOID
4580 __in BOOLEAN InPath,
4582 )
4583/*++
4584
4585Routine Description:
4586
4587 This routine reverts the usage notification flags to the old flags on
4588 the device object and updates the special file usage count.
4589
4590Arguments:
4591
4592 Type - the special file type - paging, hibernate or dump file.
4593
4594 InPath - indicates whether the system is creating or removing the special
4595 file on the device.
4596
4597 OldFlags - the previous flags on the device object.
4598
4599--*/
4600{
4601 //
4602 // Re-adjust our "special file count".
4603 //
4604 InPath = !InPath;
4605 AdjustUsageCount(Type, InPath);
4606
4607 //
4608 // Restore the flags on the device object.
4609 //
4611}
4612
4613VOID
4617 )
4618/*++
4619
4620Routine Description:
4621
4622 This routine commits the usage notification flags on the device object
4623 and invokes the usage notification callbacks. If the current flags on
4624 the device object indicates that there was a transition from power-pagable
4625 to non power-pagable, or vice-versa, then an event is posted to the power
4626 state machine to notify it of the change. After this routine is called
4627 the PNP manager will no longer be able to disable the device.
4628
4629Arguments:
4630
4631 Type - the special file type - paging, hibernation or crash dump file.
4632
4633 InPath - indicates whether the system is creating or removing the special
4634 file on the device.
4635
4636 OldFlags - the previous flags on the device object.
4637
4638--*/
4639{
4640 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4641 ULONG newFlags;
4642
4643 newFlags = m_Device->GetDeviceObjectFlags();
4644
4646 (newFlags & DO_POWER_PAGABLE) == 0) {
4647 //
4648 // We transitioned from a power pageable to a non power pageable
4649 // device. Move the power state machine to the appropriate
4650 // state.
4651 //
4653 }
4654
4655 if ((OldFlags & DO_POWER_PAGABLE) == 0 &&
4656 (newFlags & DO_POWER_PAGABLE) == DO_POWER_PAGABLE) {
4657 //
4658 // We transitioned from a non power pageable to a power pageable
4659 // device. Move the power state machine to the appropriate
4660 // state.
4661 //
4663 }
4664
4665 //
4666 // Notify PNP that it should no longer be able
4667 // to disable this device.
4668 //
4669 MxDeviceObject physicalDeviceObject(
4671 );
4672 physicalDeviceObject.InvalidateDeviceState(
4674 );
4675
4677 FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
4678 "After: special count %d, flags 0x%x, device %p (WDFDEVICE %p)",
4679 GetUsageCount(Type), newFlags,
4681}
4682
4687 )
4688{
4689 FxRelatedDevice* pRelated;
4691
4693 KIRQL irql;
4694
4695 Lock(&irql);
4698
4701 }
4702 else {
4704
4707 "Could not allocate usage device list for WDFDEVICE %p, "
4708 "%!STATUS!", m_Device->GetHandle(), status);
4709 }
4710
4711 }
4712 else {
4713 //
4714 // another thread allocated the list already
4715 //
4717 }
4718 Unlock(irql);
4719
4720 if (!NT_SUCCESS(status)) {
4721 return status;
4722 }
4723 }
4724
4725 pRelated = new(GetDriverGlobals())
4727
4728 if (pRelated == NULL) {
4730 }
4731
4733
4734 if (!NT_SUCCESS(status)) {
4735 pRelated->DeleteFromFailedCreate();
4736 }
4737
4738 return status;
4739}
4740
4741VOID
4744 )
4745{
4748 }
4749}
4750
4755 )
4756{
4757 FxRelatedDevice* pRelated;
4759
4760 if (m_RemovalDeviceList == NULL) {
4761 KIRQL irql;
4762
4763 Lock(&irql);
4764 if (m_RemovalDeviceList == NULL) {
4766
4767 if (m_RemovalDeviceList != NULL) {
4769 }
4770 else {
4772
4775 "Could not allocate removal device list for WDFDEVICE %p, "
4776 "%!STATUS!", m_Device->GetHandle(), status);
4777 }
4778 }
4779 else {
4780 //
4781 // another thread allocated the list already
4782 //
4784 }
4785 Unlock(irql);
4786
4787 if (!NT_SUCCESS(status)) {
4788 return status;
4789 }
4790 }
4791
4792 pRelated = new(GetDriverGlobals())
4794 if (pRelated == NULL) {
4796 }
4797
4799
4800 if (NT_SUCCESS(status)) {
4801 //
4802 // RemovalRelations are queried automatically by PnP when the device is
4803 // going to be query removed. No need to tell pnp that the list changed
4804 // until it needs to query for it.
4805 //
4806 DO_NOTHING();
4807 }
4808 else {
4809 pRelated->DeleteFromFailedCreate();
4810 }
4811
4812 return status;
4813}
4814
4815VOID
4818 )
4819{
4820 if (m_RemovalDeviceList != NULL) {
4822 }
4823
4824 //
4825 // RemovalRelations are queried automatically by PnP when the device is
4826 // going to be query removed. No need to tell pnp that the list changed
4827 // until it needs to query for it.
4828 //
4829}
4830
4831VOID
4833 VOID
4834 )
4835{
4837
4838 if (m_RemovalDeviceList == NULL) {
4839 return;
4840 }
4841
4845 }
4847
4848 //
4849 // RemovalRelations are queried automatically by PnP when the device is
4850 // going to be query removed. No need to tell pnp that the list changed
4851 // until it needs to query for it.
4852 //
4853}
4854
4855VOID
4857 VOID
4858 )
4859/*++
4860
4861Routine Description:
4862 Sets the failure field and then optionally invalidates the device state.
4863
4864Arguments:
4865 InvalidateState - If TRUE, the state is invalidated
4866
4867Return Value:
4868 None
4869
4870 --*/
4871{
4873
4874 MxDeviceObject physicalDeviceObject(
4876 );
4877 physicalDeviceObject.InvalidateDeviceState(
4879 );
4880}
4881
4882VOID
4884 __inout FxIrp* Irp,
4885 __in BOOLEAN MarkIrpPending
4886 )
4887{
4888 if (m_PendingPnPIrp != NULL ) {
4889 FxIrp pendingIrp(m_PendingPnPIrp);
4890
4891 //
4892 // A state changing pnp irp is already pended. If we don't bugcheck
4893 // the pended pnp irp will be overwritten with new pnp irp and the old
4894 // one may never get completed, which may have drastic implications (
4895 // unresponsive system, power manager not sending Sx Irp etc.)
4896 //
4898 "A new state changing pnp irp %!pnpmn! IRP %p arrived while another "
4899 "pnp irp %!pnpmn! IRP %p is still pending WDFDEVICE %p\n",
4900 Irp->GetMinorFunction(), Irp->GetIrp(),
4901 pendingIrp.GetMinorFunction(),pendingIrp.GetIrp(),
4902 m_Device->GetHandle());
4903
4905 WDF_PNP_FATAL_ERROR, // specific type
4906 (ULONG_PTR)m_Device->GetHandle(), //parm 2
4907 (ULONG_PTR)Irp->GetIrp()); // parm 3
4908
4909 /* NOTREACHED */
4910 return;
4911 }
4912 if (MarkIrpPending) {
4913 Irp->MarkIrpPending();
4914 }
4915 m_PendingPnPIrp = Irp->GetIrp();
4916}
4917
4921 VOID
4922 )
4923{
4924 KIRQL irql;
4926
4927 if (m_EnumInfo != NULL) {
4928 return STATUS_SUCCESS;
4929 }
4930
4931 Lock(&irql);
4932 if (m_EnumInfo == NULL) {
4934
4935 if (m_EnumInfo != NULL) {
4937
4938 if (!NT_SUCCESS(status)) {
4939 delete m_EnumInfo;
4940 m_EnumInfo = NULL;
4941
4943 TRACINGPNP,
4944 "Could not initialize enum info for "
4945 "WDFDEVICE %p, %!STATUS!",
4947 }
4948
4949 }
4950 else {
4952
4954 "Could not allocate enum info for WDFDEVICE %p, "
4955 "%!STATUS!", m_Device->GetHandle(), status);
4956 }
4957 }
4958 else {
4959 //
4960 // another thread allocated the list already
4961 //
4963 }
4964 Unlock(irql);
4965
4966 return status;
4967}
4968
4969VOID
4972 )
4973{
4975 "Adding FxChildList %p, WDFCHILDLIST %p", List,
4976 List->GetHandle());
4977
4979 &List->m_TransactionLink);
4980}
4981
4982VOID
4985 )
4986{
4988 "Removing FxChildList %p, WDFCHILDLIST %p", List,
4989 List->GetHandle());
4990
4991 m_EnumInfo->m_ChildListList.Remove(GetDriverGlobals(), &List->m_TransactionLink);
4992
4993 //
4994
4995 //
4996}
4997
4998VOID
5000 __inout PLONG PendingCount
5001 )
5002{
5004
5005 ple = NULL;
5006
5007 if (m_EnumInfo != NULL) {
5011 }
5013 }
5014}
5015
5016VOID
5020 )
5