1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxPkgFdo.cpp
8 
9 Abstract:
10 
11     This module implements the pnp/power package for the driver
12     framework.
13 
14 Author:
15 
16 
17 
18 Environment:
19 
20     Both kernel and user mode
21 
22 Revision History:
23 
24 
25 
26 
27 --*/
28 
29 #include "pnppriv.hpp"
30 
31 
32 //#include <FxIoTarget.hpp>
33 
34 #include <initguid.h>
35 #include <wdmguid.h>
36 
37 #if defined(EVENT_TRACING)
38 // Tracing support
39 extern "C" {
40 #include "fxpkgfdo.tmh"
41 }
42 #endif
43 
44 struct FxFilteredStartContext : public FxStump {
FxFilteredStartContextFxFilteredStartContext45     FxFilteredStartContext(
46         VOID
47         )
48     {
49         ResourcesRaw = NULL;
50         ResourcesTranslated = NULL;
51     }
52 
~FxFilteredStartContextFxFilteredStartContext53     ~FxFilteredStartContext()
54     {
55         if (ResourcesRaw != NULL) {
56             MxMemory::MxFreePool(ResourcesRaw);
57         }
58         if (ResourcesTranslated != NULL) {
59             MxMemory::MxFreePool(ResourcesTranslated);
60         }
61     }
62 
63     FxPkgFdo* PkgFdo;
64 
65     PCM_RESOURCE_LIST ResourcesRaw;
66 
67     PCM_RESOURCE_LIST ResourcesTranslated;
68 };
69 
70 const PFN_PNP_POWER_CALLBACK FxPkgFdo::m_FdoPnpFunctionTable[IRP_MN_SURPRISE_REMOVAL + 1] =
71 {
72     _PnpStartDevice,                // IRP_MN_START_DEVICE
73     _PnpQueryRemoveDevice,          // IRP_MN_QUERY_REMOVE_DEVICE
74     _PnpRemoveDevice,               // IRP_MN_REMOVE_DEVICE
75     _PnpCancelRemoveDevice,         // IRP_MN_CANCEL_REMOVE_DEVICE
76     _PnpStopDevice,                 // IRP_MN_STOP_DEVICE
77     _PnpQueryStopDevice,            // IRP_MN_QUERY_STOP_DEVICE
78     _PnpCancelStopDevice,           // IRP_MN_CANCEL_STOP_DEVICE
79 
80     _PnpQueryDeviceRelations,       // IRP_MN_QUERY_DEVICE_RELATIONS
81     _PnpQueryInterface,             // IRP_MN_QUERY_INTERFACE
82     _PnpQueryCapabilities,          // IRP_MN_QUERY_CAPABILITIES
83     _PnpPassDown,                   // IRP_MN_QUERY_RESOURCES
84     _PnpPassDown,                   // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
85     _PnpPassDown,                   // IRP_MN_QUERY_DEVICE_TEXT
86     _PnpFilterResourceRequirements, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
87 
88     _PnpPassDown,                   // 0x0E
89 
90     _PnpPassDown,                   // IRP_MN_READ_CONFIG
91     _PnpPassDown,                   // IRP_MN_WRITE_CONFIG
92     _PnpPassDown,                   // IRP_MN_EJECT
93     _PnpPassDown,                   // IRP_MN_SET_LOCK
94     _PnpPassDown,                   // IRP_MN_QUERY_ID
95     _PnpQueryPnpDeviceState,        // IRP_MN_QUERY_PNP_DEVICE_STATE
96     _PnpPassDown,                   // IRP_MN_QUERY_BUS_INFORMATION
97     _PnpDeviceUsageNotification,    // IRP_MN_DEVICE_USAGE_NOTIFICATION
98     _PnpSurpriseRemoval,            // IRP_MN_SURPRISE_REMOVAL
99 
100 };
101 
102 const PFN_PNP_POWER_CALLBACK FxPkgFdo::m_FdoPowerFunctionTable[IRP_MN_QUERY_POWER + 1] =
103 {
104     _DispatchWaitWake,      // IRP_MN_WAIT_WAKE
105     _PowerPassDown,         // IRP_MN_POWER_SEQUENCE
106     _DispatchSetPower,      // IRP_MN_SET_POWER
107     _DispatchQueryPower,    // IRP_MN_QUERY_POWER
108 };
109 
110 //#if defined(ALLOC_PRAGMA)
111 //#pragma code_seg("PAGE")
112 //#endif
113 
FxPkgFdo(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in CfxDevice * Device)114 FxPkgFdo::FxPkgFdo(
115     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
116     __in CfxDevice *Device
117     ) :
118     FxPkgPnp(FxDriverGlobals, Device, FX_TYPE_PACKAGE_FDO)
119 /*++
120 
121 Routine Description:
122 
123     This is the constructor for the FxPkgFdo.  Don't do any initialization
124     that might fail here.
125 
126 Arguments:
127 
128     none
129 
130 Returns:
131 
132     none
133 
134 --*/
135 
136 {
137     m_DefaultDeviceList = NULL;
138     m_StaticDeviceList = NULL;
139 
140     m_DefaultTarget = NULL;
141     m_SelfTarget = NULL;
142 
143     m_BusEnumRetries = 0;
144 
145     //
146     // Since we will always have a valid PDO when we are the FDO, we can do
147     // any device interface related activity at any time
148     //
149     m_DeviceInterfacesCanBeEnabled = TRUE;
150 
151     m_Filter = FALSE;
152 
153     RtlZeroMemory(&m_BusInformation, sizeof(m_BusInformation));
154 
155     RtlZeroMemory(&m_SurpriseRemoveAndReenumerateSelfInterface,
156         sizeof(m_SurpriseRemoveAndReenumerateSelfInterface));
157 }
158 
~FxPkgFdo(VOID)159 FxPkgFdo::~FxPkgFdo(
160     VOID
161     )
162 /*++
163 
164 Routine Description:
165 
166     This is the destructor for the FxPkgFdo
167 
168 Arguments:
169 
170     none
171 
172 Returns:
173 
174     none
175 
176 --*/
177 
178 {
179     if (m_DefaultDeviceList != NULL) {
180         m_DefaultDeviceList->RELEASE(this);
181     }
182     if (m_StaticDeviceList != NULL) {
183         m_StaticDeviceList->RELEASE(this);
184     }
185     if (m_SelfTarget != NULL) {
186         m_SelfTarget->RELEASE(this);
187     }
188     if (m_DefaultTarget != NULL) {
189         m_DefaultTarget->RELEASE(this);
190     }
191 }
192 
193 _Must_inspect_result_
194 NTSTATUS
_Create(__in PFX_DRIVER_GLOBALS DriverGlobals,__in CfxDevice * Device,__deref_out FxPkgFdo ** PkgFdo)195 FxPkgFdo::_Create(
196     __in PFX_DRIVER_GLOBALS DriverGlobals,
197     __in CfxDevice * Device,
198     __deref_out FxPkgFdo ** PkgFdo
199     )
200 {
201     NTSTATUS status;
202     FxPkgFdo * fxPkgFdo;
203     FxEventQueue *eventQueue;
204 
205     fxPkgFdo = new(DriverGlobals) FxPkgFdo(DriverGlobals, Device);
206 
207     if (NULL == fxPkgFdo) {
208         status = STATUS_INSUFFICIENT_RESOURCES;
209         DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
210                             "Memory allocation failed: %!STATUS!", status);
211         return status;
212     }
213 
214     //
215     // Initialize the event queues in the PnP, power and power policy state
216     // machines
217     //
218     eventQueue = static_cast<FxEventQueue*> (&(fxPkgFdo->m_PnpMachine));
219     status = eventQueue->Initialize(DriverGlobals);
220     if (!NT_SUCCESS(status)) {
221         goto exit;
222     }
223 
224     eventQueue = static_cast<FxEventQueue*> (&(fxPkgFdo->m_PowerMachine));
225     status = eventQueue->Initialize(DriverGlobals);
226     if (!NT_SUCCESS(status)) {
227         goto exit;
228     }
229 
230     eventQueue = static_cast<FxEventQueue*> (&(fxPkgFdo->m_PowerPolicyMachine));
231     status = eventQueue->Initialize(DriverGlobals);
232     if (!NT_SUCCESS(status)) {
233         goto exit;
234     }
235 
236     *PkgFdo = fxPkgFdo;
237 
238 exit:
239     if (!NT_SUCCESS(status)) {
240         fxPkgFdo->DeleteFromFailedCreate();
241     }
242 
243     return status;
244 }
245 
246 _Must_inspect_result_
247 NTSTATUS
SendIrpSynchronously(__inout FxIrp * Irp)248 FxPkgFdo::SendIrpSynchronously(
249     __inout FxIrp* Irp
250     )
251 
252 /*++
253 
254 Routine Description:
255 
256     Helper function that makes it easy to handle events which need to be
257     done as an IRP comes back up the stack.
258 
259 Arguments:
260 
261     Irp - The request
262 
263 Returns:
264 
265     results from IoCallDriver
266 
267 --*/
268 
269 {
270     Irp->CopyCurrentIrpStackLocationToNext();
271     return Irp->SendIrpSynchronously(m_Device->GetAttachedDevice());
272 }
273 
274 _Must_inspect_result_
275 NTSTATUS
FireAndForgetIrp(__inout FxIrp * Irp)276 FxPkgFdo::FireAndForgetIrp(
277     __inout FxIrp *Irp
278     )
279 
280 /*++
281 
282 Routine Description:
283 
284     Virtual override which sends the request down the stack and forgets about it.
285 
286 Arguments:
287 
288     Irp - The request
289 
290 Returns:
291 
292     results from IoCallDriver
293 
294 --*/
295 
296 {
297     if (Irp->GetMajorFunction() == IRP_MJ_POWER) {
298         return _PowerPassDown(this, Irp);
299     }
300     else {
301         return _PnpPassDown(this, Irp);
302     }
303 }
304 
305 _Must_inspect_result_
306 NTSTATUS
_PnpPassDown(__in FxPkgPnp * This,__inout FxIrp * Irp)307 FxPkgFdo::_PnpPassDown(
308     __in FxPkgPnp* This,
309     __inout FxIrp* Irp
310     )
311 /*++
312 
313 Routine Description:
314     Functionally equivalent to FireAndForgetIrp except this isn't a virtual
315     call
316 
317 Arguments:
318     Irp - The request
319 
320 Return Value:
321     result from IoCallDriver
322 
323   --*/
324 {
325     NTSTATUS status;
326     FxDevice* device;
327     MdIrp pIrp;
328 
329     device = ((FxPkgFdo*)This)->m_Device;
330     pIrp = Irp->GetIrp();
331 
332     Irp->CopyCurrentIrpStackLocationToNext();
333     status = Irp->CallDriver(
334         ((FxPkgFdo*)This)->m_Device->GetAttachedDevice());
335 
336     Mx::MxReleaseRemoveLock(device->GetRemoveLock(),
337                             pIrp
338                             );
339 
340     return status;
341 }
342 
343 _Must_inspect_result_
344 NTSTATUS
_PnpSurpriseRemoval(__inout FxPkgPnp * This,__inout FxIrp * Irp)345 FxPkgFdo::_PnpSurpriseRemoval(
346     __inout FxPkgPnp* This,
347     __inout FxIrp *Irp
348     )
349 /*++
350 
351 Routine Description:
352 
353     This method is called in response to a PnP SurpriseRemoval IRP.
354 
355 Arguments:
356 
357     Device - a pointer to the FxDevice
358 
359     Irp - a pointer to the FxIrp
360 
361 Returns:
362 
363     NTSTATUS
364 
365 --*/
366 {
367     return ((FxPkgFdo*) This)->PnpSurpriseRemoval(Irp);
368 }
369 
370 _Must_inspect_result_
371 NTSTATUS
_PnpQueryDeviceRelations(__inout FxPkgPnp * This,__inout FxIrp * Irp)372 FxPkgFdo::_PnpQueryDeviceRelations(
373     __inout FxPkgPnp* This,
374     __inout FxIrp *Irp
375     )
376 /*++
377 
378 Routine Description:
379 
380     This method is called in response to a PnP QDR.
381 
382 Arguments:
383 
384     Device - a pointer to the FxDevice
385 
386     Irp - a pointer to the FxIrp
387 
388 Returns:
389 
390     NTSTATUS
391 
392 --*/
393 {
394     return ((FxPkgFdo*) This)->PnpQueryDeviceRelations(Irp);
395 }
396 
397 _Must_inspect_result_
398 NTSTATUS
PnpQueryDeviceRelations(__inout FxIrp * Irp)399 FxPkgFdo::PnpQueryDeviceRelations(
400     __inout FxIrp *Irp
401     )
402 
403 /*++
404 
405 Routine Description:
406 
407     This routine is called in response to a QueryDeviceRelations IRP.
408 
409 Arguments:
410 
411     Device - a pointer to the FxDevice
412 
413     Irp - a pointer to the FxIrp
414 
415 Returns:
416 
417     NSTATUS
418 
419 --*/
420 
421 {
422     NTSTATUS status;
423     DEVICE_RELATION_TYPE type;
424 
425     type = Irp->GetParameterQDRType();
426 
427     DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
428                         "Entering QueryDeviceRelations handler, "
429                         "type %!DEVICE_RELATION_TYPE!",
430                         type);
431 
432     status = STATUS_SUCCESS;
433 
434 
435     //
436     // Set up the type of relations.
437     //
438     switch (type) {
439     case BusRelations:
440         status = HandleQueryBusRelations(Irp);
441 
442         //
443         // STATUS_NOT_SUPPORTED is a special value. It means that
444         // HandleQueryBusRelations did not modify the irp at all and it should
445         // be sent off as is.
446         //
447         if (status == STATUS_NOT_SUPPORTED) {
448             //
449             // We set status to STATUS_SUCCESS so that we send the requqest down
450             // the stack in the comparison below.
451             //
452             status = STATUS_SUCCESS;
453         }
454         break;
455 
456     case RemovalRelations:
457         status = HandleQueryDeviceRelations(Irp, m_RemovalDeviceList);
458 
459         //
460         // STATUS_NOT_SUPPORTED is a special value. It means that
461         // HandleQueryDeviceRelations did not modify the irp at all and it should
462         // be sent off as is.
463         //
464         if (status == STATUS_NOT_SUPPORTED) {
465             //
466             // We set status to STATUS_SUCCESS so that we send the requqest down
467             // the stack in the comparison below.
468             //
469             status = STATUS_SUCCESS;
470         }
471         break;
472     }
473 
474     if (NT_SUCCESS(status)) {
475         status = _PnpPassDown(this, Irp);
476     }
477     else {
478         CompletePnpRequest(Irp, status);
479     }
480 
481     DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
482                         "Exiting QueryDeviceRelations handler, status %!STATUS!",
483                         status);
484 
485     return status;
486 }
487 
488 _Must_inspect_result_
489 NTSTATUS
_PnpQueryInterface(__inout FxPkgPnp * This,__inout FxIrp * Irp)490 FxPkgFdo::_PnpQueryInterface(
491     __inout FxPkgPnp* This,
492     __inout FxIrp *Irp
493     )
494 /*++
495 
496 Routine Description:
497 
498     This method is invoked in response to a Pnp QueryInterface IRP.
499 
500 Arguments:
501 
502     This - The package
503 
504     Irp - a pointer to the FxIrp
505 
506 Returns:
507 
508     NTSTATUS
509 
510 --*/
511 {
512     FxPkgFdo* pThis;
513     NTSTATUS status;
514     BOOLEAN completeIrp;
515 
516     pThis = (FxPkgFdo*) This;
517 
518     DoTraceLevelMessage(pThis->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
519                         "Entering QueryInterface handler");
520 
521     status = pThis->HandleQueryInterface(Irp, &completeIrp);
522 
523     DoTraceLevelMessage(pThis->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
524                         "Exiting QueryInterface handler, %!STATUS!",
525                         status);
526     //
527     // If we understand the irp, we'll complete it.  Otherwise we
528     // pass it down.
529     //
530     if (completeIrp == FALSE) {
531         status = _PnpPassDown(pThis, Irp);
532     }
533     else {
534         Irp->SetInformation(NULL);
535         pThis->CompletePnpRequest(Irp, status);
536     }
537 
538     //
539     // Remlock is released in _PnpPassDown and  CompletePnpRequest. If this
540     // irp is racing with remove on another thread, it's possible for the device
541     // to get deleted right after the lock is released and before anything
542     // after this point is executed. So make sure to not touch any memory in
543     // the return path.
544     //
545 
546     return status;
547 }
548 
549 _Must_inspect_result_
550 NTSTATUS
_PnpQueryCapabilities(__inout FxPkgPnp * This,__inout FxIrp * Irp)551 FxPkgFdo::_PnpQueryCapabilities(
552     __inout FxPkgPnp* This,
553     __inout FxIrp *Irp
554     )
555 {
556 
557 
558 
559 
560 
561 
562 
563 
564 
565 
566 
567 
568     return ((FxPkgFdo*) This)->PnpQueryCapabilities(Irp);
569 }
570 
571 VOID
HandleQueryCapabilities(__inout FxIrp * Irp)572 FxPkgFdo::HandleQueryCapabilities(
573     __inout FxIrp *Irp
574     )
575 {
576     PDEVICE_CAPABILITIES pCaps;
577     LONG pnpCaps;
578 
579     DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
580                         "Entering QueryCapabilities handler");
581 
582     pCaps = Irp->GetParameterDeviceCapabilities();
583 
584     pnpCaps = GetPnpCapsInternal();
585 
586     //
587     // Add Capabilities.  These need to be done as the IRP goes down, since
588     // lower drivers need to see them.
589     //
590     if ((pCaps->Size >= sizeof(DEVICE_CAPABILITIES)) && (pCaps->Version == 1)) {
591         SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, LockSupported);
592         SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, EjectSupported);
593         SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, Removable);
594         SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, DockDevice);
595         SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, SurpriseRemovalOK);
596         SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, NoDisplayInUI);
597         //
598         // If the driver has declared a wake capable interrupt,
599         // we need to set this bit in the capabilities so that
600         // ACPI will relinquish control of wake responsiblity
601         //
602         if (SupportsWakeInterrupt()) {
603             pCaps->WakeFromInterrupt = TRUE;
604         }
605     }
606 
607     DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
608                         "Exiting QueryCapabilities handler");
609     return;
610 }
611 
612 VOID
HandleQueryCapabilitiesCompletion(__inout FxIrp * Irp)613 FxPkgFdo::HandleQueryCapabilitiesCompletion(
614     __inout FxIrp *Irp
615     )
616 {
617     PDEVICE_CAPABILITIES pCaps;
618     LONG pnpCaps;
619     ULONG i;
620 
621     DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
622                         "Entering QueryCapabilities completion handler");
623 
624     pCaps = Irp->GetParameterDeviceCapabilities();
625 
626     pnpCaps = GetPnpCapsInternal();
627 
628     //
629     // Confirm this is a valid DeviceCapabilities structure.
630     //
631     ASSERT(pCaps->Size >= sizeof(DEVICE_CAPABILITIES));
632     ASSERT(pCaps->Version >= 1);
633 
634     if ((pCaps->Size >= sizeof(DEVICE_CAPABILITIES)) &&
635         (pCaps->Version == 1)) {
636         ULONG states;
637 
638         //
639         // Remove Capabilities
640         //
641 
642         //
643         // Re-add SOME capibilties that the bus driver may have accidentally
644         // stomped.
645 
646 
647 
648 
649 
650         SET_PNP_CAP_IF_FALSE(pnpCaps, pCaps, LockSupported);
651         SET_PNP_CAP_IF_FALSE(pnpCaps, pCaps, EjectSupported);
652         SET_PNP_CAP_IF_FALSE(pnpCaps, pCaps, DockDevice);
653 
654         SET_PNP_CAP(pnpCaps, pCaps, Removable);
655         SET_PNP_CAP(pnpCaps, pCaps, SurpriseRemovalOK);
656 
657         //
658         // The DeviceState array contains a table of D states that correspond
659         // to a given S state.  If the driver writer initialized entries of the
660         // array, and if the new value is a deeper sleep state than the
661         // original, we will use the new driver supplied value.
662         //
663         states = m_PowerCaps.States;
664 
665         for (i = PowerSystemWorking; i < PowerSystemMaximum; i++) {
666             DEVICE_POWER_STATE state;
667 
668             //
669             // PowerDeviceMaximum indicates to use the default value
670             //
671             // We are only allowed to deepen the D states, not lighten them,
672             // hence the > compare.
673             //
674             state = _GetPowerCapState(i, states);
675 
676             if (state != PowerDeviceMaximum && state > pCaps->DeviceState[i]) {
677                 pCaps->DeviceState[i] = state;
678             }
679         }
680 
681         //
682         // If the driver supplied SystemWake value is lighter than the current
683         // value, then use the driver supplied value.
684         //
685         // PowerSystemMaximum indicates to use the default value
686         //
687         // We are only allowed to lighten the S state, not deepen it, hence
688         // the < compare.
689         //
690         if (m_PowerCaps.SystemWake != PowerSystemMaximum &&
691             m_PowerCaps.SystemWake < pCaps->SystemWake) {
692             pCaps->SystemWake = (SYSTEM_POWER_STATE) m_PowerCaps.SystemWake;
693         }
694 
695         //
696         // Same for DeviceWake
697         //
698         if (m_PowerCaps.DeviceWake != PowerDeviceMaximum &&
699             m_PowerCaps.DeviceWake < pCaps->DeviceWake) {
700             pCaps->DeviceWake = (DEVICE_POWER_STATE) m_PowerCaps.DeviceWake;
701         }
702 
703         //
704         // Set the Device wake up latencies.  A value of -1 indicates to
705         // use the default values provided by the lower stack.
706         //
707         if (m_PowerCaps.D1Latency != (ULONG) -1 &&
708             m_PowerCaps.D1Latency > pCaps->D1Latency) {
709             pCaps->D1Latency = m_PowerCaps.D1Latency;
710         }
711 
712         if (m_PowerCaps.D2Latency != (ULONG) -1 &&
713             m_PowerCaps.D2Latency > pCaps->D2Latency) {
714             pCaps->D2Latency = m_PowerCaps.D2Latency;
715         }
716 
717         if (m_PowerCaps.D3Latency != (ULONG) -1 &&
718             m_PowerCaps.D3Latency > pCaps->D3Latency) {
719             pCaps->D3Latency = m_PowerCaps.D3Latency;
720         }
721 
722         //
723         // Set the Address and the UI number values.  A value of -1 indicates
724         // to use the default values provided by the lower stack.
725         //
726         if (m_PnpCapsAddress != (ULONG) -1) {
727             pCaps->Address = m_PnpCapsAddress;
728         }
729 
730         if (m_PnpCapsUINumber != (ULONG) -1) {
731             pCaps->UINumber= m_PnpCapsUINumber;
732         }
733     }
734 
735     //
736     // CompletePnpRequest is called after return from this function
737     // so it is safe to log here
738     //
739 
740     DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
741                         "Exiting QueryCapabilities completion handler");
742 
743     return;
744 }
745 
746 _Must_inspect_result_
747 NTSTATUS
_PnpFilterResourceRequirements(__inout FxPkgPnp * This,__inout FxIrp * Irp)748 FxPkgFdo::_PnpFilterResourceRequirements(
749     __inout FxPkgPnp* This,
750     __inout FxIrp *Irp
751     )
752 {
753     return ((FxPkgFdo*) This)->PnpFilterResourceRequirements(Irp);
754 }
755 
756 
757 
758 
759 
760 
761 
762 VOID
HandleQueryPnpDeviceStateCompletion(__inout FxIrp * Irp)763 FxPkgFdo::HandleQueryPnpDeviceStateCompletion(
764     __inout FxIrp *Irp
765     )
766 {
767     PNP_DEVICE_STATE pnpDeviceState;
768 
769     DoTraceLevelMessage(
770         GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
771         "Entering QueryPnpDeviceState completion handler");
772 
773     pnpDeviceState = HandleQueryPnpDeviceState(
774         (PNP_DEVICE_STATE) Irp->GetInformation()
775         );
776 
777     Irp->SetInformation((ULONG_PTR) pnpDeviceState);
778 
779     DoTraceLevelMessage(
780         GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
781         "WDFDEVICE 0x%p !devobj 0x%p returning PNP_DEVICE_STATE 0x%d IRP 0x%p",
782         m_Device->GetHandle(),
783         m_Device->GetDeviceObject(),
784         pnpDeviceState,
785         Irp->GetIrp());
786 
787     DoTraceLevelMessage(
788         GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
789         "Exiting QueryPnpDeviceState completion handler");
790 
791     return;
792 }
793 
794 _Must_inspect_result_
795 NTSTATUS
RegisterCallbacks(__in PWDF_FDO_EVENT_CALLBACKS DispatchTable)796 FxPkgFdo::RegisterCallbacks(
797     __in PWDF_FDO_EVENT_CALLBACKS DispatchTable
798     )
799 {
800     //
801     // Walk the table, and only update the pkg table *if* the dispatch
802     // table has a non-null entry.
803     //
804     m_DeviceFilterAddResourceRequirements.m_Method =
805         DispatchTable->EvtDeviceFilterAddResourceRequirements;
806     m_DeviceFilterRemoveResourceRequirements.m_Method =
807         DispatchTable->EvtDeviceFilterRemoveResourceRequirements;
808     m_DeviceRemoveAddedResources.m_Method =
809         DispatchTable->EvtDeviceRemoveAddedResources;
810 
811     return STATUS_SUCCESS;
812 }
813 
814 _Must_inspect_result_
815 NTSTATUS
CreateDefaultDeviceList(__in PWDF_CHILD_LIST_CONFIG ListConfig,__in PWDF_OBJECT_ATTRIBUTES ListAttributes)816 FxPkgFdo::CreateDefaultDeviceList(
817     __in PWDF_CHILD_LIST_CONFIG ListConfig,
818     __in PWDF_OBJECT_ATTRIBUTES ListAttributes
819     )
820 
821 /*++
822 
823 Routine Description:
824 
825 
826 
827 Arguments:
828 
829 
830 Returns:
831 
832     NTSTATUS
833 
834 --*/
835 
836 {
837     PFX_DRIVER_GLOBALS pFxDriverGlobals;
838     WDFCHILDLIST hList;
839     size_t totalDescriptionSize = 0;
840     NTSTATUS status;
841 
842     pFxDriverGlobals = GetDriverGlobals();
843 
844     ASSERT(m_EnumInfo != NULL);
845 
846     //
847     // This should not fail, we already validated the total size when we
848     // validated the config (we just had no place to store the total size, so
849     // we recompute it again).
850     //
851     status = FxChildList::_ComputeTotalDescriptionSize(
852         pFxDriverGlobals,
853         ListConfig,
854         &totalDescriptionSize
855         );
856     if (!NT_SUCCESS(status)) {
857         return status;
858     }
859 
860     status = FxChildList::_CreateAndInit(&m_DefaultDeviceList,
861                                          pFxDriverGlobals,
862                                          ListAttributes,
863                                          totalDescriptionSize,
864                                          m_Device,
865                                          ListConfig);
866     if (!NT_SUCCESS(status)) {
867         return status;
868     }
869 
870     status = m_DefaultDeviceList->Commit(ListAttributes,
871                                          (WDFOBJECT*)&hList,
872                                          m_Device);
873 
874     if (!NT_SUCCESS(status)) {
875         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
876                             "Could not convert object to handle");
877         m_DefaultDeviceList->DeleteFromFailedCreate();
878         m_DefaultDeviceList = NULL;
879         return status;
880     }
881 
882     //
883     // This will be released in the destructor
884     //
885     m_DefaultDeviceList->ADDREF(this);
886 
887     return status;
888 }
889 
890 _Must_inspect_result_
891 NTSTATUS
SetFilter(__in BOOLEAN Value)892 FxPkgFdo::SetFilter(
893     __in BOOLEAN Value
894     )
895 
896 /*++
897 
898 Routine Description:
899 
900     The Framework behaves differently depending on whether this device is a
901     filter in the stack.  This method is the way we keep track.
902 
903 Arguments:
904 
905     Value - Filter or not
906 
907 Returns:
908 
909     NTSTATUS
910 
911 --*/
912 
913 {
914     m_Filter = Value;
915     return STATUS_SUCCESS;
916 }
917 
918 BOOLEAN
PnpSendStartDeviceDownTheStackOverload(VOID)919 FxPkgFdo::PnpSendStartDeviceDownTheStackOverload(
920     VOID
921     )
922 /*++
923 
924 Routine Description:
925     Send the start irp down the stack.
926 
927 Arguments:
928     None
929 
930 Return Value:
931     FALSE, the transition will occur in the irp's completion routine.
932 
933   --*/
934 {
935     //
936     // We will re-set the pending pnp irp when the start irp returns
937     //
938     FxIrp irp(ClearPendingPnpIrp());
939     PCM_RESOURCE_LIST pWdmRaw, pWdmTranslated;
940     NTSTATUS status;
941     BOOLEAN setFilteredCompletion = FALSE;
942     FxFilteredStartContext* pContext = NULL;
943 
944     pWdmRaw = irp.GetParameterAllocatedResources();
945     pWdmTranslated = irp.GetParameterAllocatedResourcesTranslated();
946 
947     //
948     // Always setup the irp to be sent down the stack.  In case of an error,
949     // this does no harm and it keeps everything simple.
950     //
951     irp.CopyCurrentIrpStackLocationToNext();
952 
953     //
954     // If the driver registered for a callback to remove its added resources
955     // and there are resources to remove, call the driver and set the next
956     // stack location to the filtered resources lists
957     //
958     if (m_DeviceRemoveAddedResources.m_Method != NULL &&
959         pWdmRaw != NULL && pWdmTranslated != NULL) {
960 
961         //
962         // Since we reuse these 2 fields for both the removal and the normal
963         // reporting (and can then be subsequently reused on a restart), we
964         // set the changed status back to FALSE.
965         //
966         m_ResourcesRaw->m_Changed = FALSE;
967         m_Resources->m_Changed = FALSE;
968 
969         status = m_ResourcesRaw->BuildFromWdmList(pWdmRaw,
970                                                   FxResourceAllAccessAllowed);
971 
972         if (NT_SUCCESS(status)) {
973             status = m_Resources->BuildFromWdmList(pWdmTranslated,
974                                                    FxResourceAllAccessAllowed);
975         }
976 
977         if (NT_SUCCESS(status)) {
978             status = m_DeviceRemoveAddedResources.Invoke(
979                 m_Device->GetHandle(),
980                 m_ResourcesRaw->GetHandle(),
981                 m_Resources->GetHandle()
982                 );
983         }
984 
985         if (NT_SUCCESS(status) &&
986             (m_ResourcesRaw->IsChanged() || m_Resources->IsChanged())) {
987 
988             pContext = new(GetDriverGlobals()) FxFilteredStartContext();
989 
990             if (pContext != NULL) {
991                 pContext->PkgFdo = this;
992 
993                 //
994                 // Allocate the raw and translated resources.  Upon failure for
995                 // either, fail the start irp.  We allocate from NonPagedPool
996                 // because we are going to free the list in a completion routine
997                 // which maybe running at an IRQL > PASSIVE_LEVEL.
998                 //
999                 if (m_ResourcesRaw->Count() > 0) {
1000                     pContext->ResourcesRaw =
1001                         m_ResourcesRaw->CreateWdmList(NonPagedPool);
1002 
1003                     if (pContext->ResourcesRaw == NULL) {
1004                         status = STATUS_INSUFFICIENT_RESOURCES;
1005                     }
1006                 }
1007 
1008                 if (NT_SUCCESS(status) && m_Resources->Count() > 0) {
1009                     pContext->ResourcesTranslated =
1010                         m_Resources->CreateWdmList(NonPagedPool);
1011 
1012                     if (pContext->ResourcesTranslated == NULL) {
1013                         status = STATUS_INSUFFICIENT_RESOURCES;
1014                     }
1015                 }
1016 
1017                 if (NT_SUCCESS(status)) {
1018                     //
1019                     // We copied to the next stack location at the start
1020                     //
1021                     irp.SetParameterAllocatedResources(
1022                         pContext->ResourcesRaw);
1023                     irp.SetParameterAllocatedResourcesTranslated(
1024                         pContext->ResourcesTranslated);
1025 
1026                     //
1027                     // Completion routine will free the resource list
1028                     // allocations.
1029                     //
1030                     setFilteredCompletion = TRUE;
1031                 }
1032                 else {
1033                     //
1034                     // Allocation failure.  The destructor will free any
1035                     // outstanding allocations.
1036                     //
1037                     delete pContext;
1038                 }
1039             }
1040         }
1041     }
1042     else {
1043         status = STATUS_SUCCESS;
1044     }
1045 
1046     if (NT_SUCCESS(status)) {
1047         //
1048         // The completion of the start irp will move the state machine into a new
1049         // state.
1050         //
1051         // After calling IoSetCompletionRoutineEx the driver must call
1052         // IoCallDriver, otherwise a memory leak would occur. So call this API
1053         // as close to IoCallDriver as possible to avoid failure paths.
1054         //
1055         if (setFilteredCompletion) {
1056             ASSERT(pContext != NULL);
1057             irp.SetCompletionRoutineEx(
1058                 m_Device->GetDeviceObject(),
1059                 _PnpFilteredStartDeviceCompletionRoutine,
1060                 pContext);
1061         }
1062         else {
1063             irp.SetCompletionRoutineEx(
1064                 m_Device->GetDeviceObject(),
1065                 _PnpStartDeviceCompletionRoutine,
1066                 this);
1067         }
1068 
1069         irp.CallDriver(m_Device->GetAttachedDevice());
1070     }
1071     else {
1072         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1073                             "PNP start preprocessing failed with %!STATUS!",
1074                             status);
1075 
1076         //
1077         // Move the state machine to the failed state.
1078         //
1079         // Process the event *before* completing the irp so that this even is in
1080         // the queue before the device remove event which will be be processed
1081         // right after the start irp has been completed.
1082         //
1083         PnpProcessEvent(PnpEventStartDeviceFailed);
1084 
1085         //
1086         // All states which handle the PnpEventStartDeviceFailed event
1087         // transition do not expect a pended start irp.
1088         //
1089         CompletePnpRequest(&irp, status);
1090     }
1091 
1092     //
1093     // Indicate to the caller that the transition is asynchronous.
1094     //
1095     return FALSE;
1096 }
1097 
1098 WDF_DEVICE_PNP_STATE
PnpEventEjectHardwareOverload(VOID)1099 FxPkgFdo::PnpEventEjectHardwareOverload(
1100     VOID
1101     )
1102 
1103 /*++
1104 
1105 Routine Description:
1106 
1107     This method implements the Eject Hardware state in the PnP State Machine.
1108     Since FDO and PDO behavior is different, this is overloaded.  In fact,
1109     this state shouldn't be reachable for FDOs, as the FDO should have been
1110     torn off the stack before the device was cleanly ejected.
1111 
1112 Arguments:
1113 
1114     none
1115 
1116 Returns:
1117 
1118     WdfDevStatePnpEjectedWaitingForRemove
1119 
1120 --*/
1121 
1122 {
1123     ASSERT(!"This should only be reachable for PDOs.");
1124 
1125     //
1126     // Do something safe.  Act like the device got
1127     // ejected.
1128     //
1129     return WdfDevStatePnpEjectedWaitingForRemove;
1130 }
1131 
1132 WDF_DEVICE_PNP_STATE
PnpEventCheckForDevicePresenceOverload(VOID)1133 FxPkgFdo::PnpEventCheckForDevicePresenceOverload(
1134     VOID
1135     )
1136 
1137 /*++
1138 
1139 Routine Description:
1140 
1141     This method implements the Check For Device Presence state in the PnP State
1142     Machine.  Since FDO and PDO behavior is different, this is overloaded.  In
1143     fact, this state shouldn't be reachable for FDOs, as the FDO should have
1144     been torn off the stack before the device was cleanly ejected.
1145 
1146 Arguments:
1147 
1148     none
1149 
1150 Returns:
1151 
1152     WdfDevStatePnpFinal
1153 
1154 --*/
1155 
1156 {
1157     ASSERT(!"This should only be implemented for PDOs.");
1158 
1159     //
1160     // Do something safe.  Act like the device is not
1161     // present.
1162     //
1163     return WdfDevStatePnpFinal;
1164 }
1165 
1166 WDF_DEVICE_PNP_STATE
PnpEventPdoRemovedOverload(VOID)1167 FxPkgFdo::PnpEventPdoRemovedOverload(
1168     VOID
1169     )
1170 
1171 /*++
1172 
1173 Routine Description:
1174 
1175     This method implements the PDO Removed state in the PnP State Machine.
1176     Since FDO and PDO behavior is different, this is overloaded.  In fact,
1177     this state shouldn't be reachable for FDOs, as the FDO should have been
1178     torn off the stack before the PDO is removed.
1179 
1180 Arguments:
1181 
1182     none
1183 
1184 Returns:
1185 
1186     none
1187 
1188 --*/
1189 
1190 {
1191     ASSERT(!"This should only be implemented for PDOs.");
1192 
1193     return WdfDevStatePnpFinal;
1194 }
1195 
1196 WDF_DEVICE_PNP_STATE
PnpGetPostRemoveState(VOID)1197 FxPkgFdo::PnpGetPostRemoveState(
1198     VOID
1199     )
1200 
1201 /*++
1202 
1203 Routine Description:
1204 
1205     This method implements the Removed state in the PnP State Machine.
1206     Since FDO and PDO behavior is different, this is overloaded.  This state
1207     just moves us toward the FDO-specific removal states.
1208 
1209 Arguments:
1210 
1211     none
1212 
1213 Returns:
1214 
1215     none
1216 
1217 --*/
1218 
1219 {
1220     return WdfDevStatePnpFdoRemoved;
1221 }
1222 
1223 WDF_DEVICE_PNP_STATE
PnpEventFdoRemovedOverload(VOID)1224 FxPkgFdo::PnpEventFdoRemovedOverload(
1225     VOID
1226     )
1227 /*++
1228 
1229 Routine Description:
1230     FDO is being removed, see if there are any children that need to be removed
1231 
1232 Arguments:
1233     None
1234 
1235 Return Value:
1236     New device pnp state
1237 
1238   --*/
1239 {
1240     //
1241     // Do that which all device stacks need to do upon removal.
1242     //
1243     PnpEventRemovedCommonCode();
1244 
1245     return WdfDevStatePnpFinal;
1246 }
1247 
1248 _Must_inspect_result_
1249 NTSTATUS
ProcessRemoveDeviceOverload(__inout FxIrp * Irp)1250 FxPkgFdo::ProcessRemoveDeviceOverload(
1251     __inout FxIrp* Irp
1252     )
1253 {
1254     NTSTATUS status;
1255 
1256     //
1257     // After this is called, any irp dispatched to FxDevice::DispatchWithLock
1258     // will fail with STATUS_INVALID_DEVICE_REQUEST.
1259     //
1260     Mx::MxReleaseRemoveLockAndWait(m_Device->GetRemoveLock(),
1261                                    Irp->GetIrp());
1262 
1263     //
1264     // Cleanup the state machines and release the power thread.
1265     //
1266     CleanupStateMachines(TRUE);
1267 
1268     Irp->CopyCurrentIrpStackLocationToNext();
1269     status = Irp->CallDriver(m_Device->GetAttachedDevice());
1270 
1271     //
1272     // Detach and delete the device object.
1273     //
1274     DeleteDevice();
1275 
1276     return status;
1277 }
1278 
1279 VOID
DeleteSymbolicLinkOverload(__in BOOLEAN GracefulRemove)1280 FxPkgFdo::DeleteSymbolicLinkOverload(
1281     __in BOOLEAN GracefulRemove
1282     )
1283 /*++
1284 
1285 Routine Description:
1286     Role specific virtual function which determines if the symbolic link for a
1287     device should be deleted.
1288 
1289 Arguments:
1290     None
1291 
1292 Return Value:
1293     None
1294 
1295   --*/
1296 {
1297     UNREFERENCED_PARAMETER(GracefulRemove);
1298 
1299     //
1300     // We always remove the symbolic link for an FDO since there is no presence
1301     // state to check.
1302     //
1303     m_Device->DeleteSymbolicLink();
1304 }
1305 
1306 VOID
QueryForReenumerationInterface(VOID)1307 FxPkgFdo::QueryForReenumerationInterface(
1308     VOID
1309     )
1310 {
1311     PREENUMERATE_SELF_INTERFACE_STANDARD pInterface;
1312     NTSTATUS status;
1313 
1314     pInterface = &m_SurpriseRemoveAndReenumerateSelfInterface;
1315 
1316     if (pInterface->SurpriseRemoveAndReenumerateSelf != NULL) {
1317         //
1318         // Already got it, just return.  This function can be called again during
1319         // stop -> start, so we must check.
1320         //
1321         return;
1322     }
1323 
1324     RtlZeroMemory(pInterface, sizeof(*pInterface));
1325     pInterface->Size =  sizeof(*pInterface);
1326     pInterface->Version = 1;
1327 
1328     //
1329     // Since there are some stacks that are not PnP re-entrant
1330 
1331     // we specify that the QI goes only to our attached device and
1332     // not to the top of the stack as a normal QI irp would.  For the
1333     // reenumerate self interface, having someone on top of us filter the
1334     // IRP makes no sense anyways.
1335     //
1336     // We also do this as a preventative measure for other stacks we don't know
1337     // about internally and do not have access to when testing.
1338     //
1339     status = m_Device->QueryForInterface(&GUID_REENUMERATE_SELF_INTERFACE_STANDARD,
1340         (PINTERFACE) pInterface,
1341         sizeof(*pInterface),
1342         1,
1343         NULL,
1344         m_Device->GetAttachedDevice()
1345         );
1346 
1347     //
1348     // Failure to get this interface is not fatal.
1349     // Note that an implicit reference has been taken on the interface. We
1350     // must release the reference when we are done with the interface.
1351     //
1352     UNREFERENCED_PARAMETER(status); // for analyis tools.
1353 }
1354 
1355 VOID
ReleaseReenumerationInterface(VOID)1356 FxPkgFdo::ReleaseReenumerationInterface(
1357     VOID
1358     )
1359 /*++
1360 
1361 Routine Description:
1362 
1363     Releases the implicit reference taken on REENUMERATE_SELF interface.
1364     NOOP for PDO.
1365 
1366 Arguments:
1367     None
1368 
1369 Return Value:
1370     VOID
1371 
1372   --*/
1373 {
1374     PREENUMERATE_SELF_INTERFACE_STANDARD pInterface;
1375 
1376     pInterface = &m_SurpriseRemoveAndReenumerateSelfInterface;
1377 
1378     pInterface->SurpriseRemoveAndReenumerateSelf = NULL;
1379 
1380     if (pInterface->InterfaceDereference != NULL) {
1381         pInterface->InterfaceDereference(pInterface->Context);
1382     }
1383 }
1384 
1385 _Must_inspect_result_
1386 NTSTATUS
QueryForPowerThread(VOID)1387 FxPkgFdo::QueryForPowerThread(
1388     VOID
1389     )
1390 /*++
1391 
1392 Routine Description:
1393     Sends a query for a power thread down the stack.  If it can't query for one,
1394     it attempts to create one on its own.
1395 
1396 Arguments:
1397     None
1398 
1399 Return Value:
1400     NTSTATUS
1401 
1402   --*/
1403 {
1404     NTSTATUS status;
1405 
1406     //
1407     // Query down the stack to see if a lower device already created a thread.
1408     // Do NOT send this to the top of the stack, it is sent to the attached
1409     // device b/c we need the thread from a device below us b/c its lifetime
1410     // will outlast this device's.
1411     //
1412     status = m_Device->QueryForInterface(&GUID_POWER_THREAD_INTERFACE,
1413         &m_PowerThreadInterface.Interface,
1414         sizeof(m_PowerThreadInterface),
1415         1,
1416         NULL,
1417         m_Device->GetAttachedDevice());
1418 
1419     if (NT_SUCCESS(status)) {
1420         //
1421         // A lower thread exists, use it
1422         //
1423         m_HasPowerThread = TRUE;
1424     }
1425     else {
1426         //
1427         // No thread exists yet, attempt to create our own
1428         //
1429         status = CreatePowerThread();
1430     }
1431 
1432     return status;
1433 }
1434 
1435 _Must_inspect_result_
1436 NTSTATUS
1437 STDCALL
_PnpFilteredStartDeviceCompletionRoutine(__in MdDeviceObject DeviceObject,__inout MdIrp Irp,__inout PVOID Context)1438 FxPkgFdo::_PnpFilteredStartDeviceCompletionRoutine(
1439     __in    MdDeviceObject DeviceObject,
1440     __inout MdIrp Irp,
1441     __inout PVOID Context
1442     )
1443 {
1444     FxFilteredStartContext *pContext;
1445     FxPkgFdo* pPkgFdo;
1446 
1447     pContext = (FxFilteredStartContext*) Context;
1448 
1449     //
1450     // Save off the package so we can use it after we free the context
1451     //
1452     pPkgFdo = pContext->PkgFdo;
1453 
1454     delete pContext;
1455 
1456     return _PnpStartDeviceCompletionRoutine(DeviceObject, Irp, pPkgFdo);
1457 }
1458 
1459 _Must_inspect_result_
1460 NTSTATUS
1461 STDCALL
_PnpStartDeviceCompletionRoutine(__in MdDeviceObject DeviceObject,__inout MdIrp Irp,__inout PVOID Context)1462 FxPkgFdo::_PnpStartDeviceCompletionRoutine(
1463     __in    MdDeviceObject DeviceObject,
1464     __inout MdIrp Irp,
1465     __inout PVOID Context
1466     )
1467 {
1468     FxPkgFdo* pThis;
1469     FxIrp irp(Irp);
1470 
1471     UNREFERENCED_PARAMETER(DeviceObject);
1472 
1473     pThis = (FxPkgFdo*) Context;
1474 
1475     if (NT_SUCCESS(irp.GetStatus())) {
1476         pThis->SetPendingPnpIrp(&irp);
1477 
1478         //
1479         // Only raise irql if we are the power policy owner.  Only the p.p.o.
1480         // does this so that we only have one driver in the device stack moving
1481         // to another thread.
1482         //
1483         if (pThis->IsPowerPolicyOwner()) {
1484             KIRQL irql;
1485 
1486             //
1487             // By raising to dispatch level we are forcing the pnp state machine
1488             // to move to another thread.  On NT 6.0 PnP supports asynchronous
1489             // starts, so this will other starts to proceed while WDF processes
1490             // this device starting.
1491             //
1492             Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql);
1493             pThis->PnpProcessEvent(PnpEventStartDeviceComplete);
1494             Mx::MxLowerIrql(irql);
1495         }
1496         else {
1497             pThis->PnpProcessEvent(PnpEventStartDeviceComplete);
1498         }
1499     }
1500     else {
1501         //
1502         // Just complete the request, the current pnp state can handle the remove
1503         // which will be sent b/c of the failed start.
1504         //
1505         DoTraceLevelMessage(
1506             pThis->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1507             "PNP start failed with %!STATUS!", irp.GetStatus());
1508 
1509         //
1510         // Process the event *before* completing the irp so that this even is in
1511         // the queue before the device remove event which will be be processed
1512         // right after the start irp has been completed.
1513         //
1514         pThis->PnpProcessEvent(PnpEventStartDeviceFailed);
1515 
1516         pThis->CompletePnpRequest(&irp, irp.GetStatus());
1517     }
1518 
1519     return STATUS_MORE_PROCESSING_REQUIRED;
1520 }
1521 
1522 _Must_inspect_result_
1523 NTSTATUS
PostCreateDeviceInitialize(VOID)1524 FxPkgFdo::PostCreateDeviceInitialize(
1525     VOID
1526     )
1527 {
1528     NTSTATUS status;
1529 
1530     status = FxPkgPnp::PostCreateDeviceInitialize(); // __super call
1531     if (!NT_SUCCESS(status)) {
1532         return status;
1533     }
1534 
1535 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
1536     //
1537     // Allow device simulation framework to hook interrupt routines.
1538     //
1539     if (GetDriverGlobals()->FxDsfOn) {
1540         status = QueryForDsfInterface();
1541         if (!NT_SUCCESS(status)) {
1542             return status;
1543         }
1544     }
1545 
1546 #endif
1547 
1548     status = m_Device->AllocateTarget(&m_DefaultTarget,
1549                                       FALSE /*SelfTarget=FALSE*/);
1550     if (NT_SUCCESS(status)) {
1551         //
1552         // This will be released in the destructor
1553         //
1554         m_DefaultTarget->ADDREF(this);
1555     }
1556 
1557     if (m_Device->m_SelfIoTargetNeeded) {
1558         status = m_Device->AllocateTarget((FxIoTarget**)&m_SelfTarget,
1559                                           TRUE /*SelfTarget*/);
1560         if (NT_SUCCESS(status)) {
1561             //
1562             // This will be released in the destructor
1563             //
1564             m_SelfTarget->ADDREF(this);
1565         }
1566     }
1567 
1568 
1569     return status;
1570 }
1571 
1572