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