1 /*++ 2 3 Copyright (C) Microsoft Corporation. All rights reserved. 4 5 Module Name: 6 7 zpodd.c 8 9 Abstract: 10 11 Code for Zero Power ODD support. 12 13 Environment: 14 15 kernel mode only 16 17 Notes: 18 19 20 Revision History: 21 22 --*/ 23 24 #include "ntddk.h" 25 #include "ntddstor.h" 26 #include "wdmguid.h" 27 #include "cdrom.h" 28 #include "mmc.h" 29 #include "ioctl.h" 30 #include "scratch.h" 31 32 #ifdef DEBUG_USE_WPP 33 #include "zpodd.tmh" 34 #endif 35 36 _IRQL_requires_max_(PASSIVE_LEVEL) 37 ULONG 38 DeviceGetZPODDEnabledFromRegistry(); 39 40 _IRQL_requires_max_(PASSIVE_LEVEL) 41 NTSTATUS 42 DeviceQueryD3ColdInterface( 43 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 44 _Out_ PD3COLD_SUPPORT_INTERFACE D3ColdInterface 45 ); 46 47 _IRQL_requires_max_(PASSIVE_LEVEL) 48 NTSTATUS 49 DeviceSendEnableIdlePowerIoctl( 50 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 51 _In_ BOOLEAN WakeCapable, 52 _In_ BOOLEAN Enable, 53 _In_ ULONG D3IdleTimeout 54 ); 55 56 #if ALLOC_PRAGMA 57 58 #pragma alloc_text(PAGE, DeviceInitializeZPODD) 59 #pragma alloc_text(PAGE, DeviceGetZPODDEnabledFromRegistry) 60 #pragma alloc_text(PAGE, DeviceQueryD3ColdInterface) 61 #pragma alloc_text(PAGE, DeviceSendEnableIdlePowerIoctl) 62 #pragma alloc_text(PAGE, DeviceReleaseZPODDResources) 63 #pragma alloc_text(PAGE, DeviceZPODDIsInHomePosition) 64 #pragma alloc_text(PAGE, DeviceMarkActive) 65 66 #endif 67 68 #pragma warning(push) 69 #pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression 70 #pragma warning(disable:26000) // read overflow reported because of pointer type conversion 71 72 _IRQL_requires_max_(PASSIVE_LEVEL) 73 NTSTATUS 74 DeviceInitializeZPODD( 75 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension 76 ) 77 /*++ 78 79 Routine Description: 80 81 This routine initialize the contents of ZPODD structure. 82 83 Arguments: 84 85 DeviceExtension - the device extension 86 87 Return Value: 88 NTSTATUS 89 90 --*/ 91 { 92 NTSTATUS status = STATUS_SUCCESS; 93 NTSTATUS tempStatus = STATUS_SUCCESS; 94 PZERO_POWER_ODD_INFO zpoddInfo = NULL; 95 PFEATURE_DATA_REMOVABLE_MEDIUM removableMediumHeader = NULL; 96 ULONG ZPODDEnabledInRegistry = 0; 97 PD3COLD_SUPPORT_INTERFACE d3ColdInterface = NULL; 98 DEVICE_WAKE_DEPTH deepestWakeableDstate = DeviceWakeDepthNotWakeable; 99 BOOLEAN inHomePosition = FALSE; 100 101 PAGED_CODE(); 102 103 if (DeviceExtension->ZeroPowerODDInfo != NULL) 104 { 105 // 106 // Already initialized. 107 // 108 109 goto Cleanup; 110 } 111 112 ZPODDEnabledInRegistry = DeviceGetZPODDEnabledFromRegistry(); 113 114 if (ZPODDEnabledInRegistry == 0) 115 { 116 // 117 // User has explicitly disabled Zero Power ODD. 118 // 119 120 status = STATUS_NOT_SUPPORTED; 121 122 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 123 "DeviceInitializeZPODD: ZPODD not enabled due to registry settings.\n" 124 )); 125 126 goto Cleanup; 127 } 128 129 zpoddInfo = ExAllocatePoolWithTag(NonPagedPoolNx, 130 sizeof(ZERO_POWER_ODD_INFO), 131 CDROM_TAG_ZERO_POWER_ODD); 132 133 if (zpoddInfo == NULL) 134 { 135 status = STATUS_INSUFFICIENT_RESOURCES; 136 137 goto Cleanup; 138 } 139 140 RtlZeroMemory(zpoddInfo, sizeof (ZERO_POWER_ODD_INFO)); 141 142 // 143 // Check the system for the following prerequisites: 144 // 145 // 1. SATA: Device Attention line 146 // 2. SATA: Asynchronous Notification 147 // 3. ODD: LoChange / MediaRemoval 148 // 4. ACPI: Wake capable 149 // 150 // Only drawer and slot loading types have well defined behaviors in the spec, so only these two 151 // types are supported. 152 // 153 154 // 155 // Check for DA & AN 156 // 157 158 if ((DeviceExtension->PowerDescriptor == NULL) || 159 (DeviceExtension->PowerDescriptor->DeviceAttentionSupported == FALSE) || 160 (DeviceExtension->PowerDescriptor->AsynchronousNotificationSupported == FALSE)) 161 { 162 status = STATUS_NOT_SUPPORTED; 163 164 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 165 "DeviceInitializeZPODD: ZPODD not enabled due to SATA features not present.\n" 166 )); 167 168 goto Cleanup; 169 } 170 171 // 172 // Check for LoChange / MediaRemoval 173 // 174 175 removableMediumHeader = (PFEATURE_DATA_REMOVABLE_MEDIUM) 176 DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer, 177 DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize, 178 FeatureRemovableMedium); 179 180 if ((removableMediumHeader == NULL) || 181 (!((removableMediumHeader->LoadingMechanism == LOADING_MECHANISM_TRAY) && (removableMediumHeader->Load == 0) && // Drawer ... 182 (removableMediumHeader->DBML != FALSE)) && // requires LoChange/NotBusy 183 !((removableMediumHeader->LoadingMechanism == LOADING_MECHANISM_CADDY) && (removableMediumHeader->Load == 0) && // Slot ... 184 (DeviceExtension->MediaChangeDetectionInfo->Gesn.Supported != FALSE)))) // requires MediaRemoval 185 { 186 status = STATUS_NOT_SUPPORTED; 187 188 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 189 "DeviceInitializeZPODD: ZPODD not enabled due to ODD features not present.\n" 190 )); 191 192 goto Cleanup; 193 } 194 195 zpoddInfo->LoadingMechanism = removableMediumHeader->LoadingMechanism; 196 zpoddInfo->Load = removableMediumHeader->Load; 197 198 // 199 // Check for ACPI 200 // 201 202 status = DeviceQueryD3ColdInterface(DeviceExtension, &zpoddInfo->D3ColdInterface); 203 204 if (!NT_SUCCESS(status)) 205 { 206 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 207 "DeviceInitializeZPODD: Query D3Cold support interface failed.\n" 208 )); 209 210 goto Cleanup; 211 } 212 213 // 214 // If the platform supports Zero Power ODD, the following conditions must be met: 215 // 216 // 1. The deepest wakeable D-state for the device is D3Cold; 217 // 2. The platform supports D3Cold for the device. 218 // 219 220 d3ColdInterface = &zpoddInfo->D3ColdInterface; 221 222 status = d3ColdInterface->GetIdleWakeInfo(d3ColdInterface->Context, 223 PowerSystemWorking, 224 &deepestWakeableDstate); 225 226 if (!NT_SUCCESS(status)) 227 { 228 goto Cleanup; 229 } 230 231 // 232 // DeviceExtension->PowerDescriptor->D3ColdSupported is retrieved from lower layer. 233 // It has more accurate supportive information than just uses d3ColdInterface->GetD3ColdCapability 234 // 235 if ((deepestWakeableDstate != DeviceWakeDepthD3cold) || 236 (DeviceExtension->PowerDescriptor->D3ColdSupported == FALSE)) 237 { 238 status = STATUS_NOT_SUPPORTED; 239 240 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 241 "DeviceInitializeZPODD: ZPODD not enabled due to ACPI support not present.\n" 242 )); 243 244 goto Cleanup; 245 } 246 247 // 248 // The system meets all requirements. Go ahead and enable ZPODD. 249 // 250 251 // 252 // Register with the runtime power framework. 253 // Note that no un-registration is needed during tear-down. 254 // D3Cold will be enabled (success case of following call) or disabled by port driver during processing Enable Idle Power IOCTL. 255 // 256 257 status = DeviceSendEnableIdlePowerIoctl(DeviceExtension, TRUE, TRUE, DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS); 258 259 if (!NT_SUCCESS(status)) 260 { 261 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 262 "DeviceInitializeZPODD: ZPODD not enabled due to runtime power framework.\n" 263 )); 264 265 goto Cleanup; 266 } 267 268 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 269 "DeviceInitializeZPODD: ZPODD is enabled.\n" 270 )); 271 272 DeviceExtension->ZeroPowerODDInfo = zpoddInfo; 273 274 // 275 // If device is not in home position, then we should take an active reference here 276 // to prevent it from being powered off. 277 // 278 279 inHomePosition = DeviceZPODDIsInHomePosition(DeviceExtension); 280 281 if (inHomePosition == FALSE) 282 { 283 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 284 "DeviceInitializeZPODD: not ready to power off, device marked as active\n")); 285 286 DeviceMarkActive(DeviceExtension, TRUE, FALSE); 287 } 288 else 289 { 290 // 291 // cache get configuration response. 292 // failing is not critical, so we don't want to check for status here. 293 // 294 295 if (zpoddInfo->GetConfigurationBuffer == NULL) 296 { 297 tempStatus = DeviceGetConfigurationWithAlloc(DeviceExtension->Device, 298 &zpoddInfo->GetConfigurationBuffer, 299 &zpoddInfo->GetConfigurationBufferSize, 300 FeatureProfileList, 301 SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL); 302 303 UNREFERENCED_PARAMETER(tempStatus); // Avoid PREFAST warning. 304 } 305 } 306 307 Cleanup: 308 309 if (!NT_SUCCESS(status)) 310 { 311 // 312 // We register always even in non-ZPODD case, per request from storport. 313 // 314 315 tempStatus = DeviceSendEnableIdlePowerIoctl(DeviceExtension, FALSE, FALSE, DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS); 316 317 if (NT_SUCCESS(tempStatus)) 318 { 319 // 320 // Mark the device active; this reference will never be released unless the system enters a 321 // low power state. 322 // 323 324 DeviceMarkActive(DeviceExtension, TRUE, FALSE); 325 } 326 327 FREE_POOL(zpoddInfo); 328 } 329 330 // 331 // If Zero Power ODD is not supported, we should not block the device init sequence. 332 // 333 334 return STATUS_SUCCESS; 335 } 336 337 _IRQL_requires_max_(PASSIVE_LEVEL) 338 ULONG 339 DeviceGetZPODDEnabledFromRegistry() 340 /*++ 341 342 Routine Description: 343 344 Get the ZeroPowerODDEnabled value from registry, which dictates if Zero Power ODD 345 should be enabled or not. If the value is not in registry, by default Zero 346 Power ODD is enabled. 347 348 Arguments: 349 350 None 351 352 Return Value: 353 354 ULONG 355 356 --*/ 357 { 358 NTSTATUS status = STATUS_SUCCESS; 359 WDFKEY registryKey = NULL; 360 ULONG ZPODDEnabled = 0; 361 362 DECLARE_CONST_UNICODE_STRING(registryValueName, L"ZeroPowerODDEnabled"); 363 364 PAGED_CODE(); 365 366 // 367 // open the Parameters key under the service key. 368 // 369 370 status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(), 371 KEY_READ, 372 WDF_NO_OBJECT_ATTRIBUTES, 373 ®istryKey); 374 375 if (NT_SUCCESS(status)) 376 { 377 status = WdfRegistryQueryULong(registryKey, 378 ®istryValueName, 379 &ZPODDEnabled); 380 381 WdfRegistryClose(registryKey); 382 } 383 384 if (!NT_SUCCESS(status)) 385 { 386 // 387 // By default, Zero Power ODD is enabled 388 // 389 390 ZPODDEnabled = 1; 391 } 392 393 return ZPODDEnabled; 394 } 395 396 _IRQL_requires_max_(PASSIVE_LEVEL) 397 NTSTATUS 398 DeviceQueryD3ColdInterface( 399 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 400 _Out_ PD3COLD_SUPPORT_INTERFACE D3ColdInterface 401 ) 402 /*++ 403 404 Routine Description: 405 406 Queries ACPI for the D3Cold support interface. 407 408 Arguments: 409 410 DeviceExtension - the device extension 411 D3ColdInterface - output buffer receiving the interface 412 413 Return Value: 414 415 NTSTATUS 416 417 --*/ 418 { 419 PIRP irp = NULL; 420 KEVENT event; 421 NTSTATUS status = STATUS_SUCCESS; 422 PDEVICE_OBJECT targetDevice = NULL; 423 IO_STATUS_BLOCK ioStatus = {0}; 424 PIO_STACK_LOCATION irpStack = NULL; 425 426 PAGED_CODE(); 427 428 RtlZeroMemory(D3ColdInterface, sizeof(D3COLD_SUPPORT_INTERFACE)); 429 430 // 431 // Query D3COLD support interface synchronously 432 // 433 434 KeInitializeEvent(&event, NotificationEvent, FALSE); 435 436 targetDevice = IoGetAttachedDeviceReference(DeviceExtension->DeviceObject); 437 438 irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, 439 targetDevice, 440 NULL, 441 0, 442 0, 443 &event, 444 &ioStatus); 445 446 if (irp == NULL) 447 { 448 status = STATUS_INSUFFICIENT_RESOURCES; 449 450 goto Cleanup; 451 } 452 453 irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 454 irp->IoStatus.Information = 0; 455 456 irpStack = IoGetNextIrpStackLocation(irp); 457 irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE; 458 irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_D3COLD_SUPPORT_INTERFACE; 459 irpStack->Parameters.QueryInterface.Size = sizeof (D3COLD_SUPPORT_INTERFACE); 460 irpStack->Parameters.QueryInterface.Version = D3COLD_SUPPORT_INTERFACE_VERSION; 461 irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) D3ColdInterface; 462 irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL; 463 464 status = IoCallDriver(targetDevice, irp); 465 466 if (status == STATUS_PENDING) 467 { 468 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 469 470 status = ioStatus.Status; 471 } 472 473 if (!NT_SUCCESS(status)) 474 { 475 goto Cleanup; 476 } 477 478 NT_ASSERT(D3ColdInterface->SetD3ColdSupport != NULL); 479 NT_ASSERT(D3ColdInterface->GetIdleWakeInfo != NULL); 480 NT_ASSERT(D3ColdInterface->GetD3ColdCapability != NULL); 481 482 Cleanup: 483 484 ObDereferenceObject(targetDevice); 485 486 return status; 487 } 488 489 _IRQL_requires_max_(PASSIVE_LEVEL) 490 NTSTATUS 491 DeviceSendEnableIdlePowerIoctl( 492 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 493 _In_ BOOLEAN WakeCapable, 494 _In_ BOOLEAN Enable, 495 _In_ ULONG D3IdleTimeout 496 ) 497 /*++ 498 499 Routine Description: 500 501 Enables idle power support. 502 503 Arguments: 504 505 DeviceExtension - the device extension 506 WakeCapable - whether the device is wake capable 507 Enable - enable / disable idle power management 508 509 Return Value: 510 511 NTSTATUS 512 513 --*/ 514 { 515 NTSTATUS status = STATUS_SUCCESS; 516 STORAGE_IDLE_POWER idlePower = {0}; 517 IO_STATUS_BLOCK ioStatus = {0}; 518 PIRP irp = NULL; 519 KEVENT event; 520 521 PAGED_CODE(); 522 523 idlePower.Version = 1; 524 idlePower.Size = sizeof (STORAGE_IDLE_POWER); 525 idlePower.WakeCapableHint = WakeCapable; 526 idlePower.D3ColdSupported = Enable; 527 idlePower.D3IdleTimeout = D3IdleTimeout; 528 529 KeInitializeEvent(&event, NotificationEvent, FALSE); 530 531 irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_ENABLE_IDLE_POWER, 532 DeviceExtension->LowerPdo, 533 &idlePower, 534 sizeof(STORAGE_IDLE_POWER), 535 NULL, 536 0, 537 FALSE, 538 &event, 539 &ioStatus); 540 541 if (irp == NULL) 542 { 543 status = STATUS_INSUFFICIENT_RESOURCES; 544 } 545 else 546 { 547 // 548 // Send the synchronous request to port driver. 549 // 550 551 status = IoCallDriver(DeviceExtension->LowerPdo, irp); 552 553 if (status == STATUS_PENDING) 554 { 555 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 556 557 status = ioStatus.Status; 558 } 559 } 560 561 TracePrint((TRACE_LEVEL_INFORMATION, 562 TRACE_FLAG_POWER, 563 "DeviceSendEnableIdlePowerIoctl: Port driver returned status (%x) for FDO (%p)\n" 564 "\tD3ColdSupported: %u\n" 565 "\tD3IdleTimeout: %u (ms)", 566 status, 567 DeviceExtension->DeviceObject, 568 Enable, 569 DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS)); 570 571 return status; 572 } 573 574 _IRQL_requires_max_(APC_LEVEL) 575 VOID 576 DeviceReleaseZPODDResources( 577 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension 578 ) 579 /*++ 580 581 Routine Description: 582 583 This routine will cleanup any resources allocated for ZPODD. 584 585 Arguments: 586 587 DeviceExtension - the device context 588 589 Return Value: 590 None. 591 592 --*/ 593 { 594 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; 595 596 PAGED_CODE() 597 598 if (zpoddInfo != NULL) 599 { 600 FREE_POOL(zpoddInfo->GetConfigurationBuffer); 601 FREE_POOL(zpoddInfo); 602 } 603 604 return; 605 } 606 607 NTSTATUS 608 DeviceZPODDGetPowerupReason( 609 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 610 _Out_ PSTORAGE_IDLE_POWERUP_REASON PowerupReason 611 ) 612 /*++ 613 614 Routine Description: 615 616 This routine queries the port driver for what caused the power up. 617 618 Arguments: 619 620 DeviceExtension - device extension. 621 PowerupReason - what caused the power up. 622 623 Return Value: 624 NTSTATUS 625 626 --*/ 627 { 628 NTSTATUS status = STATUS_SUCCESS; 629 PIRP irp = NULL; 630 IO_STATUS_BLOCK ioStatus = {0}; 631 KEVENT event; 632 633 RtlZeroMemory(PowerupReason, sizeof (STORAGE_IDLE_POWERUP_REASON)); 634 635 PowerupReason->Size = sizeof (STORAGE_IDLE_POWERUP_REASON); 636 PowerupReason->Version = STORAGE_IDLE_POWERUP_REASON_VERSION_V1; 637 638 // 639 // Setup a synchronous irp. 640 // 641 642 KeInitializeEvent(&event, NotificationEvent, FALSE); 643 644 irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_IDLE_POWERUP_REASON, 645 DeviceExtension->LowerPdo, 646 PowerupReason, 647 sizeof (STORAGE_IDLE_POWERUP_REASON), 648 PowerupReason, 649 sizeof (STORAGE_IDLE_POWERUP_REASON), 650 FALSE, 651 &event, 652 &ioStatus); 653 654 if (irp == NULL) 655 { 656 status = STATUS_INSUFFICIENT_RESOURCES; 657 } 658 else 659 { 660 // 661 // Send the synchronous request to port driver. 662 // 663 664 status = IoCallDriver(DeviceExtension->LowerPdo, irp); 665 666 if (status == STATUS_PENDING) 667 { 668 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 669 670 status = ioStatus.Status; 671 } 672 } 673 674 return status; 675 } 676 677 _IRQL_requires_max_(PASSIVE_LEVEL) 678 BOOLEAN 679 DeviceZPODDIsInHomePosition( 680 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension 681 ) 682 /*++ 683 684 Routine Description: 685 686 Checks to see if the device is ready to be powered off. 687 Requirements are: 1. tray closed 2. no media present. 688 689 Arguments: 690 691 DeviceExtension - device extension. 692 693 Return Value: 694 BOOLEAN 695 696 --*/ 697 { 698 NTSTATUS status = STATUS_SUCCESS; 699 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; 700 SCSI_REQUEST_BLOCK srb = {0}; 701 PCDB cdb = (PCDB) srb.Cdb; 702 BOOLEAN inHomePosition = FALSE; 703 704 PAGED_CODE(); 705 706 if (zpoddInfo != NULL) 707 { 708 // 709 // Clear sense data. 710 // 711 712 zpoddInfo->SenseKey = 0; 713 zpoddInfo->AdditionalSenseCode = 0; 714 zpoddInfo->AdditionalSenseCodeQualifier = 0; 715 716 // 717 // Send a Test Unit Ready to check media & tray status. 718 // 719 720 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 721 722 srb.CdbLength = 6; 723 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 724 725 srb.TimeOutValue = CDROM_TEST_UNIT_READY_TIMEOUT; 726 727 status = DeviceSendSrbSynchronously(DeviceExtension->Device, 728 &srb, 729 NULL, 730 0, 731 FALSE, 732 NULL); 733 734 #ifdef __REACTOS__ 735 if (!NT_SUCCESS(status)) 736 { 737 return FALSE; 738 } 739 #endif 740 741 // 742 // At this time, sense data, if available, is already copied into zpoddInfo. 743 // 744 // We don't check for status because we expect it to fail in case there is no media in device. 745 // 746 // Should enter Zero Power state if: 747 // 748 // Drawer: 02/3A/01 749 // Slot: 02/3A/xx 750 // 751 752 if (((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && (zpoddInfo->Load == 0) && // Drawer 753 (zpoddInfo->SenseKey == SCSI_SENSE_NOT_READY) && 754 (zpoddInfo->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) && 755 (zpoddInfo->AdditionalSenseCodeQualifier == 0x01)) || 756 ((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_CADDY) && (zpoddInfo->Load == 0) && // Slot 757 (zpoddInfo->SenseKey == SCSI_SENSE_NOT_READY) && 758 (zpoddInfo->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE))) 759 { 760 inHomePosition = TRUE; 761 } 762 } 763 764 return inHomePosition; 765 } 766 767 _IRQL_requires_max_(PASSIVE_LEVEL) 768 VOID 769 DeviceMarkActive( 770 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 771 _In_ BOOLEAN IsActive, 772 _In_ BOOLEAN SetIdleTimeout 773 ) 774 /*++ 775 776 Routine Description: 777 778 This routine will mark the device as active / idle. 779 780 Arguments: 781 782 DeviceExtension - the device context 783 IsActive - if the device should be marked as active 784 785 Return Value: 786 None. 787 788 --*/ 789 { 790 NTSTATUS status = STATUS_SUCCESS; 791 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; 792 793 PAGED_CODE() 794 795 if (DeviceExtension->IsActive != IsActive) 796 { 797 if ((IsActive == FALSE) && (zpoddInfo != NULL)) 798 { 799 // cache get configuration response. 800 // failing is not critical, so we don't want to check for status here. 801 if (zpoddInfo->GetConfigurationBuffer == NULL) 802 { 803 (VOID)DeviceGetConfigurationWithAlloc(DeviceExtension->Device, 804 &zpoddInfo->GetConfigurationBuffer, 805 &zpoddInfo->GetConfigurationBufferSize, 806 FeatureProfileList, 807 SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL); 808 } 809 } 810 811 if (SetIdleTimeout) 812 { 813 status = DeviceSendEnableIdlePowerIoctl(DeviceExtension, 814 FALSE, 815 FALSE, 816 IsActive ? DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS : DELAY_TIME_TO_ENTER_AOAC_IDLE_POWER_IN_MS); 817 } 818 819 if (NT_SUCCESS(status)) 820 { 821 DeviceSendIoctlAsynchronously(DeviceExtension, 822 IsActive ? IOCTL_STORAGE_POWER_ACTIVE : IOCTL_STORAGE_POWER_IDLE, 823 DeviceExtension->LowerPdo); 824 } 825 826 DeviceExtension->IsActive = IsActive; 827 } 828 } 829 830 #pragma warning(pop) // un-sets any local warning changes 831 832 833