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
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
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
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
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
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
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
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
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