1 //
2 // Copyright (C) Microsoft. All rights reserved.
3 //
4 #include "../pnppriv.hpp"
5
6 #include <initguid.h>
7 #include <wdmguid.h>
8
9 extern "C" {
10 #if defined(EVENT_TRACING)
11 #include "FxPkgPnpKM.tmh"
12 #endif
13 }
14
15 NTSTATUS
FilterResourceRequirements(__in IO_RESOURCE_REQUIREMENTS_LIST ** IoList)16 FxPkgPnp::FilterResourceRequirements(
17 __in IO_RESOURCE_REQUIREMENTS_LIST **IoList
18 )
19 /*++
20
21 Routine Description:
22
23 This routine traverses one or more alternate _IO_RESOURCE_LISTs in the input
24 IO_RESOURCE_REQUIREMENTS_LIST looking for interrupt descriptor and applies
25 the policy set by driver in the interrupt object to the resource descriptor.
26
27 LBI - Line based interrupt
28 MSI - Message Signalled interrupt
29
30 Here are the assumptions made about the order of descriptors.
31
32 - An IoRequirementList can have one or more alternate IoResourceList
33 - Each IoResourceList can have one or more resource descriptors
34 - A descriptor can be default (unique), preferred, or alternate descriptors
35 - A preferred descriptor can have zero or more alternate descriptors (P, A, A, A..)
36 - In an IoResourceList, there can be one or more LBI descriptors
37 (non-pci devices)(P,A,P,A)
38 - In an IoResourceList, there can be only one preferred MSI 2.2
39 (single or multi message) descriptor
40 - In an IoResourceList, there cannot be MSI2.2 and MSI-X descriptors
41 - In an IoResourceList, there can be one or more MSI-X descriptor
42 - An alternate descriptor cannot be a very first descriptor in the list
43
44
45 Now with that assumption, this routines parses the list looking for interrupt
46 descriptor.
47
48 - If it finds a LBI, it starts with the very first interrupt object and applies
49 the policy set by the driver to the resource descriptor.
50 - If it's finds an MSI2.2 then it starts with the first interrupt object and applies
51 the policy. If the MSI2.2 is a multi-message one then it loops thru looking for
52 as many interrupt object as there are messages. It doesn't fail the IRP, if the
53 interrupt objects are less than the messages.
54 - If there is an alternate descriptor then it applies the same policy from the
55 interrupt object that it used for the preceding preferred descriptor.
56 - Framework always uses FULLY_SPECIFIED connection type for both LBI and MSI
57 interrupts including MSI-X
58 - Framework will apply the policy on the descriptor set by the driver only
59 if the policy is already not included in the resource descriptor. This is
60 to allow the policy set in the registry to take precedence over the hard
61 coded driver policy.
62 - If the driver registers filter resource requirement and applies the policy
63 on its own (by escaping to WDM) then framework doesn't override that.
64
65 Arguments:
66
67 IoList - Pointer to the list part of an IRP_MN_FILTER_RESOURCE_REQUIREMENTS.
68
69 Return Value:
70
71 NTSTATUS
72
73 --*/
74 {
75 ULONG altResListIndex;
76 PIO_RESOURCE_REQUIREMENTS_LIST pIoRequirementList;
77 PIO_RESOURCE_LIST pIoResList;
78
79 pIoRequirementList = *IoList;
80
81 if (pIoRequirementList == NULL) {
82 return STATUS_SUCCESS;
83 }
84
85 if (IsListEmpty(&m_InterruptListHead)) {
86 //
87 // No interrupt objects created to filter resource requirements.
88 //
89 return STATUS_SUCCESS;
90 }
91
92 pIoResList = pIoRequirementList->List;
93
94 //
95 // Parse one or more alternative resource lists.
96 //
97 for (altResListIndex = 0;
98 altResListIndex < pIoRequirementList->AlternativeLists;
99 altResListIndex++) {
100 PLIST_ENTRY pIntListEntryForMSI;
101 PLIST_ENTRY pIntListEntryForLBI;
102 BOOLEAN multiMessageMSI22Found;
103 BOOLEAN previousDescMSI;
104 ULONG descIndex;
105
106 multiMessageMSI22Found = FALSE;
107 previousDescMSI = FALSE;
108
109 pIntListEntryForMSI = &m_InterruptListHead;
110 pIntListEntryForLBI = &m_InterruptListHead;
111
112 //
113 // Traverse each _IO_RESOURCE_LISTs looking for interrupt descriptors
114 // and call FilterResourceRequirements method so that it can apply
115 // policy set on the interrupt object into the resource-descriptor.
116 //
117
118 for (descIndex = 0; descIndex < pIoResList->Count; descIndex++) {
119 ULONG messageCount;
120 PIO_RESOURCE_DESCRIPTOR pIoDesc;
121 FxInterrupt* pInterruptInstance;
122
123 pIoDesc = &pIoResList->Descriptors[descIndex];
124
125 switch (pIoDesc->Type) {
126 case CmResourceTypeInterrupt:
127
128 if (FxInterrupt::_IsMessageInterrupt(pIoDesc->Flags)) {
129
130 previousDescMSI = TRUE;
131
132 //
133 // We will advance to the next interrupt object if the resource
134 // is not an alternate resource descriptor. A resource list can
135 // have a preferred and zero or more alternate resource descriptors
136 // for the same resource. We need to apply the same policy on the
137 // alternate desc that we applied on the preferred one in case one
138 // of the alernate desc is selected for this device. An alternate
139 // resource descriptor can't be the first descriptor in a list.
140 //
141 if ((pIoDesc->Option & IO_RESOURCE_ALTERNATIVE) == 0) {
142 pIntListEntryForMSI = pIntListEntryForMSI->Flink;
143 }
144
145 if (pIntListEntryForMSI == &m_InterruptListHead) {
146 DoTraceLevelMessage(
147 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
148 "Not enough interrupt objects created for MSI by WDFDEVICE 0x%p ",
149 m_Device->GetHandle());
150 break;
151 }
152
153 pInterruptInstance = CONTAINING_RECORD(pIntListEntryForMSI, FxInterrupt, m_PnpList);
154 messageCount = pIoDesc->u.Interrupt.MaximumVector - pIoDesc->u.Interrupt.MinimumVector + 1;
155
156 if (messageCount > 1) {
157 //
158 // PCI spec guarantees that there can be only one preferred/default
159 // MSI 2.2 descriptor in a single list.
160 //
161 if ((pIoDesc->Option & IO_RESOURCE_ALTERNATIVE) == 0) {
162 #if DBG
163 ASSERT(multiMessageMSI22Found == FALSE);
164 #else
165 UNREFERENCED_PARAMETER(multiMessageMSI22Found);
166 #endif
167 multiMessageMSI22Found = TRUE;
168
169 }
170 }
171 else {
172 //
173 // This is either single message MSI 2.2 or MSI-X interrupts
174 //
175 DO_NOTHING();
176 }
177
178 pInterruptInstance->FilterResourceRequirements(pIoDesc);
179 }
180 else {
181
182 //
183 // We will advance to next interrupt object if the desc is not an alternate
184 // descriptor. For non PCI devices, the first LBI interrupt desc can't be an
185 // alternate descriptor.
186 //
187 if ((pIoDesc->Option & IO_RESOURCE_ALTERNATIVE) == 0) {
188 pIntListEntryForLBI = pIntListEntryForLBI->Flink;
189 }
190
191 //
192 // An LBI can be first alternate resource if there are preceding MSI(X) descriptors
193 // listed in the list. In that case, this descriptor is the alternate interrupt resource
194 // for all of the MSI messages. As a result, we will use the first interrupt object from
195 // the list if this ends up being assigned by the system instead of MSI.
196 //
197 if (previousDescMSI) {
198 ASSERT(pIoDesc->Option & IO_RESOURCE_ALTERNATIVE);
199 pIntListEntryForLBI = m_InterruptListHead.Flink;
200 previousDescMSI = FALSE;
201 }
202
203 //
204 // There can be one or more LBI interrupts and each LBI interrupt
205 // could have zero or more alternate descriptors.
206 //
207 if (pIntListEntryForLBI == &m_InterruptListHead) {
208 DoTraceLevelMessage(
209 GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
210 "Not enough interrupt objects created for LBI by WDFDEVICE 0x%p ",
211 m_Device->GetHandle());
212 break;
213 }
214
215 pInterruptInstance = CONTAINING_RECORD(pIntListEntryForLBI, FxInterrupt, m_PnpList);
216
217 pInterruptInstance->FilterResourceRequirements(pIoDesc);
218 }
219
220 break;
221
222 default:
223 break;
224 }
225 }
226
227 //
228 // Since the Descriptors is a variable length list, you cannot get to the next
229 // alternate list by doing pIoRequirementList->List[altResListIndex].
230 // Descriptors[descIndex] will now point to the end of the descriptor list.
231 // If there is another alternate list, it would be begin there.
232 //
233 pIoResList = (PIO_RESOURCE_LIST) &pIoResList->Descriptors[descIndex];
234 }
235
236 return STATUS_SUCCESS;
237 }
238
239 _Must_inspect_result_
240 NTSTATUS
AllocateDmaEnablerList(VOID)241 FxPkgPnp::AllocateDmaEnablerList(
242 VOID
243 )
244 {
245 FxSpinLockTransactionedList* pList;
246 NTSTATUS status;
247 KIRQL irql;
248
249 if (m_DmaEnablerList != NULL) {
250 return STATUS_SUCCESS;
251 }
252
253 Lock(&irql);
254 if (m_DmaEnablerList == NULL) {
255 pList = new (GetDriverGlobals()) FxSpinLockTransactionedList();
256
257 if (pList != NULL) {
258 m_DmaEnablerList = pList;
259 status = STATUS_SUCCESS;
260 }
261 else {
262 status = STATUS_INSUFFICIENT_RESOURCES;
263 }
264 }
265 else {
266 //
267 // Already have a DMA list
268 //
269 status = STATUS_SUCCESS;
270 }
271 Unlock(irql);
272
273 return status;
274 }
275
276 VOID
AddDmaEnabler(__in FxDmaEnabler * Enabler)277 FxPkgPnp::AddDmaEnabler(
278 __in FxDmaEnabler* Enabler
279 )
280 {
281 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
282 "Adding DmaEnabler %p, WDFDMAENABLER %p",
283 Enabler, Enabler->GetObjectHandle());
284
285 m_DmaEnablerList->Add(GetDriverGlobals(), &Enabler->m_TransactionLink);
286 }
287
288 VOID
RemoveDmaEnabler(__in FxDmaEnabler * Enabler)289 FxPkgPnp::RemoveDmaEnabler(
290 __in FxDmaEnabler* Enabler
291 )
292 {
293 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
294 "Removing DmaEnabler %p, WDFDMAENABLER %p",
295 Enabler, Enabler->GetObjectHandle());
296
297 m_DmaEnablerList->Remove(GetDriverGlobals(), &Enabler->m_TransactionLink);
298 }
299
300 VOID
WriteStateToRegistry(__in HANDLE RegKey,__in PUNICODE_STRING ValueName,__in ULONG Value)301 FxPkgPnp::WriteStateToRegistry(
302 __in HANDLE RegKey,
303 __in PUNICODE_STRING ValueName,
304 __in ULONG Value
305 )
306 {
307 ZwSetValueKey(RegKey, ValueName, 0, REG_DWORD, &Value, sizeof(Value));
308 }
309
310 // NTSTATUS __REACTOS__
311 // FxPkgPnp::UpdateWmiInstanceForS0Idle(
312 // __in FxWmiInstanceAction Action
313 // )
314 // {
315 // FxWmiProvider* pProvider;
316 // NTSTATUS status;
317
318 // switch(Action) {
319 // case AddInstance:
320 // if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.WmiInstance == NULL) {
321 // FxWmiInstanceInternalCallbacks cb;
322
323 // cb.SetInstance = _S0IdleSetInstance;
324 // cb.QueryInstance = _S0IdleQueryInstance;
325 // cb.SetItem = _S0IdleSetItem;
326
327 // status = RegisterPowerPolicyWmiInstance(
328 // &GUID_POWER_DEVICE_ENABLE,
329 // &cb,
330 // &m_PowerPolicyMachine.m_Owner->m_IdleSettings.WmiInstance);
331
332 // if (!NT_SUCCESS(status)) {
333 // return status;
334 // }
335 // }
336 // else {
337 // pProvider = m_PowerPolicyMachine.m_Owner->m_IdleSettings.
338 // WmiInstance->GetProvider();
339
340 // //
341 // // Enable the WMI GUID by adding the instance back to the provider's
342 // // list. If there is an error, ignore it. It just means we were
343 // // racing with another thread removing or adding the instance.
344 // //
345 // (void) pProvider->AddInstance(
346 // m_PowerPolicyMachine.m_Owner->m_IdleSettings.WmiInstance,
347 // TRUE
348 // );
349 // }
350 // break;
351
352 // case RemoveInstance:
353 // if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.WmiInstance != NULL) {
354 // //
355 // // Disable the WMI guid by removing it from the provider's list of
356 // // instances.
357 // //
358 // pProvider = m_PowerPolicyMachine.m_Owner->m_IdleSettings.
359 // WmiInstance->GetProvider();
360
361 // pProvider->RemoveInstance(
362 // m_PowerPolicyMachine.m_Owner->m_IdleSettings.WmiInstance
363 // );
364 // }
365 // break;
366
367 // default:
368 // ASSERT(FALSE);
369 // break;
370 // }
371
372 // return STATUS_SUCCESS;;
373 // }
374
375 VOID
ReadRegistryS0Idle(__in PCUNICODE_STRING ValueName,__out BOOLEAN * Enabled)376 FxPkgPnp::ReadRegistryS0Idle(
377 __in PCUNICODE_STRING ValueName,
378 __out BOOLEAN *Enabled
379 )
380 {
381 NTSTATUS status;
382 FxAutoRegKey hKey;
383
384 status = m_Device->OpenSettingsKey(&hKey.m_Key, STANDARD_RIGHTS_READ);
385
386 //
387 // Modify the value of Enabled only if success
388 //
389 if (NT_SUCCESS(status)) {
390 ULONG value;
391
392 status = FxRegKey::_QueryULong(
393 hKey.m_Key, ValueName, &value);
394
395 if (NT_SUCCESS(status)) {
396 //
397 // Normalize the ULONG value into a BOOLEAN
398 //
399 *Enabled = (value == FALSE) ? FALSE : TRUE;
400 }
401 }
402 }
403
404 // NTSTATUS __REACTOS__
405 // FxPkgPnp::UpdateWmiInstanceForSxWake(
406 // __in FxWmiInstanceAction Action
407 // )
408 // {
409 // FxWmiProvider* pProvider;
410 // NTSTATUS status;
411
412 // switch(Action) {
413 // case AddInstance:
414 // if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.WmiInstance == NULL) {
415 // FxWmiInstanceInternalCallbacks cb;
416
417 // cb.SetInstance = _SxWakeSetInstance;
418 // cb.QueryInstance = _SxWakeQueryInstance;
419 // cb.SetItem = _SxWakeSetItem;
420
421 // status = RegisterPowerPolicyWmiInstance(
422 // &GUID_POWER_DEVICE_WAKE_ENABLE,
423 // &cb,
424 // &m_PowerPolicyMachine.m_Owner->m_WakeSettings.WmiInstance);
425
426 // if (!NT_SUCCESS(status)) {
427 // return status;
428 // }
429 // } else {
430 // pProvider = m_PowerPolicyMachine.m_Owner->m_WakeSettings.
431 // WmiInstance->GetProvider();
432
433 // //
434 // // Enable the WMI GUID by adding the instance back to the provider's
435 // // list. If there is an error, ignore it. It just means we were
436 // // racing with another thread removing or adding the instance.
437 // //
438 // (void) pProvider->AddInstance(
439 // m_PowerPolicyMachine.m_Owner->m_WakeSettings.WmiInstance,
440 // TRUE
441 // );
442 // }
443 // break;
444
445 // case RemoveInstance:
446 // if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.WmiInstance != NULL) {
447 // //
448 // // Disable the WMI guid by removing it from the provider's list of
449 // // instances.
450 // //
451 // pProvider = m_PowerPolicyMachine.m_Owner->m_WakeSettings.
452 // WmiInstance->GetProvider();
453
454 // pProvider->RemoveInstance(
455 // m_PowerPolicyMachine.m_Owner->m_WakeSettings.WmiInstance
456 // );
457 // }
458 // break;
459
460 // default:
461 // ASSERT(FALSE);
462 // break;
463 // }
464
465 // return STATUS_SUCCESS;
466 // }
467
468 VOID
ReadRegistrySxWake(__in PCUNICODE_STRING ValueName,__out BOOLEAN * Enabled)469 FxPkgPnp::ReadRegistrySxWake(
470 __in PCUNICODE_STRING ValueName,
471 __out BOOLEAN *Enabled
472 )
473 {
474 FxAutoRegKey hKey;
475 NTSTATUS status;
476
477 status = m_Device->OpenSettingsKey(&hKey.m_Key, STANDARD_RIGHTS_READ);
478
479 //
480 // Modify the value of Enabled only if success
481 //
482 if (NT_SUCCESS(status)) {
483 ULONG value;
484
485 status = FxRegKey::_QueryULong(
486 hKey.m_Key, ValueName, &value);
487
488 if (NT_SUCCESS(status)) {
489 //
490 // Normalize the ULONG value into a BOOLEAN
491 //
492 *Enabled = (value == FALSE) ? FALSE : TRUE;
493 }
494 }
495 }
496
497 VOID
PnpPassThroughQIWorker(__in MxDeviceObject * Device,__inout FxIrp * Irp,__inout FxIrp * ForwardIrp)498 PnpPassThroughQIWorker(
499 __in MxDeviceObject* Device,
500 __inout FxIrp* Irp,
501 __inout FxIrp* ForwardIrp
502 )
503 {
504 PIO_STACK_LOCATION pFwdStack, pCurStack;
505
506 pCurStack = Irp->GetCurrentIrpStackLocation();
507
508 ForwardIrp->SetStatus(STATUS_NOT_SUPPORTED);
509
510 pFwdStack = ForwardIrp->GetNextIrpStackLocation();
511 pFwdStack->MajorFunction = Irp->GetMajorFunction();
512 pFwdStack->MinorFunction = Irp->GetMinorFunction();
513
514 RtlCopyMemory(&pFwdStack->Parameters.QueryInterface,
515 &pCurStack->Parameters.QueryInterface,
516 sizeof(pFwdStack->Parameters.QueryInterface));
517
518 ForwardIrp->SetInformation(Irp->GetInformation());
519 ForwardIrp->SendIrpSynchronously(Device->GetObject());
520
521 pFwdStack = ForwardIrp->GetNextIrpStackLocation();
522
523 RtlCopyMemory(&pCurStack->Parameters.QueryInterface,
524 &pFwdStack->Parameters.QueryInterface,
525 sizeof(pCurStack->Parameters.QueryInterface));
526 }
527
528 VOID
RevokeDmaEnablerResources(__in FxDmaEnabler * DmaEnabler)529 FxPkgPnp::RevokeDmaEnablerResources(
530 __in FxDmaEnabler *DmaEnabler
531 )
532 {
533 // DmaEnabler->RevokeResources();
534 ROSWDFNOTIMPLEMENTED;
535 }
536
537 VOID
QueryForD3ColdInterface(VOID)538 FxPkgPnp::QueryForD3ColdInterface(
539 VOID
540 )
541 {
542 MxDeviceObject deviceObject;
543 PDEVICE_OBJECT topOfStack;
544 PDEVICE_OBJECT pdo;
545 FxAutoIrp irp;
546 NTSTATUS status;
547
548 //
549 // This function can be invoked multiple times, particularly if filters
550 // send IRP_MN_QUERY_CAPABILITIES. So bail out if the interface has already
551 // been acquired.
552 //
553
554 if ((m_D3ColdInterface.InterfaceDereference != NULL) ||
555 (m_D3ColdInterface.GetIdleWakeInfo != NULL) ||
556 (m_D3ColdInterface.SetD3ColdSupport != NULL)) {
557 return;
558 }
559
560 pdo = m_Device->GetPhysicalDevice();
561
562 if (pdo == NULL) {
563 return;
564 }
565
566 //
567 // Get the top of stack device object, even though normal filters and the
568 // FDO may not have been added to the stack yet to ensure that this
569 // query-interface is seen by bus filters. Specifically, in a PCI device
570 // which is soldered to the motherboard, ACPI will be on the stack and it
571 // needs to see this IRP.
572 //
573 topOfStack = IoGetAttachedDeviceReference(pdo);
574 deviceObject.SetObject(topOfStack);
575 if (deviceObject.GetObject() != NULL) {
576 irp.SetIrp(FxIrp::AllocateIrp(deviceObject.GetStackSize()));
577 if (irp.GetIrp() == NULL) {
578
579 DoTraceLevelMessage(
580 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
581 "Failed to allocate IRP to get D3COLD_SUPPORT_INTERFACE from !devobj %p",
582 pdo);
583 } else {
584
585 //
586 // Initialize the Irp
587 //
588 irp.SetStatus(STATUS_NOT_SUPPORTED);
589
590 irp.ClearNextStack();
591 irp.SetMajorFunction(IRP_MJ_PNP);
592 irp.SetMinorFunction(IRP_MN_QUERY_INTERFACE);
593 irp.SetParameterQueryInterfaceType(&GUID_D3COLD_SUPPORT_INTERFACE);
594 irp.SetParameterQueryInterfaceVersion(D3COLD_SUPPORT_INTERFACE_VERSION);
595 irp.SetParameterQueryInterfaceSize(sizeof(m_D3ColdInterface));
596 irp.SetParameterQueryInterfaceInterfaceSpecificData(NULL);
597 irp.SetParameterQueryInterfaceInterface((PINTERFACE)&m_D3ColdInterface);
598
599 status = irp.SendIrpSynchronously(deviceObject.GetObject());
600
601 if (!NT_SUCCESS(status)) {
602 DoTraceLevelMessage(
603 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
604 "!devobj %p declined to supply D3COLD_SUPPORT_INTERFACE",
605 pdo);
606
607 RtlZeroMemory(&m_D3ColdInterface, sizeof(m_D3ColdInterface));
608 }
609 }
610 }
611 ObDereferenceObject(topOfStack);
612 }
613
614 VOID
DropD3ColdInterface(VOID)615 FxPkgPnp::DropD3ColdInterface(
616 VOID
617 )
618 {
619 if (m_D3ColdInterface.InterfaceDereference != NULL) {
620 m_D3ColdInterface.InterfaceDereference(m_D3ColdInterface.Context);
621 }
622
623 RtlZeroMemory(&m_D3ColdInterface, sizeof(m_D3ColdInterface));
624 }
625
626