1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxPkgPdo.cpp
8
9 Abstract:
10
11 This module implements the Pnp package for Pdo devices.
12
13 Author:
14
15
16
17 Environment:
18
19 Both kernel and user mode
20
21 Revision History:
22
23
24
25
26 --*/
27
28 #include "pnppriv.hpp"
29 #include <wdmguid.h>
30
31 // Tracing support
32 #if defined(EVENT_TRACING)
33 extern "C" {
34 #include "FxPkgPdo.tmh"
35 }
36 #endif
37
38 const PFN_PNP_POWER_CALLBACK FxPkgPdo::m_PdoPnpFunctionTable[IRP_MN_SURPRISE_REMOVAL + 1] =
39 {
40 _PnpStartDevice, // IRP_MN_START_DEVICE
41 _PnpQueryRemoveDevice, // IRP_MN_QUERY_REMOVE_DEVICE
42 _PnpRemoveDevice, // IRP_MN_REMOVE_DEVICE
43 _PnpCancelRemoveDevice, // IRP_MN_CANCEL_REMOVE_DEVICE
44 _PnpStopDevice, // IRP_MN_STOP_DEVICE
45 _PnpQueryStopDevice, // IRP_MN_QUERY_STOP_DEVICE
46 _PnpCancelStopDevice, // IRP_MN_CANCEL_STOP_DEVICE
47
48 _PnpQueryDeviceRelations, // IRP_MN_QUERY_DEVICE_RELATIONS
49 _PnpQueryInterface, // IRP_MN_QUERY_INTERFACE
50 _PnpQueryCapabilities, // IRP_MN_QUERY_CAPABILITIES
51 _PnpQueryResources, // IRP_MN_QUERY_RESOURCES
52 _PnpQueryResourceRequirements, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
53 _PnpQueryDeviceText, // IRP_MN_QUERY_DEVICE_TEXT
54 _PnpFilterResourceRequirements, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
55
56 _PnpCompleteIrp, // 0x0E
57
58 _PnpCompleteIrp, // IRP_MN_READ_CONFIG
59 _PnpCompleteIrp, // IRP_MN_WRITE_CONFIG
60 _PnpEject, // IRP_MN_EJECT
61 _PnpSetLock, // IRP_MN_SET_LOCK
62 _PnpQueryId, // IRP_MN_QUERY_ID
63 _PnpQueryPnpDeviceState, // IRP_MN_QUERY_PNP_DEVICE_STATE
64 _PnpQueryBusInformation, // IRP_MN_QUERY_BUS_INFORMATION
65 _PnpDeviceUsageNotification, // IRP_MN_DEVICE_USAGE_NOTIFICATION
66 _PnpSurpriseRemoval, // IRP_MN_SURPRISE_REMOVAL
67 };
68
69 const PFN_PNP_POWER_CALLBACK FxPkgPdo::m_PdoPowerFunctionTable[IRP_MN_QUERY_POWER + 1] =
70 {
71 _DispatchWaitWake, // IRP_MN_WAIT_WAKE
72 _DispatchPowerSequence, // IRP_MN_POWER_SEQUENCE
73 _DispatchSetPower, // IRP_MN_SET_POWER
74 _DispatchQueryPower, // IRP_MN_QUERY_POWER
75 };
76
77 //#if defined(ALLOC_PRAGMA)
78 //#pragma code_seg("PAGE")
79 //#endif
80
FxPkgPdo(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in CfxDevice * Device)81 FxPkgPdo::FxPkgPdo(
82 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
83 __in CfxDevice *Device
84 ) :
85 FxPkgPnp(FxDriverGlobals, Device, FX_TYPE_PACKAGE_PDO)
86 /*++
87
88 Routine Description:
89
90 This is the constructor for the FxPkgPdo. Don't do any initialization
91 that might fail here.
92
93 Arguments:
94
95 none
96
97 Returns:
98
99 none
100
101 --*/
102
103 {
104 m_DeviceTextHead.Next = NULL;
105
106 m_DeviceID = NULL;
107 m_InstanceID = NULL;
108 m_HardwareIDs = NULL;
109 m_CompatibleIDs = NULL;
110 m_ContainerID = NULL;
111 m_IDsAllocation = NULL;
112
113 m_RawOK = FALSE;
114 m_Static = FALSE;
115 m_AddedToStaticList = FALSE;
116
117 //
118 // By default the PDO is the owner of wait wake irps (only case where this
119 // wouldn't be the case is for a bus filter to be sitting above us).
120 //
121 m_SharedPower.m_WaitWakeOwner = TRUE;
122
123 m_Description = NULL;
124 m_OwningChildList = NULL;
125
126 m_EjectionDeviceList = NULL;
127 m_DeviceEjectProcessed = NULL;
128
129 m_CanBeDeleted = FALSE;
130 m_EnableWakeAtBusInvoked = FALSE;
131 }
132
~FxPkgPdo(VOID)133 FxPkgPdo::~FxPkgPdo(
134 VOID
135 )
136 /*++
137
138 Routine Description:
139
140 This is the destructor for the FxPkgPdo
141
142 Arguments:
143
144 none
145
146 Returns:
147
148 none
149
150 --*/
151 {
152 //
153 // If IoCreateDevice fails on a dynamically created PDO, m_Description will
154 // be != NULL b/c we will not go through the pnp state machine in its entirety
155 // for cleanup. FxChildList will need a valid m_Description to cleanup upon
156 // failure from EvtChildListDeviceCrate, so we just leave m_Description alone
157 // here if != NULL.
158 //
159 // ASSERT(m_Description == NULL);
160
161 FxDeviceText::_CleanupList(&m_DeviceTextHead);
162
163 //
164 // This will free the underlying memory for m_DeviceID, m_InstanceID,
165 // m_HardwareIDs, m_CompatibleIDs and m_ContainerID
166 //
167 if (m_IDsAllocation != NULL) {
168 FxPoolFree(m_IDsAllocation);
169 m_IDsAllocation = NULL;
170 }
171
172 if (m_OwningChildList != NULL) {
173 m_OwningChildList->RELEASE(this);
174 }
175
176 if (m_EjectionDeviceList != NULL) {
177 delete m_EjectionDeviceList;
178 m_EjectionDeviceList = NULL;
179 }
180 }
181
182 _Must_inspect_result_
183 NTSTATUS
Initialize(__in PWDFDEVICE_INIT DeviceInit)184 FxPkgPdo::Initialize(
185 __in PWDFDEVICE_INIT DeviceInit
186 )
187 /*++
188
189 Routine Description:
190
191 Do initialization that might fail here.
192
193 Arguemnts:
194
195 DeviceInit - the structure the driver passed in with initialization data
196
197 Returns:
198
199 NTSTATUS
200
201 --*/
202 {
203 NTSTATUS status;
204 size_t cbLength, cbStrLength;
205 PWSTR pCur;
206 PdoInit* pPdo;
207
208 status = FxPkgPnp::Initialize(DeviceInit);
209 if (!NT_SUCCESS(status)) {
210 return status;
211 }
212
213 cbLength = 0;
214
215 //
216 // Compute the total number of bytes required for all strings and then
217 // make one allocation and remember pointers w/in the string so we can
218 // retrieve them individually later.
219 //
220 pPdo = &DeviceInit->Pdo;
221 cbLength += FxCalculateTotalStringSize(&pPdo->HardwareIDs);
222 cbLength += FxCalculateTotalStringSize(&pPdo->CompatibleIDs);
223
224 if (pPdo->DeviceID != NULL) {
225 cbLength += pPdo->DeviceID->ByteLength(TRUE);
226 }
227 if (pPdo->InstanceID != NULL) {
228 cbLength += pPdo->InstanceID->ByteLength(TRUE);
229 }
230 if (pPdo->ContainerID != NULL) {
231 cbLength += pPdo->ContainerID->ByteLength(TRUE);
232 }
233
234 m_IDsAllocation = (PWSTR) FxPoolAllocate(GetDriverGlobals(),
235 PagedPool,
236 cbLength);
237
238 if (m_IDsAllocation == NULL) {
239 status = STATUS_INSUFFICIENT_RESOURCES;
240
241 DoTraceLevelMessage(
242 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
243 "DeviceInit %p could not allocate string for device IDs "
244 "(length %I64d), %!STATUS!", DeviceInit, cbLength, status);
245
246 return status;
247 }
248
249 pCur = m_IDsAllocation;
250
251 m_HardwareIDs = pCur;
252 pCur = FxCopyMultiSz(m_HardwareIDs, &pPdo->HardwareIDs);
253
254 m_CompatibleIDs = pCur;
255 pCur = FxCopyMultiSz(m_CompatibleIDs, &pPdo->CompatibleIDs);
256
257 if (pPdo->DeviceID != NULL) {
258 m_DeviceID = pCur;
259
260 //
261 // Copy the bytes and then null terminate the buffer
262 //
263 cbStrLength = pPdo->DeviceID->ByteLength(FALSE);
264
265 RtlCopyMemory(m_DeviceID,
266 pPdo->DeviceID->Buffer(),
267 cbStrLength);
268
269 m_DeviceID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL;
270
271 pCur = (PWSTR) WDF_PTR_ADD_OFFSET(m_DeviceID,
272 cbStrLength + sizeof(UNICODE_NULL));
273 }
274
275 if (pPdo->InstanceID != NULL) {
276 m_InstanceID = pCur;
277
278 //
279 // Copy the bytes and then null terminate the buffer
280 //
281 cbStrLength = pPdo->InstanceID->ByteLength(FALSE);
282
283 RtlCopyMemory(m_InstanceID,
284 pPdo->InstanceID->Buffer(),
285 cbStrLength);
286
287 m_InstanceID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL;
288
289 pCur = (PWSTR) WDF_PTR_ADD_OFFSET(m_InstanceID,
290 cbStrLength + sizeof(UNICODE_NULL));
291 }
292
293 if (pPdo->ContainerID != NULL) {
294 m_ContainerID = pCur;
295
296 //
297 // Copy the bytes and then null terminate the buffer
298 //
299 cbStrLength = pPdo->ContainerID->ByteLength(FALSE);
300
301 RtlCopyMemory(m_ContainerID,
302 pPdo->ContainerID->Buffer(),
303 cbStrLength);
304
305 m_ContainerID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL;
306 }
307
308 m_Static = pPdo->Static;
309
310 if (m_Static) {
311 //
312 // Statically enumerated children do not support reenumeration requests
313 // from the stack on top of them.
314 //
315
316 //
317 // The only way we can have static children is if an FDO enumerates them.
318 //
319
320
321
322
323
324 Mx::MxAssert(m_Device->m_ParentDevice->IsFdo());
325 m_OwningChildList = m_Device->m_ParentDevice->GetFdoPkg()->m_StaticDeviceList;
326
327 m_OwningChildList->ADDREF(this);
328 }
329 else {
330 m_Description = pPdo->DescriptionEntry;
331
332 m_OwningChildList = m_Description->GetParentList();
333 m_OwningChildList->ADDREF(this);
334 }
335
336 return STATUS_SUCCESS;
337 }
338
339 VOID
FinishInitialize(__in PWDFDEVICE_INIT DeviceInit)340 FxPkgPdo::FinishInitialize(
341 __in PWDFDEVICE_INIT DeviceInit
342 )
343 {
344 PdoInit* pdoInit;
345
346 pdoInit = &DeviceInit->Pdo;
347
348 m_DefaultLocale = pdoInit->DefaultLocale;
349 m_DeviceTextHead.Next = pdoInit->DeviceText.Next;
350 pdoInit->DeviceText.Next = NULL;
351
352 //
353 // Important to do this last since this will cause a pnp state machine
354 // transition
355 //
356 FxPkgPnp::FinishInitialize(DeviceInit); // __super call
357 }
358
359 _Must_inspect_result_
360 NTSTATUS
SendIrpSynchronously(__in FxIrp * Irp)361 FxPkgPdo::SendIrpSynchronously(
362 __in FxIrp* Irp
363 )
364 /*++
365
366 Routine Description:
367 Virtual override for synchronously sending a request down the stack and
368 catching it on the way back up. For PDOs, we are the bottom, so this is a
369 no-op.
370
371 Arguments:
372 Irp - The request
373
374 Return Value:
375 Status in the Irp
376
377 --*/
378 {
379 return Irp->GetStatus();
380 }
381
382 _Must_inspect_result_
383 NTSTATUS
FireAndForgetIrp(__inout FxIrp * Irp)384 FxPkgPdo::FireAndForgetIrp(
385 __inout FxIrp *Irp
386 )
387 /*++
388
389 Routine Description:
390
391 Virtual override for sending a request down the stack and forgetting about
392 it. Since we are the bottom of the stack, just complete the request.
393
394 Arguments:
395
396 Return Value:
397
398 --*/
399 {
400 NTSTATUS status;
401
402 status = Irp->GetStatus();
403
404 if (Irp->GetMajorFunction() == IRP_MJ_POWER) {
405 return CompletePowerRequest(Irp, status);
406 }
407 else {
408 return CompletePnpRequest(Irp, status);
409 }
410 }
411
412 _Must_inspect_result_
413 NTSTATUS
_PnpCompleteIrp(__in FxPkgPnp * This,__inout FxIrp * Irp)414 FxPkgPdo::_PnpCompleteIrp(
415 __in FxPkgPnp* This,
416 __inout FxIrp *Irp
417 )
418 {
419 return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, Irp->GetStatus());
420 }
421
422 _Must_inspect_result_
423 NTSTATUS
_PnpQueryDeviceRelations(__in FxPkgPnp * This,__inout FxIrp * Irp)424 FxPkgPdo::_PnpQueryDeviceRelations(
425 __in FxPkgPnp* This,
426 __inout FxIrp *Irp
427 )
428 {
429 return ((FxPkgPdo*) This)->PnpQueryDeviceRelations(Irp);
430 }
431
432 _Must_inspect_result_
433 NTSTATUS
PnpQueryDeviceRelations(__inout FxIrp * Irp)434 FxPkgPdo::PnpQueryDeviceRelations(
435 __inout FxIrp *Irp
436 )
437 /*++
438
439 Routine Description:
440
441 This method is called in response to a PnP QDR. PDOs handle Ejection
442 Relations and Target Relations.
443
444 Arguments:
445
446 Irp - a pointer to the FxIrp
447
448 Returns:
449
450 NTSTATUS
451
452 --*/
453 {
454 PDEVICE_RELATIONS pDeviceRelations;
455 NTSTATUS status;
456 DEVICE_RELATION_TYPE type;
457 PFX_DRIVER_GLOBALS pFxDriverGlobals;
458
459 status = Irp->GetStatus();
460 pFxDriverGlobals = GetDriverGlobals();
461
462 type = Irp->GetParameterQDRType();
463 switch (type) {
464 case BusRelations:
465 status = HandleQueryBusRelations(Irp);
466 break;
467
468 case EjectionRelations:
469 case RemovalRelations:
470 status = HandleQueryDeviceRelations(
471 Irp,
472 (type == RemovalRelations) ? m_RemovalDeviceList
473 : m_EjectionDeviceList);
474
475 //
476 // STATUS_NOT_SUPPORTED is a special value. It means that
477 // HandleQueryDeviceRelations did not modify the irp at all and it
478 // should be sent off as is.
479 //
480 if (status == STATUS_NOT_SUPPORTED) {
481 //
482 // Complete the request with the status it was received with
483 //
484 status = Irp->GetStatus();
485 }
486 break;
487
488 case TargetDeviceRelation:
489 pDeviceRelations = (PDEVICE_RELATIONS) MxMemory::MxAllocatePoolWithTag(
490 PagedPool, sizeof(DEVICE_RELATIONS), pFxDriverGlobals->Tag);
491
492 if (pDeviceRelations != NULL) {
493 PDEVICE_OBJECT pDeviceObject;
494
495 pDeviceObject = reinterpret_cast<PDEVICE_OBJECT> (m_Device->GetDeviceObject());
496
497 Mx::MxReferenceObject(pDeviceObject);
498
499 pDeviceRelations->Count = 1;
500 pDeviceRelations->Objects[0] = pDeviceObject;
501
502 Irp->SetInformation((ULONG_PTR) pDeviceRelations);
503 status = STATUS_SUCCESS;
504 }
505 else {
506 Irp->SetInformation(NULL);
507 status = STATUS_INSUFFICIENT_RESOURCES;
508
509 DoTraceLevelMessage(
510 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
511 "WDFDEVICE %p failing TargetDeviceRelations, %!STATUS!",
512 m_Device->GetHandle(), status);
513 }
514 break;
515 }
516
517 return CompletePnpRequest(Irp, status);
518 }
519
520 _Must_inspect_result_
521 NTSTATUS
_PnpQueryInterface(IN FxPkgPnp * This,IN FxIrp * Irp)522 FxPkgPdo::_PnpQueryInterface(
523 IN FxPkgPnp* This,
524 IN FxIrp *Irp
525 )
526 /*++
527
528 Routine Description:
529 Query interface handler for the PDO
530
531 Arguments:
532 This - the package
533
534 Irp - the QI request
535
536 Return Value:
537 NTSTATUS
538
539 --*/
540 {
541 NTSTATUS status;
542 BOOLEAN completeIrp;
543
544 status = ((FxPkgPdo*) This)->HandleQueryInterface(Irp, &completeIrp);
545
546 return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, status);
547 }
548
549 _Must_inspect_result_
550 NTSTATUS
_PnpQueryCapabilities(__inout FxPkgPnp * This,__inout FxIrp * Irp)551 FxPkgPdo::_PnpQueryCapabilities(
552 __inout FxPkgPnp* This,
553 __inout FxIrp *Irp
554 )
555 {
556 return ((FxPkgPdo*) This)->PnpQueryCapabilities(Irp);
557 }
558
559 _Must_inspect_result_
560 NTSTATUS
PnpQueryCapabilities(__inout FxIrp * Irp)561 FxPkgPdo::PnpQueryCapabilities(
562 __inout FxIrp *Irp
563 )
564
565 /*++
566
567 Routine Description:
568
569 This method is invoked in response to a Pnp QueryCapabilities IRP.
570
571 Arguments:
572
573 Irp - a pointer to the FxIrp
574
575 Returns:
576
577 NTSTATUS
578
579 --*/
580
581 {
582 PDEVICE_CAPABILITIES pDeviceCapabilities;
583 STACK_DEVICE_CAPABILITIES parentStackCapabilities = {0};
584 NTSTATUS status;
585
586 status = STATUS_UNSUCCESSFUL;
587
588 pDeviceCapabilities = Irp->GetParameterDeviceCapabilities();
589
590 //
591 // Confirm this is a valid DeviceCapabilities structure.
592 //
593 ASSERT(pDeviceCapabilities->Size >= sizeof(DEVICE_CAPABILITIES));
594 ASSERT(pDeviceCapabilities->Version == 1);
595
596 if ((pDeviceCapabilities->Version == 1) &&
597 (pDeviceCapabilities->Size >= sizeof(DEVICE_CAPABILITIES))) {
598
599 //
600 // Since query caps must be sent to the parent stack until it reaches
601 // the root, we can quickly run out of stack space. If that happens,
602 // then move to a work item to get a fresh stack with plenty of stack
603 // space.
604 //
605 if (Mx::MxHasEnoughRemainingThreadStack() == FALSE) {
606 MxWorkItem workItem;
607
608 status = workItem.Allocate(m_Device->GetDeviceObject());
609
610 if (NT_SUCCESS(status)) {
611 //
612 // Store off the work item so we can free it in the worker routine
613 //
614 Irp->SetContext(0, (PVOID)workItem.GetWorkItem());
615
616 //
617 // Mark the irp as pending because it will be completed in
618 // another thread
619 //
620 Irp->MarkIrpPending();
621
622 //
623 // Kick off to another thread
624 //
625 workItem.Enqueue(_QueryCapsWorkItem, Irp->GetIrp());
626
627 return STATUS_PENDING;
628 }
629 else {
630 //
631 // Not enough for a work item, return error
632 //
633 status = STATUS_INSUFFICIENT_RESOURCES;
634 }
635 }
636 else {
637 MxDeviceObject parentDeviceObject;
638
639 parentDeviceObject.SetObject(
640 m_Device->m_ParentDevice->GetDeviceObject());
641 status = GetStackCapabilities(
642 GetDriverGlobals(),
643 &parentDeviceObject,
644 NULL, // D3ColdInterface
645 &parentStackCapabilities);
646
647 if (NT_SUCCESS(status)) {
648 #pragma prefast(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "prefast is confused")
649 HandleQueryCapabilities(pDeviceCapabilities,
650 &parentStackCapabilities.DeviceCaps);
651
652 //
653 // The check above does not guarantee STATUS_SUCCESS explicitly
654 // (ie the verifier can change the value to something other then
655 // STATUS_SUCCESS) so set it here
656 //
657 status = STATUS_SUCCESS;
658 }
659 }
660 }
661
662 return CompletePnpRequest(Irp, status);
663 }
664
665 VOID
666 FxPkgPdo::HandleQueryCapabilities(
667 __inout PDEVICE_CAPABILITIES ReportedCaps,
668 __in_bcount(ParentCaps->size) PDEVICE_CAPABILITIES ParentCaps
669 )
670 {
671 LONG pnpCaps;
672 ULONG i;
673
674 //
675 // PowerSystemUnspecified is reserved for system use as per the DDK
676 //
677 for (i = PowerSystemWorking; i < PowerSystemMaximum; i++) {
678 DEVICE_POWER_STATE state;
679
680 state = _GetPowerCapState(i, m_PowerCaps.States);
681
682 if (state == PowerDeviceMaximum) {
683 //
684 // PDO did not specify any value, use parent's cap
685 //
686 #pragma prefast(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "Esp:675")
687 ReportedCaps->DeviceState[i] = ParentCaps->DeviceState[i];
688 }
689 else {
690 //
691 // Use PDO's reported value
692 //
693 ReportedCaps->DeviceState[i] = state;
694 }
695 }
696
697 pnpCaps = GetPnpCapsInternal();
698
699 //
700 // Appropriately fill the DeviceCapabilities structure.
701 //
702 SET_PNP_CAP(pnpCaps, ReportedCaps, LockSupported);
703 SET_PNP_CAP(pnpCaps, ReportedCaps, EjectSupported);
704 SET_PNP_CAP(pnpCaps, ReportedCaps, Removable);
705 SET_PNP_CAP(pnpCaps, ReportedCaps, DockDevice);
706 SET_PNP_CAP(pnpCaps, ReportedCaps, UniqueID);
707
708 if ((pnpCaps & FxPnpCapSilentInstallMask) != FxPnpCapSilentInstallUseDefault) {
709 SET_PNP_CAP(pnpCaps, ReportedCaps, SilentInstall);
710 }
711 else if (m_RawOK) {
712 //
713 // By default, we report raw devices as silent install devices
714 // because if they are raw, they don't need any further
715 // installation.
716 //
717 ReportedCaps->SilentInstall = TRUE;
718 }
719
720 SET_PNP_CAP(pnpCaps, ReportedCaps, SurpriseRemovalOK);
721 SET_PNP_CAP(pnpCaps, ReportedCaps, HardwareDisabled);
722 SET_PNP_CAP(pnpCaps, ReportedCaps, NoDisplayInUI);
723
724 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD0);
725 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD1);
726 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD2);
727 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD3);
728 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, DeviceD1);
729 SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, DeviceD2);
730
731 if (m_RawOK) {
732 ReportedCaps->RawDeviceOK = TRUE;
733 }
734
735 ReportedCaps->UINumber = m_PnpCapsUINumber;
736 ReportedCaps->Address = m_PnpCapsAddress;
737
738 if (m_PowerCaps.SystemWake != PowerSystemMaximum) {
739 ReportedCaps->SystemWake = (SYSTEM_POWER_STATE) m_PowerCaps.SystemWake;
740 }
741 else {
742 ReportedCaps->SystemWake = ParentCaps->SystemWake;
743 }
744
745 //
746 // Set the least-powered device state from which the device can
747 // wake the system.
748 //
749 if (m_PowerCaps.DeviceWake != PowerDeviceMaximum) {
750 ReportedCaps->DeviceWake = (DEVICE_POWER_STATE) m_PowerCaps.DeviceWake;
751 }
752 else {
753 ReportedCaps->DeviceWake = ParentCaps->DeviceWake;
754 }
755
756 //
757 // Set the Device wake up latencies.
758 //
759 if (m_PowerCaps.D1Latency != (ULONG) -1) {
760 ReportedCaps->D1Latency = m_PowerCaps.D1Latency;
761 }
762 else {
763 ReportedCaps->D1Latency = 0;
764 }
765
766 if (m_PowerCaps.D2Latency != (ULONG) -1) {
767 ReportedCaps->D2Latency = m_PowerCaps.D2Latency;
768 }
769 else {
770 ReportedCaps->D2Latency = 0;
771 }
772
773 if (m_PowerCaps.D3Latency != (ULONG) -1) {
774 ReportedCaps->D3Latency = m_PowerCaps.D3Latency;
775 }
776 }
777
778 VOID
_QueryCapsWorkItem(__in MdDeviceObject DeviceObject,__in PVOID Context)779 FxPkgPdo::_QueryCapsWorkItem(
780 __in MdDeviceObject DeviceObject,
781 __in PVOID Context
782 )
783 {
784 STACK_DEVICE_CAPABILITIES parentCapabilities;
785 MdWorkItem pItem;
786 FxPkgPdo* pPkgPdo;
787 FxIrp irp;
788 NTSTATUS status;
789 MxDeviceObject parentDeviceObject;
790
791 irp.SetIrp((MdIrp)Context);
792 pItem = (MdWorkItem) irp.GetContext(0);
793
794 pPkgPdo = FxDevice::GetFxDevice(DeviceObject)->GetPdoPkg();
795
796 parentDeviceObject.SetObject(
797 pPkgPdo->m_Device->m_ParentDevice->GetDeviceObject());
798
799 status = GetStackCapabilities(
800 pPkgPdo->m_Device->GetDriverGlobals(),
801 &parentDeviceObject,
802 NULL, // D3ColdInterface
803 &parentCapabilities);
804
805 if (NT_SUCCESS(status)) {
806 #pragma prefast(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "prefast is confused")
807 pPkgPdo->HandleQueryCapabilities(
808 irp.GetParameterDeviceCapabilities(),
809 &parentCapabilities.DeviceCaps
810 );
811 status = STATUS_SUCCESS;
812 }
813
814 pPkgPdo->CompletePnpRequest(&irp, status);
815
816 MxWorkItem::_Free(pItem);
817 }
818
819 FxDeviceText *
FindObjectForGivenLocale(__in PSINGLE_LIST_ENTRY Head,__in LCID LocaleId)820 FindObjectForGivenLocale(
821 __in PSINGLE_LIST_ENTRY Head,
822 __in LCID LocaleId
823 )
824
825 /*++
826
827 Routine Description:
828
829
830
831 Arguments:
832
833 Returns:
834
835 --*/
836
837 {
838 PSINGLE_LIST_ENTRY ple;
839
840 for (ple = Head->Next; ple != NULL; ple = ple->Next) {
841 FxDeviceText *pDeviceText;
842
843 pDeviceText= FxDeviceText::_FromEntry(ple);
844
845 if (pDeviceText->m_LocaleId == LocaleId) {
846 //
847 // We found our object!
848 //
849 return pDeviceText;
850 }
851 }
852
853 return NULL;
854 }
855
856 _Must_inspect_result_
857 NTSTATUS
_PnpQueryDeviceText(__inout FxPkgPnp * This,__inout FxIrp * Irp)858 FxPkgPdo::_PnpQueryDeviceText(
859 __inout FxPkgPnp* This,
860 __inout FxIrp *Irp
861 )
862
863 /*++
864
865 Routine Description:
866
867 This method is invoked in response to a Pnp QueryDeviceText IRP.
868 We return the decription or the location.
869
870 Arguments:
871
872 Irp - a pointer to the FxIrp
873
874 Returns:
875
876 NTSTATUS
877
878 --*/
879
880 {
881 FxPkgPdo* pThis;
882 LCID localeId;
883 FxDeviceText *pDeviceTextObject;
884 NTSTATUS status;
885 PFX_DRIVER_GLOBALS pFxDriverGlobals;
886
887 pThis = (FxPkgPdo*) This;
888 pFxDriverGlobals = pThis->GetDriverGlobals();
889
890 localeId = Irp->GetParameterQueryDeviceTextLocaleId();
891 status = Irp->GetStatus();
892
893 //
894 // The PDO package maintains a collection of "DeviceText" objects. We
895 // will look up the item in the collection with the "appropriate" locale.
896 //
897 // If no entries are found in the collection for the given locale, then
898 // we will use the "default locale" property of the PDO and use the
899 // entry for the "default locale".
900 //
901
902 //
903 // Try to find the FxDeviceText object for the given locale.
904 //
905 pDeviceTextObject = FindObjectForGivenLocale(
906 &pThis->m_DeviceTextHead, localeId);
907
908 if (pDeviceTextObject == NULL) {
909 pDeviceTextObject = FindObjectForGivenLocale(
910 &pThis->m_DeviceTextHead, pThis->m_DefaultLocale);
911 }
912
913 if (pDeviceTextObject != NULL) {
914 PWCHAR pInformation;
915
916 pInformation = NULL;
917
918 switch (Irp->GetParameterQueryDeviceTextType()) {
919 case DeviceTextDescription:
920 pInformation = pDeviceTextObject->m_Description;
921 break;
922
923 case DeviceTextLocationInformation:
924 pInformation = pDeviceTextObject->m_LocationInformation;
925 break;
926 }
927
928 //
929 // Information should now point to a valid unicode string.
930 //
931 if (pInformation != NULL) {
932 PWCHAR pBuffer;
933 size_t length;
934
935 length = (wcslen(pInformation) + 1) * sizeof(WCHAR);
936
937 //
938 // Make sure the information field of the IRP isn't already set.
939 //
940 ASSERT(Irp->GetInformation() == NULL);
941
942 pBuffer = (PWCHAR) MxMemory::MxAllocatePoolWithTag(
943 PagedPool, length, pFxDriverGlobals->Tag);
944
945 if (pBuffer != NULL) {
946 RtlCopyMemory(pBuffer, pInformation, length);
947 Irp->SetInformation((ULONG_PTR) pBuffer);
948
949 status = STATUS_SUCCESS;
950 }
951 else {
952 status = STATUS_INSUFFICIENT_RESOURCES;
953
954 DoTraceLevelMessage(
955 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
956 "WDFDEVICE %p failing Query Device Text, type %d, %!STATUS!",
957 pThis->m_Device->GetHandle(),
958 Irp->GetParameterQueryDeviceTextType(), status);
959 }
960 }
961 }
962
963 return pThis->CompletePnpRequest(Irp, status);
964 }
965
966 _Must_inspect_result_
967 NTSTATUS
_PnpEject(__inout FxPkgPnp * This,__inout FxIrp * Irp)968 FxPkgPdo::_PnpEject(
969 __inout FxPkgPnp* This,
970 __inout FxIrp *Irp
971 )
972 /*++
973
974 Routine Description:
975
976 Ejection is handled by the PnP state machine. Handle it synchronously.
977 Don't pend it since PnP manager does not serilaize it with other state
978 changing pnp irps if handled asynchronously.
979
980 Arguments:
981
982 This - the package
983
984 Irp - the request
985
986 Return Value:
987
988 NTSTATUS
989
990 --*/
991 {
992 MxEvent event;
993 FxPkgPdo* pdoPkg;
994 NTSTATUS status;
995
996 pdoPkg = (FxPkgPdo*)This;
997
998 //
999 // This will make sure no new state changing pnp irps arrive while
1000 // we are still processing this one. Also, note that irp is not being
1001 // marked pending.
1002 //
1003 pdoPkg->SetPendingPnpIrp(Irp, FALSE);
1004
1005 status = event.Initialize(SynchronizationEvent, FALSE);
1006 if (!NT_SUCCESS(status)) {
1007
1008 DoTraceLevelMessage(
1009 pdoPkg->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1010 "Event allocation failed while processing eject for WDFDEVICE %p,"
1011 " %!STATUS!",
1012 pdoPkg->m_Device->GetHandle(), status);
1013 }
1014 else {
1015 ASSERT(pdoPkg->m_DeviceEjectProcessed == NULL);
1016 pdoPkg->m_DeviceEjectProcessed = event.GetSelfPointer();
1017
1018 //
1019 // let state machine process eject
1020 //
1021 pdoPkg->PnpProcessEvent(PnpEventEject);
1022
1023 //
1024 // No need to wait in a critical region because we are in the context of a
1025 // pnp request which is in the system context.
1026 //
1027 event.WaitFor(Executive, KernelMode, FALSE, NULL);
1028
1029 pdoPkg->m_DeviceEjectProcessed = NULL;
1030
1031 status = Irp->GetStatus();
1032 }
1033
1034 //
1035 // complete request
1036 //
1037
1038 pdoPkg->ClearPendingPnpIrp();
1039 pdoPkg->CompletePnpRequest(Irp, status);
1040
1041 return status;
1042 }
1043
1044 WDF_DEVICE_PNP_STATE
PnpEventEjectHardwareOverload(VOID)1045 FxPkgPdo::PnpEventEjectHardwareOverload(
1046 VOID
1047 )
1048 /*++
1049
1050 Routine Description:
1051
1052 This function implements the EjectHardware state. This
1053 function overloads the base PnP State machine handler. Its
1054 job is to call EvtDeviceEject. If that succeeds, then we
1055 transition immediately to EjectedWaitingForRemove. If not,
1056 then to EjectFailed.
1057
1058 Arguments:
1059
1060 none
1061
1062 Return Value:
1063
1064 NTSTATUS
1065
1066 --*/
1067 {
1068 NTSTATUS status;
1069 WDF_DEVICE_PNP_STATE state;
1070
1071 status = m_DeviceEject.Invoke(m_Device->GetHandle());
1072
1073 if (NT_SUCCESS(status)) {
1074
1075 //
1076 // Upon a successful eject, mark the child as missing so that when we
1077 // get another QDR, it is not re-reported.
1078 //
1079 FxChildList* pList;
1080 MxEvent* event;
1081
1082 pList = m_Description->GetParentList();
1083
1084 status = pList->UpdateAsMissing(m_Description->GetId());
1085 if (NT_SUCCESS(status)) {
1086 DoTraceLevelMessage(
1087 GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
1088 "PDO WDFDEVICE %p !devobj %p marked missing as a result of eject",
1089 m_Device->GetHandle(), m_Device->GetDeviceObject());
1090 }
1091 else {
1092 DoTraceLevelMessage(
1093 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1094 "Failed to mark PDO WDFDEVICE %p !devobj %p missing after eject %!STATUS!",
1095 m_Device->GetHandle(), m_Device->GetDeviceObject(),
1096 status);
1097 }
1098
1099 //
1100 // We must wait for any pending scans to finish so that the previous
1101 // update as missing is enacted into the list and reported to the
1102 // OS. Otherwise, if we don't wait we could be in the middle of a
1103 // scan, complete the eject, report the child again and it will be
1104 // reenumerated.
1105 //
1106 event = pList->GetScanEvent();
1107
1108 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
1109 "waiting on event %p for device to finish scanning",
1110 &event);
1111
1112 //
1113 // No need to wait in a crtical region because we are in the context of a
1114 // pnp request which is in the system context.
1115 //
1116 event->WaitFor(Executive, KernelMode, FALSE, NULL);
1117
1118 //
1119 // Change the state.
1120 //
1121 state = WdfDevStatePnpEjectedWaitingForRemove;
1122 }
1123 else {
1124 state = WdfDevStatePnpEjectFailed;
1125 DoTraceLevelMessage(
1126 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1127 "Eject failed since driver's EvtDeviceEject returned %!STATUS!", status);
1128
1129 if (status == STATUS_NOT_SUPPORTED) {
1130 DoTraceLevelMessage(
1131 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE,
1132 "EvtDeviceEject returned an invalid status STATUS_NOT_SUPPORTED");
1133
1134 if (GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) {
1135 FxVerifierDbgBreakPoint(GetDriverGlobals());
1136 }
1137 }
1138 }
1139
1140 //
1141 // set irp status
1142 //
1143 SetPendingPnpIrpStatus(status);
1144
1145 //
1146 // Pnp dispatch routine is waiting on this event, and it will complete
1147 // the Eject irp
1148 //
1149 m_DeviceEjectProcessed->Set();
1150
1151 return state;
1152 }
1153
1154 WDF_DEVICE_PNP_STATE
PnpEventCheckForDevicePresenceOverload(VOID)1155 FxPkgPdo::PnpEventCheckForDevicePresenceOverload(
1156 VOID
1157 )
1158 /*++
1159
1160 Routine Description:
1161
1162 This function implements the CheckForDevicePresence state. This
1163 function overloads the base PnP State machine handler. It's
1164 job is to figure out whether the removed device is actually
1165 still attached. It then changes state based on that result.
1166
1167 Arguments:
1168
1169 none
1170
1171 Return Value:
1172
1173 NTSTATUS
1174
1175 --*/
1176
1177 {
1178 if (m_Description != NULL) {
1179 if (m_Description->IsDeviceRemoved()) {
1180 //
1181 // The description freed itself now that the device has been reported
1182 // missing.
1183 //
1184 return WdfDevStatePnpPdoRemoved;
1185 }
1186 else {
1187 //
1188 // Device was not reported as missing, keep it alive
1189 //
1190 return WdfDevStatePnpRemovedPdoWait;
1191 }
1192 }
1193 else {
1194 //
1195 // Only static children can get this far without having an m_Description
1196 //
1197 ASSERT(m_Static);
1198
1199 //
1200 // The description freed itself now that the device has been reported
1201 // missing.
1202 //
1203 return WdfDevStatePnpPdoRemoved;
1204 }
1205 }
1206
1207 WDF_DEVICE_PNP_STATE
PnpEventPdoRemovedOverload(VOID)1208 FxPkgPdo::PnpEventPdoRemovedOverload(
1209 VOID
1210 )
1211 /*++
1212
1213 Routine Description:
1214
1215 This function implements the Removed state. This
1216 function overloads the base PnP State machine handler.
1217
1218 Arguments:
1219
1220 none
1221
1222 Return Value:
1223
1224 NTSTATUS
1225
1226 --*/
1227 {
1228 m_CanBeDeleted = TRUE;
1229
1230 //
1231 // Unconditionally delete the symbolic link now (vs calling
1232 // DeleteSymbolicLinkOverload()) because we know that the device has been
1233 // reported as missing.
1234 //
1235 m_Device->DeleteSymbolicLink();
1236
1237 //
1238 // Do that which all device stacks need to do upon removal.
1239 //
1240 PnpEventRemovedCommonCode();
1241
1242 //
1243 // m_Device is Release()'ed in FxPkgPnp::PnpEventFinal
1244 //
1245 if (m_Description != NULL) {
1246 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
1247 "Removing entry reference %p on FxPkgPnp %p",
1248 m_Description, this);
1249
1250 m_Description->ProcessDeviceRemoved();
1251 m_Description = NULL;
1252 }
1253
1254 return WdfDevStatePnpFinal;
1255 }
1256
1257 WDF_DEVICE_PNP_STATE
PnpGetPostRemoveState(VOID)1258 FxPkgPdo::PnpGetPostRemoveState(
1259 VOID
1260 )
1261 {
1262 //
1263 // Transition to the check for device presence state.
1264 //
1265 return WdfDevStatePnpCheckForDevicePresence;
1266 }
1267
1268 WDF_DEVICE_PNP_STATE
PnpEventFdoRemovedOverload(VOID)1269 FxPkgPdo::PnpEventFdoRemovedOverload(
1270 VOID
1271 )
1272 {
1273 ASSERT(!"This should only be implemented for FDOs.");
1274
1275 //
1276 // Do something safe. Act like the device is not present.
1277 //
1278 return WdfDevStatePnpFinal;
1279 }
1280
1281 VOID
PnpEventSurpriseRemovePendingOverload(VOID)1282 FxPkgPdo::PnpEventSurpriseRemovePendingOverload(
1283 VOID
1284 )
1285 {
1286 if (m_Description != NULL) {
1287 m_Description->DeviceSurpriseRemoved();
1288 }
1289
1290 FxPkgPnp::PnpEventSurpriseRemovePendingOverload();
1291 }
1292
1293 BOOLEAN
PnpSendStartDeviceDownTheStackOverload(VOID)1294 FxPkgPdo::PnpSendStartDeviceDownTheStackOverload(
1295 VOID
1296 )
1297 /*++
1298
1299 Routine Description:
1300 Process the start irp on the way down the stack during a start.
1301
1302 Since the PDO is the bottom, just move to the new state where we
1303 are processing the irp up the stack.
1304
1305 Arguments:
1306 None
1307
1308 Return Value:
1309 TRUE, the completion of the start irp down the stack was synchronous
1310
1311 --*/
1312 {
1313 //
1314 // We are successful so far, indicate this in the irp.
1315 //
1316 SetPendingPnpIrpStatus(STATUS_SUCCESS);
1317
1318 return TRUE;
1319 }
1320
1321 _Must_inspect_result_
1322 NTSTATUS
_PnpSetLock(__inout FxPkgPnp * This,__inout FxIrp * Irp)1323 FxPkgPdo::_PnpSetLock(
1324 __inout FxPkgPnp* This,
1325 __inout FxIrp *Irp
1326 )
1327 /*++
1328
1329 Routine Description:
1330 Set lock
1331
1332 Arguments:
1333 This - the package
1334
1335 Irp - the irp
1336
1337 Return Value:
1338 NTSTATUS
1339
1340 --*/
1341 {
1342 NTSTATUS status;
1343 BOOLEAN lock;
1344
1345 lock = Irp->GetParameterSetLockLock();
1346
1347 status = ((FxPkgPdo*) This)->m_DeviceSetLock.Invoke(
1348 ((FxPkgPdo*) This)->m_Device->GetHandle(), lock);
1349
1350 if (NT_SUCCESS(status)) {
1351 Irp->SetInformation(NULL);
1352 }
1353
1354 return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, status);
1355 }
1356
1357 _Must_inspect_result_
1358 NTSTATUS
_PnpQueryId(__inout FxPkgPnp * This,__inout FxIrp * Irp)1359 FxPkgPdo::_PnpQueryId(
1360 __inout FxPkgPnp* This,
1361 __inout FxIrp *Irp
1362 )
1363 {
1364 FxPkgPdo* pThis;
1365 NTSTATUS status;
1366 PWCHAR pBuffer;
1367 PCWSTR pSrc;
1368 size_t cbLength;
1369 PFX_DRIVER_GLOBALS pFxDriverGlobals;
1370 BUS_QUERY_ID_TYPE queryIdType;
1371
1372 pThis = (FxPkgPdo*) This;
1373 pFxDriverGlobals = pThis->GetDriverGlobals();
1374 status = Irp->GetStatus();
1375 cbLength = 0;
1376
1377 queryIdType = Irp->GetParameterQueryIdType();
1378
1379 switch (queryIdType) {
1380 case BusQueryDeviceID:
1381 case BusQueryInstanceID:
1382 case BusQueryContainerID:
1383 if (queryIdType == BusQueryDeviceID) {
1384 pSrc = pThis->m_DeviceID;
1385 }
1386 else if (queryIdType == BusQueryInstanceID) {
1387 pSrc = pThis->m_InstanceID;
1388 }
1389 else {
1390 pSrc = pThis->m_ContainerID;
1391 }
1392
1393 if (pSrc != NULL) {
1394 cbLength = (wcslen(pSrc) + 1) * sizeof(WCHAR);
1395
1396 pBuffer = (PWCHAR) MxMemory::MxAllocatePoolWithTag(
1397 PagedPool, cbLength, pFxDriverGlobals->Tag);
1398 }
1399 else {
1400 status = Irp->GetStatus();
1401 break;
1402 }
1403
1404 if (pBuffer != NULL) {
1405
1406 //
1407 // This will copy the NULL terminator too
1408 //
1409 RtlCopyMemory(pBuffer, pSrc, cbLength);
1410 Irp->SetInformation((ULONG_PTR) pBuffer);
1411 status = STATUS_SUCCESS;
1412 }
1413 else {
1414 status = STATUS_INSUFFICIENT_RESOURCES;
1415 }
1416 break;
1417
1418 case BusQueryHardwareIDs:
1419 case BusQueryCompatibleIDs:
1420 if (queryIdType == BusQueryHardwareIDs) {
1421 pSrc = pThis->m_HardwareIDs;
1422 }
1423 else {
1424 pSrc = pThis->m_CompatibleIDs;
1425 }
1426
1427 if (pSrc != NULL) {
1428 cbLength = FxCalculateTotalMultiSzStringSize(pSrc);
1429 }
1430 else {
1431 //
1432 // Must return an empty list
1433 //
1434 cbLength = 2 * sizeof(UNICODE_NULL);
1435 }
1436
1437 pBuffer = (PWCHAR) MxMemory::MxAllocatePoolWithTag(
1438 PagedPool, cbLength, pFxDriverGlobals->Tag);
1439
1440 if (pBuffer != NULL) {
1441 if (pSrc != NULL) {
1442 RtlCopyMemory(pBuffer, pSrc, cbLength);
1443 }
1444 else {
1445 RtlZeroMemory(pBuffer, cbLength);
1446 }
1447
1448 Irp->SetInformation((ULONG_PTR) pBuffer);
1449 status = STATUS_SUCCESS;
1450 }
1451 else {
1452 status = STATUS_INSUFFICIENT_RESOURCES;
1453 }
1454 break;
1455 }
1456
1457 if (!NT_SUCCESS(status)) {
1458 Irp->SetInformation(NULL);
1459
1460 if (status == STATUS_NOT_SUPPORTED) {
1461 DoTraceLevelMessage(
1462 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1463 "WDFDEVICE %p does not have a string for PnP query IdType "
1464 "%!BUS_QUERY_ID_TYPE!, %!STATUS!",
1465 pThis->m_Device->GetHandle(),
1466 queryIdType, status);
1467 }
1468 else {
1469 DoTraceLevelMessage(
1470 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
1471 "WDFDEVICE %p could not alloc string for PnP query IdType "
1472 "%!BUS_QUERY_ID_TYPE!, %!STATUS!",
1473 pThis->m_Device->GetHandle(),
1474 queryIdType, status);
1475 }
1476 }
1477
1478 return ((FxPkgPdo*) pThis)->CompletePnpRequest(Irp, status);
1479 }
1480
1481 _Must_inspect_result_
1482 NTSTATUS
_PnpQueryPnpDeviceState(__inout FxPkgPnp * This,__inout FxIrp * Irp)1483 FxPkgPdo::_PnpQueryPnpDeviceState(
1484 __inout FxPkgPnp* This,
1485 __inout FxIrp *Irp
1486 )
1487 /*++
1488
1489 Routine Description:
1490 indicates the current device state
1491
1492 Arguments:
1493 This - the package
1494
1495 Irp - the request
1496
1497 Return Value:
1498 NTSTATUS
1499
1500 --*/
1501 {
1502 PNP_DEVICE_STATE pnpDeviceState;
1503 PFX_DRIVER_GLOBALS FxDriverGlobals = This->GetDriverGlobals();
1504
1505 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
1506 "Entering QueryPnpDeviceState handler");
1507
1508 pnpDeviceState = ((FxPkgPdo*) This)->HandleQueryPnpDeviceState(
1509 (PNP_DEVICE_STATE) Irp->GetInformation());
1510
1511 Irp->SetInformation((ULONG_PTR) pnpDeviceState);
1512
1513 DoTraceLevelMessage(
1514 FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP,
1515 "WDFDEVICE 0x%p !devobj 0x%p returning PNP_DEVICE_STATE 0x%d IRP 0x%p",
1516 This->GetDevice()->GetHandle(),
1517 This->GetDevice()->GetDeviceObject(),
1518 pnpDeviceState,
1519 Irp->GetIrp());
1520
1521 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
1522 "Exiting QueryPnpDeviceState handler");
1523
1524 return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, STATUS_SUCCESS);
1525 }
1526
1527 _Must_inspect_result_
1528 NTSTATUS
_PnpQueryBusInformation(__inout FxPkgPnp * This,__inout FxIrp * Irp)1529 FxPkgPdo::_PnpQueryBusInformation(
1530 __inout FxPkgPnp* This,
1531 __inout FxIrp *Irp
1532 )
1533 /*++
1534
1535 Routine Description:
1536 Returns the bus information for this child
1537
1538 Arguments:
1539 This - the package
1540
1541 Irp - the request
1542
1543 Return Value:
1544 NTSTATUS
1545
1546 --*/
1547 {
1548 FxPkgPdo* pThis;
1549 NTSTATUS status;
1550
1551 pThis = (FxPkgPdo*) This;
1552
1553 status = pThis->m_Device->m_ParentDevice->m_PkgPnp->
1554 HandleQueryBusInformation(Irp);
1555
1556 return pThis->CompletePnpRequest(Irp, status);
1557 }
1558
1559 _Must_inspect_result_
1560 NTSTATUS
_PnpSurpriseRemoval(__inout FxPkgPnp * This,__inout FxIrp * Irp)1561 FxPkgPdo::_PnpSurpriseRemoval(
1562 __inout FxPkgPnp* This,
1563 __inout FxIrp *Irp
1564 )
1565 {
1566 FxPkgPdo* pThis;
1567
1568 pThis = (FxPkgPdo*) This;
1569
1570 pThis->m_Description->DeviceSurpriseRemoved();
1571
1572 return pThis->PnpSurpriseRemoval(Irp);
1573 }
1574
1575 VOID
RegisterCallbacks(__in PWDF_PDO_EVENT_CALLBACKS DispatchTable)1576 FxPkgPdo::RegisterCallbacks(
1577 __in PWDF_PDO_EVENT_CALLBACKS DispatchTable
1578 )
1579 {
1580 m_DeviceResourcesQuery.m_Method = DispatchTable->EvtDeviceResourcesQuery;
1581 m_DeviceResourceRequirementsQuery.m_Method = DispatchTable->EvtDeviceResourceRequirementsQuery;
1582 m_DeviceEject.m_Method = DispatchTable->EvtDeviceEject;
1583 m_DeviceSetLock.m_Method = DispatchTable->EvtDeviceSetLock;
1584
1585 m_DeviceEnableWakeAtBus.m_Method = DispatchTable->EvtDeviceEnableWakeAtBus;
1586 m_DeviceDisableWakeAtBus.m_Method = DispatchTable->EvtDeviceDisableWakeAtBus;
1587
1588 //
1589 // this callback was added in V1.11
1590 //
1591 if (DispatchTable->Size > sizeof(WDF_PDO_EVENT_CALLBACKS_V1_9)) {
1592 m_DeviceReportedMissing.m_Method = DispatchTable->EvtDeviceReportedMissing;
1593 }
1594 }
1595
1596 _Must_inspect_result_
1597 NTSTATUS
AskParentToRemoveAndReenumerate(VOID)1598 FxPkgPdo::AskParentToRemoveAndReenumerate(
1599 VOID
1600 )
1601 /*++
1602
1603 Routine Description:
1604 This routine asks the PDO to ask its parent bus driver to Surprise-Remove
1605 and re-enumerate the PDO. This will be done only at the point of
1606 catastrophic software failure, and occasionally after catastrophic hardware
1607 failure.
1608
1609 Arguments:
1610 None
1611
1612 Return Value:
1613 status
1614
1615 --*/
1616 {
1617 //
1618 // Static children do not support reenumeration.
1619 //
1620 if (m_Description != NULL && m_Static == FALSE) {
1621 m_Description->GetParentList()->ReenumerateEntry(m_Description);
1622 return STATUS_SUCCESS;
1623 }
1624
1625 return STATUS_NOT_FOUND;
1626 }
1627
1628
1629 VOID
DeleteSymbolicLinkOverload(__in BOOLEAN GracefulRemove)1630 FxPkgPdo::DeleteSymbolicLinkOverload(
1631 __in BOOLEAN GracefulRemove
1632 )
1633 /*++
1634
1635 Routine Description:
1636 Role specific virtual function which determines if the symbolic link for a
1637 device should be deleted.
1638
1639 Arguments:
1640 None
1641
1642 Return Value:
1643 None
1644
1645 --*/
1646 {
1647 if (GracefulRemove) {
1648 //
1649 // We will remove the symbolic link when we determine if the PDO was
1650 // reported missing or not.
1651 //
1652 return;
1653 }
1654 else if (m_Description->IsDeviceReportedMissing()) {
1655 //
1656 // Surprise removed and we have reported the PDO as missing
1657 //
1658
1659 m_Device->DeleteSymbolicLink();
1660 }
1661 }
1662
1663
1664 VOID
_RemoveAndReenumerateSelf(__in PVOID Context)1665 FxPkgPdo::_RemoveAndReenumerateSelf(
1666 __in PVOID Context
1667 )
1668 /*++
1669
1670 Routine Description:
1671 This routine is passed out to higher-level drivers as part of the
1672 re-enumeration interface.
1673
1674 Arguments:
1675 This
1676
1677 Return Value:
1678 void
1679
1680 --*/
1681 {
1682 ((FxPkgPdo*) Context)->AskParentToRemoveAndReenumerate();
1683 }
1684
1685 _Must_inspect_result_
1686 NTSTATUS
HandleQueryInterfaceForReenumerate(__in FxIrp * Irp,__out PBOOLEAN CompleteRequest)1687 FxPkgPdo::HandleQueryInterfaceForReenumerate(
1688 __in FxIrp* Irp,
1689 __out PBOOLEAN CompleteRequest
1690 )
1691 /*++
1692
1693 Routine Description:
1694 Handles a query interface on the PDO for the self reenumeration interface.
1695
1696 Arguments:
1697 Irp - the request containing the QI
1698
1699 CompleteRequest - whether the caller should complete the request when this
1700 call returns
1701
1702 Return Value:
1703 status to complete the irp with
1704
1705 --*/
1706 {
1707 PREENUMERATE_SELF_INTERFACE_STANDARD pInterface;
1708 NTSTATUS status;
1709
1710 *CompleteRequest = TRUE;
1711
1712 if (m_Static) {
1713 //
1714 // Return the embedded status in the irp since this is a statically
1715 // enumerated child. Only dynamically enuemrated child support self
1716 // reenumeration.
1717 //
1718 return Irp->GetStatus();
1719 }
1720
1721 if (Irp->GetParameterQueryInterfaceVersion() == 1 &&
1722 Irp->GetParameterQueryInterfaceSize() >= sizeof(*pInterface)) {
1723
1724 pInterface = (PREENUMERATE_SELF_INTERFACE_STANDARD)
1725 Irp->GetParameterQueryInterfaceInterface();
1726
1727 //
1728 // Expose the interface to the requesting driver.
1729 //
1730 pInterface->Version = 1;
1731 pInterface->Size = sizeof(*pInterface);
1732 pInterface->Context = this;
1733 pInterface->InterfaceReference = FxDevice::_InterfaceReferenceNoOp;
1734 pInterface->InterfaceDereference = FxDevice::_InterfaceDereferenceNoOp;
1735 pInterface->SurpriseRemoveAndReenumerateSelf = &FxPkgPdo::_RemoveAndReenumerateSelf;
1736
1737 status = STATUS_SUCCESS;
1738
1739 //
1740 // Caller assumes a reference has been taken.
1741 //
1742 pInterface->InterfaceReference(pInterface->Context);
1743 }
1744 else {
1745 status = STATUS_INVALID_BUFFER_SIZE;
1746 }
1747
1748 return status;
1749 }
1750
1751 _Must_inspect_result_
1752 NTSTATUS
ProcessRemoveDeviceOverload(__inout FxIrp * Irp)1753 FxPkgPdo::ProcessRemoveDeviceOverload(
1754 __inout FxIrp* Irp
1755 )
1756 {
1757 if (m_CanBeDeleted) {
1758 //
1759 // After this is called, any irp dispatched to FxDevice::DispatchWithLock
1760 // will fail with STATUS_INVALID_DEVICE_REQUEST.
1761 //
1762
1763
1764
1765
1766
1767
1768
1769 Mx::MxReleaseRemoveLockAndWait(
1770 m_Device->GetRemoveLock(),
1771 Irp->GetIrp()
1772 );
1773
1774 //
1775 // Cleanup the state machines and release the power thread.
1776 //
1777 CleanupStateMachines(TRUE);
1778
1779 //
1780 // Detach and delete the device object.
1781 //
1782 DeleteDevice();
1783
1784 //
1785 // Can't call CompletePnpRequest because we just released the tag in
1786 // IoReleaseRemoveLockAndWait above.
1787 //
1788 Irp->CompleteRequest(IO_NO_INCREMENT);
1789
1790 return STATUS_SUCCESS;
1791 }
1792 else {
1793 //
1794 // This was a PDO which was not reported missing, so do not free the
1795 // memory and clear out our stack local address.
1796 //
1797 m_DeviceRemoveProcessed = NULL;
1798 return CompletePnpRequest(Irp, Irp->GetStatus());
1799 }
1800 }
1801
1802 _Must_inspect_result_
1803 NTSTATUS
QueryForPowerThread(VOID)1804 FxPkgPdo::QueryForPowerThread(
1805 VOID
1806 )
1807 /*++
1808
1809 Routine Description:
1810 Since the PDO is the lowest device in the stack, it does not have to send
1811 a query down the stack. Rather, it just creates the thread and returns.
1812
1813 Arguments:
1814 None
1815
1816 Return Value:
1817 NTSTATUS
1818
1819 --*/
1820 {
1821 return CreatePowerThread();
1822 }
1823
1824 _Must_inspect_result_
1825 NTSTATUS
AddEjectionDevice(__in MdDeviceObject DependentDevice)1826 FxPkgPdo::AddEjectionDevice(
1827 __in MdDeviceObject DependentDevice
1828 )
1829 {
1830 FxRelatedDevice* pRelated;
1831 NTSTATUS status;
1832
1833 if (m_EjectionDeviceList == NULL) {
1834 KIRQL irql;
1835
1836 Lock(&irql);
1837 if (m_EjectionDeviceList == NULL) {
1838 m_EjectionDeviceList = new (GetDriverGlobals()) FxRelatedDeviceList();
1839
1840 if (m_EjectionDeviceList != NULL) {
1841 status = STATUS_SUCCESS;
1842 }
1843 else {
1844 status = STATUS_INSUFFICIENT_RESOURCES;
1845 DoTraceLevelMessage(
1846 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1847 "Could not allocate ejection device list for PDO WDFDEVICE %p",
1848
1849 m_Device->GetHandle());
1850 }
1851 }
1852 else {
1853 //
1854 // another thread allocated the list already
1855 //
1856 status = STATUS_SUCCESS;
1857 }
1858 Unlock(irql);
1859
1860 if (!NT_SUCCESS(status)) {
1861 return status;
1862 }
1863 }
1864
1865 pRelated = new(GetDriverGlobals())
1866 FxRelatedDevice(DependentDevice, GetDriverGlobals());
1867
1868 if (pRelated == NULL) {
1869 return STATUS_INSUFFICIENT_RESOURCES;
1870 }
1871
1872 status = m_EjectionDeviceList->Add(GetDriverGlobals(), pRelated);
1873
1874 if (NT_SUCCESS(status)) {
1875 //
1876 // EjectRelations are queried automatically by PnP when the device is
1877 // going to be ejected. No need to tell pnp that the list changed
1878 // until it needs to query for it.
1879 //
1880 DO_NOTHING();
1881 }
1882 else {
1883 pRelated->DeleteFromFailedCreate();
1884 }
1885
1886 return status;
1887 }
1888
1889 VOID
RemoveEjectionDevice(__in MdDeviceObject DependentDevice)1890 FxPkgPdo::RemoveEjectionDevice(
1891 __in MdDeviceObject DependentDevice
1892 )
1893 {
1894 if (m_EjectionDeviceList != NULL) {
1895 m_EjectionDeviceList->Remove(GetDriverGlobals(), DependentDevice);
1896 }
1897
1898 //
1899 // EjectRelations are queried automatically by PnP when the device is
1900 // going to be ejected. No need to tell pnp that the list changed
1901 // until it needs to query for it.
1902 //
1903 }
1904
1905 VOID
ClearEjectionDevicesList(VOID)1906 FxPkgPdo::ClearEjectionDevicesList(
1907 VOID
1908 )
1909 {
1910 FxRelatedDevice* pEntry;
1911
1912 if (m_EjectionDeviceList != NULL) {
1913 m_EjectionDeviceList->LockForEnum(GetDriverGlobals());
1914 while ((pEntry = m_EjectionDeviceList->GetNextEntry(NULL)) != NULL) {
1915 m_EjectionDeviceList->Remove(GetDriverGlobals(),
1916 pEntry->GetDevice());
1917 }
1918 m_EjectionDeviceList->UnlockFromEnum(GetDriverGlobals());
1919 }
1920
1921 //
1922 // EjectRelations are queried automatically by PnP when the device is
1923 // going to be ejected. No need to tell pnp that the list changed
1924 // until it needs to query for it.
1925 //
1926 }
1927