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 Kernel mode only
21
22 Revision History:
23
24
25
26 --*/
27
28 #include "../pnppriv.hpp"
29
30 #include <initguid.h>
31 #include <wdmguid.h>
32
33
34 #if defined(EVENT_TRACING)
35 // Tracing support
36 extern "C" {
37 #include "FxPkgFdoKm.tmh"
38 }
39 #endif
40
41 _Must_inspect_result_
42 NTSTATUS
PnpFilterResourceRequirements(__inout FxIrp * Irp)43 FxPkgFdo::PnpFilterResourceRequirements(
44 __inout FxIrp *Irp
45 )
46
47 /*++
48
49 Routine Description:
50
51 This method is invoked in response to a Pnp FilterResourceRequirements IRP.
52
53 Arguments:
54
55 Device - a pointer to the FxDevice
56
57 Irp - a pointer to the FxIrp
58
59 Returns:
60
61 NTSTATUS
62
63 --*/
64
65 {
66 PIO_RESOURCE_REQUIREMENTS_LIST pWdmRequirementsList;
67 PIO_RESOURCE_REQUIREMENTS_LIST pNewWdmList;
68 NTSTATUS status;
69 FxIoResReqList *pIoResReqList;
70 WDFIORESREQLIST reqlist;
71
72 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
73 "Entering FilterResourceRequirements handler");
74
75 if (m_DeviceFilterRemoveResourceRequirements.m_Method != NULL) {
76
77 pWdmRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST) Irp->GetInformation();
78
79 status = STATUS_INSUFFICIENT_RESOURCES;
80
81 pIoResReqList = FxIoResReqList::_CreateFromWdmList(GetDriverGlobals(),
82 pWdmRequirementsList,
83 FxResourceAllAccessAllowed);
84
85 if (pIoResReqList != NULL) {
86 status = pIoResReqList->Commit(NULL, (PWDFOBJECT) &reqlist);
87
88 // Commit should never fail because we own all object state
89 ASSERT(NT_SUCCESS(status));
90 UNREFERENCED_PARAMETER(status);
91
92 status = m_DeviceFilterRemoveResourceRequirements.Invoke(
93 m_Device->GetHandle(), pIoResReqList->GetHandle());
94
95 if (NT_SUCCESS(status) && pIoResReqList->IsChanged()) {
96 pNewWdmList = pIoResReqList->CreateWdmList();
97
98 if (pNewWdmList != NULL) {
99 //
100 // List could be missing previously
101 //
102 if (pWdmRequirementsList != NULL) {
103 //
104 // Propagate BusNumber to our new list.
105 //
106 pNewWdmList->BusNumber = pWdmRequirementsList->BusNumber;
107
108 MxMemory::MxFreePool(pWdmRequirementsList);
109 }
110
111 Irp->SetInformation((ULONG_PTR) pNewWdmList);
112 }
113 else {
114 status = STATUS_INSUFFICIENT_RESOURCES;
115 }
116 }
117
118 //
119 // No matter what, free the resource requirements list object. If
120 // we need another one when adding resources, another one will be
121 // allocated.
122 //
123 pIoResReqList->DeleteObject();
124 pIoResReqList = NULL;
125 }
126 }
127 else {
128 //
129 // No filtering on the way down, set status to STATUS_SUCCESS so we
130 // send the irp down the stack.
131 //
132 status = STATUS_SUCCESS;
133 }
134
135 if (NT_SUCCESS(status)) {
136 status = SendIrpSynchronously(Irp);
137 }
138
139 //
140 // If we do not handle the IRP on the way down and the PDO does not handle
141 // the IRP, we can have a status of STATUS_NOT_SUPPORTED. We still want to
142 // process the irp in this state.
143 //
144 if (NT_SUCCESS(status) || status == STATUS_NOT_SUPPORTED) {
145 NTSTATUS filterStatus;
146
147 //
148 // Give the Framework objects a pass at the list.
149 //
150 filterStatus = FxPkgPnp::FilterResourceRequirements(
151 (PIO_RESOURCE_REQUIREMENTS_LIST*)(&Irp->GetIrp()->IoStatus.Information)
152 );
153
154 if (!NT_SUCCESS(filterStatus)) {
155 status = filterStatus;
156 }
157 else if (m_DeviceFilterAddResourceRequirements.m_Method != NULL) {
158 //
159 // Now give the driver a shot at it.
160 //
161 pWdmRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST)
162 Irp->GetInformation();
163
164 pIoResReqList = FxIoResReqList::_CreateFromWdmList(
165 GetDriverGlobals(), pWdmRequirementsList, FxResourceAllAccessAllowed);
166
167 if (pIoResReqList != NULL) {
168 status = pIoResReqList->Commit(NULL, (PWDFOBJECT) &reqlist);
169 UNREFERENCED_PARAMETER(status);
170
171 //
172 // Since we absolutely control the lifetime of pIoResReqList, this
173 // should never fail
174 //
175 ASSERT(NT_SUCCESS(status));
176
177 status = m_DeviceFilterAddResourceRequirements.Invoke(
178 m_Device->GetHandle(), reqlist);
179
180 //
181 // It is possible the child driver modified the resource list,
182 // and if so we need to update the requirements list.
183 //
184 if (NT_SUCCESS(status) && pIoResReqList->IsChanged()) {
185 pNewWdmList = pIoResReqList->CreateWdmList();
186
187 if (pNewWdmList != NULL) {
188 //
189 // List could be missing previously
190 //
191 if (pWdmRequirementsList != NULL) {
192 //
193 // Propagate BusNumber to our new list.
194 //
195 pNewWdmList->BusNumber = pWdmRequirementsList->BusNumber;
196
197 ExFreePool(pWdmRequirementsList);
198 }
199
200 Irp->SetInformation((ULONG_PTR) pNewWdmList);
201 }
202 else {
203 status = STATUS_INSUFFICIENT_RESOURCES;
204 }
205 }
206
207 pIoResReqList->DeleteObject();
208 pIoResReqList = NULL;
209 }
210 else {
211 status = STATUS_INSUFFICIENT_RESOURCES;
212 }
213 }
214 }
215
216 CompletePnpRequest(Irp, status);
217
218 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP,
219 "Exiting FilterResourceRequirements handler, %!STATUS!",
220 status);
221
222 return status;
223 }
224
225 _Must_inspect_result_
226 NTSTATUS
_PnpQueryCapabilitiesCompletionRoutine(__in MdDeviceObject DeviceObject,__inout MdIrp Irp,__inout PVOID Context)227 FxPkgFdo::_PnpQueryCapabilitiesCompletionRoutine(
228 __in MdDeviceObject DeviceObject,
229 __inout MdIrp Irp,
230 __inout PVOID Context
231 )
232 {
233 UNREFERENCED_PARAMETER(DeviceObject);
234 UNREFERENCED_PARAMETER(Irp);
235 UNREFERENCED_PARAMETER(Context);
236
237 ASSERTMSG("Not implemented for KMDF\n", FALSE);
238
239 return STATUS_NOT_IMPLEMENTED;
240 }
241
242 _Must_inspect_result_
243 NTSTATUS
PnpQueryCapabilities(__inout FxIrp * Irp)244 FxPkgFdo::PnpQueryCapabilities(
245 __inout FxIrp *Irp
246 )
247
248 /*++
249
250 Routine Description:
251
252 This method is invoked in response to a Pnp QueryCapabilities IRP.
253
254 Arguments:
255
256 Device - a pointer to the FxDevice
257
258 Irp - a pointer to the FxIrp
259
260 Returns:
261
262 NTSTATUS
263
264 --*/
265
266 {
267 NTSTATUS status;
268
269 HandleQueryCapabilities(Irp);
270
271 status = SendIrpSynchronously(Irp);
272
273 //
274 // Now that the IRP has returned to us, we modify what the bus driver
275 // set up.
276 //
277 if (NT_SUCCESS(status)) {
278 HandleQueryCapabilitiesCompletion(Irp);
279 }
280
281 CompletePnpRequest(Irp, status);
282
283 return status;
284 }
285
286 _Must_inspect_result_
287 NTSTATUS
_PnpQueryPnpDeviceStateCompletionRoutine(__in MdDeviceObject DeviceObject,__inout MdIrp Irp,__inout PVOID Context)288 FxPkgFdo::_PnpQueryPnpDeviceStateCompletionRoutine(
289 __in MdDeviceObject DeviceObject,
290 __inout MdIrp Irp,
291 __inout PVOID Context
292 )
293 {
294 UNREFERENCED_PARAMETER(DeviceObject);
295 UNREFERENCED_PARAMETER(Irp);
296 UNREFERENCED_PARAMETER(Context);
297
298 ASSERTMSG("Not implemented for KMDF\n", FALSE);
299
300 return STATUS_NOT_IMPLEMENTED;
301 }
302
303 _Must_inspect_result_
304 NTSTATUS
_PnpQueryPnpDeviceState(__inout FxPkgPnp * This,__inout FxIrp * Irp)305 FxPkgFdo::_PnpQueryPnpDeviceState(
306 __inout FxPkgPnp* This,
307 __inout FxIrp *Irp
308 )
309
310 /*++
311
312 Routine Description:
313
314 This method is invoked in response to a Pnp QueryPnpDeviceState IRP.
315
316 Arguments:
317
318 Irp - a pointer to the FxIrp
319
320 Returns:
321
322 NTSTATUS
323
324 --*/
325
326 {
327 FxPkgFdo* pThis;
328 NTSTATUS status;
329
330 pThis = (FxPkgFdo*) This;
331
332 status = pThis->SendIrpSynchronously(Irp);
333
334 if (status == STATUS_NOT_SUPPORTED) {
335 //
336 // Morph into a successful code so that we process the request
337 //
338 status = STATUS_SUCCESS;
339 Irp->SetStatus(status);
340 }
341
342 if (NT_SUCCESS(status)) {
343 pThis->HandleQueryPnpDeviceStateCompletion(Irp);
344 }
345 else {
346 DoTraceLevelMessage(
347 This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
348 "Lower stack returned error for query pnp device state, %!STATUS!",
349 status);
350 }
351
352 //
353 // Since we already sent the request down the stack, we must complete it
354 // now.
355 //
356 return pThis->CompletePnpRequest(Irp, status);
357 }
358
359 _Must_inspect_result_
360 NTSTATUS
Initialize(__in PWDFDEVICE_INIT DeviceInit)361 FxPkgFdo::Initialize(
362 __in PWDFDEVICE_INIT DeviceInit
363 )
364 /*++
365
366
367
368
369
370
371
372
373 Routine Description:
374
375 After creating a FxPkgFdo, the driver writer will initialize it by passing
376 a set of driver callbacks that allow the driver writer to customize the
377 behavior when handling certain IRPs.
378
379 This is the place to do any initialization that might fail.
380
381 Arguments:
382
383 Device - a pointer to the FxDevice
384
385 DispatchTable - a driver supplied table of callbacks
386
387 Returns:
388
389 NTSTATUS
390
391 --*/
392 {
393 PFX_DRIVER_GLOBALS pGlobals;
394 WDF_CHILD_LIST_CONFIG config;
395 size_t totalDescriptionSize = 0;
396 WDFCHILDLIST hList;
397 NTSTATUS status;
398
399 pGlobals = GetDriverGlobals();
400
401 status = FxPkgPnp::Initialize(DeviceInit);
402 if (!NT_SUCCESS(status)) {
403 return status;
404 }
405
406 status = AllocateEnumInfo();
407 if (!NT_SUCCESS(status)) {
408 return status;
409 }
410
411 #pragma prefast(suppress: __WARNING_PASSING_FUNCTION_UNEXPECTED_NULL, "Static child lists do not use the EvtChildListCreateDevice callback")
412 WDF_CHILD_LIST_CONFIG_INIT(&config,
413 sizeof(FxStaticChildDescription),
414 NULL);
415
416 status = FxChildList::_ComputeTotalDescriptionSize(pGlobals,
417 &config,
418 &totalDescriptionSize);
419 if (!NT_SUCCESS(status)) {
420 return status;
421 }
422
423 status = FxChildList::_CreateAndInit(&m_StaticDeviceList,
424 pGlobals,
425 WDF_NO_OBJECT_ATTRIBUTES,
426 totalDescriptionSize,
427 m_Device,
428 &config,
429 TRUE);
430 if (!NT_SUCCESS(status)) {
431 return status;
432 }
433
434 status = m_StaticDeviceList->Commit(WDF_NO_OBJECT_ATTRIBUTES,
435 (WDFOBJECT*) &hList,
436 m_Device);
437
438 if (!NT_SUCCESS(status)) {
439 m_StaticDeviceList->DeleteFromFailedCreate();
440 m_StaticDeviceList = NULL;
441
442 return status;
443 }
444
445 //
446 // This will be released in the destructor
447 //
448 m_StaticDeviceList->ADDREF(this);
449
450 return status;
451 }
452
453 _Must_inspect_result_
454 NTSTATUS
QueryForDsfInterface(VOID)455 FxPkgFdo::QueryForDsfInterface(
456 VOID
457 )
458 {
459 // __REACTOS__ : not supported
460 // WDF_DSF_INTERFACE dsfInterface;
461 // NTSTATUS status;
462 // BOOLEAN derefQI = FALSE;
463
464 // RtlZeroMemory(&dsfInterface, sizeof(dsfInterface));
465
466 // //
467 // // Since there are some stacks that are not PnP re-entrant (like USBHUB,
468 // // xpsp2), we specify that the QI goes only to our attached device and
469 // // not to the top of the stack as a normal QI irp would.
470 // //
471 // // We also do this a preventative measure for other stacks we don't know
472 // // about internally and do not have access to when testing.
473 // //
474 // status = m_Device->QueryForInterface(&GUID_WDF_DSF_INTERFACE,
475 // (PINTERFACE) &dsfInterface,
476 // sizeof(dsfInterface),
477 // WDM_DSF_INTERFACE_V1_0,
478 // NULL,
479 // m_Device->GetAttachedDevice()
480 // );
481
482 // if (status == STATUS_NOT_SUPPORTED) {
483 // DoTraceLevelMessage(
484 // GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP,
485 // "Lower stack does not have a DSF interface");
486 // status = STATUS_SUCCESS;
487 // goto Done;
488 // }
489
490 // if (!NT_SUCCESS(status)) {
491 // DoTraceLevelMessage(
492 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
493 // "Lower stack returned an error for query DSF interface, %!STATUS!",
494 // status);
495 // goto Done;
496 // }
497
498 // derefQI = TRUE;
499
500 // //
501 // // Basic run time checks.
502 // //
503 // if (dsfInterface.Interface.Version != WDM_DSF_INTERFACE_V1_0) {
504 // status = STATUS_REVISION_MISMATCH;
505 // DoTraceLevelMessage(
506 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
507 // "Lower DSF stack supports v(%x), requested v(%x), %!STATUS!",
508 // dsfInterface.Interface.Version,
509 // WDM_DSF_INTERFACE_V1_0,
510 // status);
511 // goto Done;
512 // }
513
514 // //
515 // // Ex functions should be both set or cleared.
516 // // Active/Inactive functions should be both set or cleared.
517 // // Ex function must be present.
518 // // Note: !!(ptr) expression below converts ptr value to true/false value.
519 // // I.e., ptr==NULL to false and ptr!=NULL to true.
520 // //
521 // if (!((!!(dsfInterface.IoConnectInterruptEx) ==
522 // !!(dsfInterface.IoDisconnectInterruptEx)) &&
523 // (!!(dsfInterface.IoReportInterruptActive) ==
524 // !!(dsfInterface.IoReportInterruptInactive)) &&
525 // (dsfInterface.IoConnectInterruptEx != NULL)
526 // )) {
527 // status = STATUS_DATA_ERROR;
528 // DoTraceLevelMessage(
529 // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
530 // "Function mismatch detected in DSF interface, %!STATUS!",
531 // status);
532 // goto Done;
533 // }
534
535 // //
536 // // Info is correct.
537 // //
538 // m_IoConnectInterruptEx = dsfInterface.IoConnectInterruptEx;
539 // m_IoDisconnectInterruptEx = dsfInterface.IoDisconnectInterruptEx;
540
541 // //
542 // // If DSF interface provides active/inactive functions then use them
543 // //
544 // if (dsfInterface.IoReportInterruptActive != NULL)
545 // {
546 // m_IoReportInterruptActive = dsfInterface.IoReportInterruptActive;
547 // m_IoReportInterruptInactive = dsfInterface.IoReportInterruptInactive;
548 // }
549
550 // Done:
551
552 // //
553 // // The contract with the DSF layer is to release the interface right away;
554 // // the embedded interrupt function ptrs will be valid until this driver is
555 // // unloaded.
556 // //
557 // if (derefQI) {
558 // dsfInterface.Interface.InterfaceDereference(dsfInterface.Interface.Context);
559 // }
560
561 // return status;
562 return STATUS_NOT_IMPLEMENTED;
563 }
564
565 _Must_inspect_result_
566 NTSTATUS
AskParentToRemoveAndReenumerate(VOID)567 FxPkgFdo::AskParentToRemoveAndReenumerate(
568 VOID
569 )
570 /*++
571
572 Routine Description:
573 This routine asks the PDO to ask its parent bus driver to Surprise-Remove
574 and re-enumerate the PDO. This will be done only at the point of
575 catastrophic software failure, and occasionally after catastrophic hardware
576 failure.
577
578 Arguments:
579 None
580
581 Return Value:
582 status
583
584 --*/
585 {
586 PREENUMERATE_SELF_INTERFACE_STANDARD pInterface;
587
588 pInterface = &m_SurpriseRemoveAndReenumerateSelfInterface;
589
590 if (pInterface->SurpriseRemoveAndReenumerateSelf != NULL) {
591 pInterface->SurpriseRemoveAndReenumerateSelf(pInterface->Context);
592
593 return STATUS_SUCCESS;
594 }
595
596 return STATUS_NOT_SUPPORTED;
597 }
598
599