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