Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenautorun.c
Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (C) Microsoft Corporation, 1991 - 1999 00004 00005 Module Name: 00006 00007 autorun.c 00008 00009 Abstract: 00010 00011 Code for support of media change detection in the class driver 00012 00013 Environment: 00014 00015 kernel mode only 00016 00017 Notes: 00018 00019 00020 Revision History: 00021 00022 --*/ 00023 00024 #include "classp.h" 00025 #include "debug.h" 00026 00027 #define GESN_TIMEOUT_VALUE (0x4) 00028 #define GESN_BUFFER_SIZE (0x8) 00029 #define MAXIMUM_IMMEDIATE_MCN_RETRIES (0x20) 00030 #define MCN_REG_SUBKEY_NAME (L"MediaChangeNotification") 00031 #define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME (L"AlwaysDisableMCN") 00032 #define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME (L"AlwaysEnableMCN") 00033 00034 GUID StoragePredictFailureEventGuid = WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID; 00035 00036 // 00037 // Only send polling irp when device is fully powered up and a 00038 // power down irp is not in progress. 00039 // 00040 // NOTE: This helps close a window in time where a polling irp could cause 00041 // a drive to spin up right after it has powered down. The problem is 00042 // that SCSIPORT, ATAPI and SBP2 will be in the process of powering 00043 // down (which may take a few seconds), but won't know that. It would 00044 // then get a polling irp which will be put into its queue since it 00045 // the disk isn't powered down yet. Once the disk is powered down it 00046 // will find the polling irp in the queue and then power up the 00047 // device to do the poll. They do not want to check if the polling 00048 // irp has the SRB_NO_KEEP_AWAKE flag here since it is in a critical 00049 // path and would slow down all I/Os. A better way to fix this 00050 // would be to serialize the polling and power down irps so that 00051 // only one of them is sent to the device at a time. 00052 // 00053 #define ClasspCanSendPollingIrp(fdoExtension) \ 00054 ((fdoExtension->DevicePowerState == PowerDeviceD0) && \ 00055 (! fdoExtension->PowerDownInProgress) ) 00056 00057 BOOLEAN 00058 ClasspIsMediaChangeDisabledDueToHardwareLimitation( 00059 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00060 IN PUNICODE_STRING RegistryPath 00061 ); 00062 00063 NTSTATUS 00064 ClasspMediaChangeDeviceInstanceOverride( 00065 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00066 OUT PBOOLEAN Enabled 00067 ); 00068 00069 BOOLEAN 00070 ClasspIsMediaChangeDisabledForClass( 00071 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00072 IN PUNICODE_STRING RegistryPath 00073 ); 00074 00075 VOID 00076 ClasspSetMediaChangeStateEx( 00077 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00078 IN MEDIA_CHANGE_DETECTION_STATE NewState, 00079 IN BOOLEAN Wait, 00080 IN BOOLEAN KnownStateChange // can ignore oldstate == unknown 00081 ); 00082 00083 NTSTATUS 00084 ClasspMediaChangeRegistryCallBack( 00085 IN PWSTR ValueName, 00086 IN ULONG ValueType, 00087 IN PVOID ValueData, 00088 IN ULONG ValueLength, 00089 IN PVOID Context, 00090 IN PVOID EntryContext 00091 ); 00092 00093 VOID 00094 ClasspSendMediaStateIrp( 00095 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00096 IN PMEDIA_CHANGE_DETECTION_INFO Info, 00097 IN ULONG CountDown 00098 ); 00099 00100 VOID 00101 ClasspFailurePredict( 00102 IN PDEVICE_OBJECT DeviceObject, 00103 IN PFAILURE_PREDICTION_INFO Info 00104 ); 00105 00106 NTSTATUS 00107 ClasspInitializePolling( 00108 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00109 IN BOOLEAN AllowDriveToSleep 00110 ); 00111 00112 00113 #if ALLOC_PRAGMA 00114 00115 #pragma alloc_text(PAGE, ClassInitializeMediaChangeDetection) 00116 #pragma alloc_text(PAGE, ClassEnableMediaChangeDetection) 00117 #pragma alloc_text(PAGE, ClassDisableMediaChangeDetection) 00118 #pragma alloc_text(PAGE, ClassCleanupMediaChangeDetection) 00119 #pragma alloc_text(PAGE, ClasspMediaChangeRegistryCallBack) 00120 #pragma alloc_text(PAGE, ClasspInitializePolling) 00121 00122 #pragma alloc_text(PAGE, ClasspIsMediaChangeDisabledDueToHardwareLimitation) 00123 #pragma alloc_text(PAGE, ClasspMediaChangeDeviceInstanceOverride) 00124 #pragma alloc_text(PAGE, ClasspIsMediaChangeDisabledForClass) 00125 00126 #pragma alloc_text(PAGE, ClassSetFailurePredictionPoll) 00127 #pragma alloc_text(PAGE, ClasspDisableTimer) 00128 #pragma alloc_text(PAGE, ClasspEnableTimer) 00129 00130 #endif 00131 00132 // ISSUE -- make this public? 00133 VOID 00134 ClassSendEjectionNotification( 00135 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 00136 ) 00137 { 00138 // 00139 // For post-NT5.1 work, need to move EjectSynchronizationEvent 00140 // to be a MUTEX so we can attempt to grab it here and benefit 00141 // from deadlock detection. This will allow checking if the media 00142 // has been locked by programs before broadcasting these events. 00143 // (what's the point of broadcasting if the media is not locked?) 00144 // 00145 // This would currently only be a slight optimization. For post-NT5.1, 00146 // it would allow us to send a single PERSISTENT_PREVENT to MMC devices, 00147 // thereby cleaning up a lot of the ejection code. Then, when the 00148 // ejection request occured, we could see if any locks for the media 00149 // existed. if locked, broadcast. if not, we send the eject irp. 00150 // 00151 00152 // 00153 // for now, just always broadcast. make this a public routine, 00154 // so class drivers can add special hacks to broadcast this for their 00155 // non-MMC-compliant devices also from sense codes. 00156 // 00157 00158 DBGTRACE(ClassDebugTrace, ("ClassSendEjectionNotification: media EJECT_REQUEST")); 00159 ClasspSendNotification(FdoExtension, 00160 &GUID_IO_MEDIA_EJECT_REQUEST, 00161 0, 00162 NULL); 00163 return; 00164 } 00165 00166 00167 VOID 00168 ClasspSendNotification( 00169 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00170 IN const GUID * Guid, 00171 IN ULONG ExtraDataSize, 00172 IN PVOID ExtraData 00173 ) 00174 { 00175 PTARGET_DEVICE_CUSTOM_NOTIFICATION notification; 00176 ULONG requiredSize; 00177 00178 requiredSize = 00179 (sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) - sizeof(UCHAR)) + 00180 ExtraDataSize; 00181 00182 if (requiredSize > 0x0000ffff) { 00183 // MAX_USHORT, max total size for these events! 00184 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugWarning, 00185 "Error sending event: size too large! (%x)\n", 00186 requiredSize)); 00187 return; 00188 } 00189 00190 notification = ExAllocatePoolWithTag(NonPagedPool, 00191 requiredSize, 00192 'oNcS'); 00193 00194 // 00195 // if none allocated, exit 00196 // 00197 00198 if (notification == NULL) { 00199 return; 00200 } 00201 00202 // 00203 // Prepare and send the request! 00204 // 00205 00206 RtlZeroMemory(notification, requiredSize); 00207 notification->Version = 1; 00208 notification->Size = (USHORT)(requiredSize); 00209 notification->FileObject = NULL; 00210 notification->NameBufferOffset = -1; 00211 notification->Event = *Guid; 00212 RtlCopyMemory(notification->CustomDataBuffer, ExtraData, ExtraDataSize); 00213 00214 IoReportTargetDeviceChangeAsynchronous(FdoExtension->LowerPdo, 00215 notification, 00216 NULL, NULL); 00217 00218 ExFreePool(notification); 00219 notification = NULL; 00220 return; 00221 } 00222 00223 00224 00225 00226 /*++//////////////////////////////////////////////////////////////////////////// 00227 00228 ClasspInterpretGesnData() 00229 00230 Routine Description: 00231 00232 This routine will interpret the data returned for a GESN command, and 00233 (if appropriate) set the media change event, and broadcast the 00234 appropriate events to user mode for applications who care. 00235 00236 Arguments: 00237 00238 FdoExtension - the device 00239 00240 DataBuffer - the resulting data from a GESN event. 00241 requires at least EIGHT valid bytes (header == 4, data == 4) 00242 00243 ResendImmediately - whether or not to immediately resend the request. 00244 this should be FALSE if there was no event, FALSE if the reported 00245 event was of the DEVICE BUSY class, else true. 00246 00247 Return Value: 00248 00249 None 00250 00251 Notes: 00252 00253 DataBuffer must be at least four bytes of valid data (header == 4 bytes), 00254 and have at least eight bytes of allocated memory (all events == 4 bytes). 00255 00256 The call to StartNextPacket may occur before this routine is completed. 00257 the operational change notifications are informational in nature, and 00258 while useful, are not neccessary to ensure proper operation. For example, 00259 if the device morphs to no longer supporting WRITE commands, all further 00260 write commands will fail. There exists a small timing window wherein 00261 IOCTL_IS_DISK_WRITABLE may be called and get an incorrect response. If 00262 a device supports software write protect, it is expected that the 00263 application can handle such a case. 00264 00265 NOTE: perhaps setting the updaterequired byte to one should be done here. 00266 if so, it relies upon the setting of a 32-byte value to be an atomic 00267 operation. unfortunately, there is no simple way to notify a class driver 00268 which wants to know that the device behavior requires updating. 00269 00270 Not ready events may be sent every second. For example, if we were 00271 to minimize the number of asynchronous notifications, an application may 00272 register just after a large busy time was reported. This would then 00273 prevent the application from knowing the device was busy until some 00274 arbitrarily chosen timeout has occurred. Also, the GESN request would 00275 have to still occur, since it checks for non-busy events (such as user 00276 keybutton presses and media change events) as well. The specification 00277 states that the lower-numered events get reported first, so busy events, 00278 while repeating, will only be reported when all other events have been 00279 cleared from the device. 00280 00281 --*/ 00282 VOID 00283 ClasspInterpretGesnData( 00284 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00285 IN PNOTIFICATION_EVENT_STATUS_HEADER Header, 00286 IN PBOOLEAN ResendImmediately 00287 ) 00288 { 00289 PMEDIA_CHANGE_DETECTION_INFO info; 00290 LONG dataLength; 00291 LONG requiredLength; 00292 00293 info = FdoExtension->MediaChangeDetectionInfo; 00294 00295 // 00296 // note: don't allocate anything in this routine so that we can 00297 // always just 'return'. 00298 // 00299 00300 *ResendImmediately = FALSE; 00301 00302 if (Header->NEA) { 00303 return; 00304 } 00305 if (Header->NotificationClass == NOTIFICATION_NO_CLASS_EVENTS) { 00306 return; 00307 } 00308 00309 // 00310 // HACKHACK - REF #0001 00311 // This loop is only taken initially, due to the inability to reliably 00312 // auto-detect drives that report events correctly at boot. When we 00313 // detect this behavior during the normal course of running, we will 00314 // disable the hack, allowing more efficient use of the system. This 00315 // should occur "nearly" instantly, as the drive should have multiple 00316 // events queue'd (ie. power, morphing, media). 00317 // 00318 00319 if (info->Gesn.HackEventMask) { 00320 00321 // 00322 // all events use the low four bytes of zero to indicate 00323 // that there was no change in status. 00324 // 00325 00326 UCHAR thisEvent = Header->ClassEventData[0] & 0xf; 00327 UCHAR lowestSetBit; 00328 UCHAR thisEventBit = (1 << Header->NotificationClass); 00329 00330 ASSERT(TEST_FLAG(info->Gesn.EventMask, thisEventBit)); 00331 00332 00333 // 00334 // some bit magic here... this results in the lowest set bit only 00335 // 00336 00337 lowestSetBit = info->Gesn.EventMask; 00338 lowestSetBit &= (info->Gesn.EventMask - 1); 00339 lowestSetBit ^= (info->Gesn.EventMask); 00340 00341 if (thisEventBit != lowestSetBit) { 00342 00343 // 00344 // HACKHACK - REF #0001 00345 // the first time we ever see an event set that is not the lowest 00346 // set bit in the request (iow, highest priority), we know that the 00347 // hack is no longer required, as the device is ignoring "no change" 00348 // events when a real event is waiting in the other requested queues. 00349 // 00350 00351 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 00352 "Classpnp => GESN::NONE: Compliant drive found, " 00353 "removing GESN hack (%x, %x)\n", 00354 thisEventBit, info->Gesn.EventMask)); 00355 00356 info->Gesn.HackEventMask = FALSE; 00357 00358 } else if (thisEvent == 0) { 00359 00360 // 00361 // HACKHACK - REF #0001 00362 // note: this hack prevents poorly implemented firmware from constantly 00363 // returning "No Event". we do this by cycling through the 00364 // supported list of events here. 00365 // 00366 00367 SET_FLAG(info->Gesn.NoChangeEventMask, thisEventBit); 00368 CLEAR_FLAG(info->Gesn.EventMask, thisEventBit); 00369 00370 // 00371 // if we have cycled through all supported event types, then 00372 // we need to reset the events we are asking about. else we 00373 // want to resend this request immediately in case there was 00374 // another event pending. 00375 // 00376 00377 if (info->Gesn.EventMask == 0) { 00378 info->Gesn.EventMask = info->Gesn.NoChangeEventMask; 00379 info->Gesn.NoChangeEventMask = 0; 00380 } else { 00381 *ResendImmediately = TRUE; 00382 } 00383 return; 00384 } 00385 00386 } // end if (info->Gesn.HackEventMask) 00387 00388 dataLength = 00389 (Header->EventDataLength[0] << 8) | 00390 (Header->EventDataLength[1] & 0xff); 00391 dataLength -= 2; 00392 requiredLength = 4; // all events are four bytes 00393 00394 if (dataLength < requiredLength) { 00395 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugWarning, 00396 "Classpnp => GESN returned only %x bytes data for fdo %p\n", 00397 dataLength, FdoExtension->DeviceObject)); 00398 return; 00399 } 00400 if (dataLength != requiredLength) { 00401 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugWarning, 00402 "Classpnp => GESN returned too many (%x) bytes data for fdo %p\n", 00403 dataLength, FdoExtension->DeviceObject)); 00404 dataLength = 4; 00405 } 00406 00407 /* 00408 ClasspSendNotification(FdoExtension, 00409 &GUID_IO_GENERIC_GESN_EVENT, 00410 sizeof(NOTIFICATION_EVENT_STATUS_HEADER) + dataLength, 00411 Header) 00412 */ 00413 00414 switch (Header->NotificationClass) { 00415 00416 case NOTIFICATION_EXTERNAL_REQUEST_CLASS_EVENTS: { // 0x3 00417 00418 PNOTIFICATION_EXTERNAL_STATUS externalInfo = 00419 (PNOTIFICATION_EXTERNAL_STATUS)(Header->ClassEventData); 00420 DEVICE_EVENT_EXTERNAL_REQUEST externalData; 00421 00422 // 00423 // unfortunately, due to time constraints, we will only notify 00424 // about keys being pressed, and not released. this makes keys 00425 // single-function, but simplifies the code significantly. 00426 // 00427 00428 if (externalInfo->ExternalEvent != 00429 NOTIFICATION_EXTERNAL_EVENT_BUTTON_DOWN) { 00430 break; 00431 } 00432 00433 *ResendImmediately = TRUE; 00434 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 00435 "Classpnp => GESN::EXTERNAL: Event: %x Status %x Req %x\n", 00436 externalInfo->ExternalEvent, externalInfo->ExternalStatus, 00437 (externalInfo->Request[0] >> 8) | externalInfo->Request[1] 00438 )); 00439 00440 RtlZeroMemory(&externalData, sizeof(DEVICE_EVENT_EXTERNAL_REQUEST)); 00441 externalData.Version = 1; 00442 externalData.DeviceClass = 0; 00443 externalData.ButtonStatus = externalInfo->ExternalEvent; 00444 externalData.Request = 00445 (externalInfo->Request[0] << 8) | 00446 (externalInfo->Request[1] & 0xff); 00447 KeQuerySystemTime(&(externalData.SystemTime)); 00448 externalData.SystemTime.QuadPart *= (LONGLONG)KeQueryTimeIncrement(); 00449 00450 DBGTRACE(ClassDebugTrace, ("ClasspInterpretGesnData: media DEVICE_EXTERNAL_REQUEST")); 00451 ClasspSendNotification(FdoExtension, 00452 &GUID_IO_DEVICE_EXTERNAL_REQUEST, 00453 sizeof(DEVICE_EVENT_EXTERNAL_REQUEST), 00454 &externalData); 00455 return; 00456 } 00457 00458 case NOTIFICATION_MEDIA_STATUS_CLASS_EVENTS: { // 0x4 00459 00460 PNOTIFICATION_MEDIA_STATUS mediaInfo = 00461 (PNOTIFICATION_MEDIA_STATUS)(Header->ClassEventData); 00462 00463 if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_NO_CHANGE) { 00464 break; 00465 } 00466 00467 *ResendImmediately = TRUE; 00468 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 00469 "Classpnp => GESN::MEDIA: Event: %x Status %x\n", 00470 mediaInfo->MediaEvent, mediaInfo->MediaStatus)); 00471 00472 if ((mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_NEW_MEDIA) || 00473 (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_MEDIA_CHANGE)) { 00474 00475 00476 if (TEST_FLAG(FdoExtension->DeviceObject->Characteristics, 00477 FILE_REMOVABLE_MEDIA) && 00478 (ClassGetVpb(FdoExtension->DeviceObject) != NULL) && 00479 (ClassGetVpb(FdoExtension->DeviceObject)->Flags & VPB_MOUNTED) 00480 ) { 00481 00482 SET_FLAG(FdoExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); 00483 00484 } 00485 InterlockedIncrement(&FdoExtension->MediaChangeCount); 00486 ClasspSetMediaChangeStateEx(FdoExtension, 00487 MediaPresent, 00488 FALSE, 00489 TRUE); 00490 00491 } else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_MEDIA_REMOVAL) { 00492 00493 ClasspSetMediaChangeStateEx(FdoExtension, 00494 MediaNotPresent, 00495 FALSE, 00496 TRUE); 00497 00498 } else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_EJECT_REQUEST) { 00499 00500 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugError, 00501 "Classpnp => GESN Ejection request received!\n")); 00502 ClassSendEjectionNotification(FdoExtension); 00503 00504 } 00505 break; 00506 00507 } 00508 00509 case NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS: { // lowest priority events... 00510 00511 PNOTIFICATION_BUSY_STATUS busyInfo = 00512 (PNOTIFICATION_BUSY_STATUS)(Header->ClassEventData); 00513 DEVICE_EVENT_BECOMING_READY busyData; 00514 00515 // 00516 // NOTE: we never actually need to immediately retry for these 00517 // events: if one exists, the device is busy, and if not, 00518 // we still don't want to retry. 00519 // 00520 00521 if (busyInfo->DeviceBusyStatus == NOTIFICATION_BUSY_STATUS_NO_EVENT) { 00522 break; 00523 } 00524 00525 // 00526 // else we want to report the approximated time till it's ready. 00527 // 00528 00529 RtlZeroMemory(&busyData, sizeof(DEVICE_EVENT_BECOMING_READY)); 00530 busyData.Version = 1; 00531 busyData.Reason = busyInfo->DeviceBusyStatus; 00532 busyData.Estimated100msToReady = (busyInfo->Time[0] << 8) | 00533 (busyInfo->Time[1] & 0xff); 00534 00535 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 00536 "Classpnp => GESN::BUSY: Event: %x Status %x Time %x\n", 00537 busyInfo->DeviceBusyEvent, busyInfo->DeviceBusyStatus, 00538 busyData.Estimated100msToReady 00539 )); 00540 00541 DBGTRACE(ClassDebugTrace, ("ClasspInterpretGesnData: media BECOMING_READY")); 00542 ClasspSendNotification(FdoExtension, 00543 &GUID_IO_DEVICE_BECOMING_READY, 00544 sizeof(DEVICE_EVENT_BECOMING_READY), 00545 &busyData); 00546 break; 00547 } 00548 00549 default: { 00550 00551 break; 00552 00553 } 00554 00555 } // end switch on notification class 00556 return; 00557 } 00558 00559 /*++//////////////////////////////////////////////////////////////////////////// 00560 00561 ClasspInternalSetMediaChangeState() 00562 00563 Routine Description: 00564 00565 This routine will (if appropriate) set the media change event for the 00566 device. The event will be set if the media state is changed and 00567 media change events are enabled. Otherwise the media state will be 00568 tracked but the event will not be set. 00569 00570 This routine will lock out the other media change routines if possible 00571 but if not a media change notification may be lost after the enable has 00572 been completed. 00573 00574 Arguments: 00575 00576 FdoExtension - the device 00577 00578 MediaPresent - indicates whether the device has media inserted into it 00579 (TRUE) or not (FALSE). 00580 00581 Return Value: 00582 00583 none 00584 00585 --*/ 00586 VOID 00587 ClasspInternalSetMediaChangeState( 00588 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00589 IN MEDIA_CHANGE_DETECTION_STATE NewState, 00590 IN BOOLEAN KnownStateChange // can ignore oldstate == unknown 00591 ) 00592 { 00593 #if DBG 00594 PUCHAR states[] = {"Unknown", "Present", "Not Present"}; 00595 #endif 00596 MEDIA_CHANGE_DETECTION_STATE oldMediaState; 00597 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo; 00598 ULONG data; 00599 NTSTATUS status; 00600 00601 ASSERT((NewState >= MediaUnknown) && (NewState <= MediaNotPresent)); 00602 00603 if(info == NULL) { 00604 return; 00605 } 00606 00607 oldMediaState = InterlockedExchange( 00608 (PLONG)(&info->MediaChangeDetectionState), 00609 (LONG)NewState); 00610 00611 if((oldMediaState == MediaUnknown) && (!KnownStateChange)) { 00612 00613 // 00614 // The media was in an indeterminate state before - don't notify for 00615 // this change. 00616 // 00617 00618 DebugPrint((ClassDebugMCN, 00619 "ClassSetMediaChangeState: State was unknown - this may " 00620 "not be a change\n")); 00621 return; 00622 00623 } else if(oldMediaState == NewState) { 00624 00625 // 00626 // Media is in the same state it was before. 00627 // 00628 00629 return; 00630 } 00631 00632 if(info->MediaChangeDetectionDisableCount != 0) { 00633 00634 DBGTRACE(ClassDebugMCN, 00635 ("ClassSetMediaChangeState: MCN not enabled, state " 00636 "changed from %s to %s\n", 00637 states[oldMediaState], states[NewState])); 00638 return; 00639 00640 } 00641 00642 DBGTRACE(ClassDebugMCN, 00643 ("ClassSetMediaChangeState: State change from %s to %s\n", 00644 states[oldMediaState], states[NewState])); 00645 00646 // 00647 // make the data useful -- it used to always be zero. 00648 // 00649 data = FdoExtension->MediaChangeCount; 00650 00651 if (NewState == MediaPresent) { 00652 00653 DBGTRACE(ClassDebugTrace, ("ClasspInternalSetMediaChangeState: media ARRIVAL")); 00654 ClasspSendNotification(FdoExtension, 00655 &GUID_IO_MEDIA_ARRIVAL, 00656 sizeof(ULONG), 00657 &data); 00658 00659 } 00660 else if (NewState == MediaNotPresent) { 00661 00662 DBGTRACE(ClassDebugTrace, ("ClasspInternalSetMediaChangeState: media REMOVAL")); 00663 ClasspSendNotification(FdoExtension, 00664 &GUID_IO_MEDIA_REMOVAL, 00665 sizeof(ULONG), 00666 &data); 00667 00668 } else { 00669 00670 // 00671 // Don't notify of changed going to unknown. 00672 // 00673 00674 return; 00675 } 00676 00677 return; 00678 } // end ClasspInternalSetMediaChangeState() 00679 00680 /*++//////////////////////////////////////////////////////////////////////////// 00681 00682 ClassSetMediaChangeState() 00683 00684 Routine Description: 00685 00686 This routine will (if appropriate) set the media change event for the 00687 device. The event will be set if the media state is changed and 00688 media change events are enabled. Otherwise the media state will be 00689 tracked but the event will not be set. 00690 00691 This routine will lock out the other media change routines if possible 00692 but if not a media change notification may be lost after the enable has 00693 been completed. 00694 00695 Arguments: 00696 00697 FdoExtension - the device 00698 00699 MediaPresent - indicates whether the device has media inserted into it 00700 (TRUE) or not (FALSE). 00701 00702 Wait - indicates whether the function should wait until it can acquire 00703 the synchronization lock or not. 00704 00705 Return Value: 00706 00707 none 00708 00709 --*/ 00710 VOID 00711 ClasspSetMediaChangeStateEx( 00712 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00713 IN MEDIA_CHANGE_DETECTION_STATE NewState, 00714 IN BOOLEAN Wait, 00715 IN BOOLEAN KnownStateChange // can ignore oldstate == unknown 00716 ) 00717 { 00718 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo; 00719 LARGE_INTEGER zero; 00720 NTSTATUS status; 00721 00722 DBGTRACE(ClassDebugMCN, ("> ClasspSetMediaChangeStateEx")); 00723 00724 // 00725 // Reset SMART status on media removal as the old status may not be 00726 // valid when there is no media in the device or when new media is 00727 // inserted. 00728 // 00729 00730 if (NewState == MediaNotPresent) { 00731 00732 FdoExtension->FailurePredicted = FALSE; 00733 FdoExtension->FailureReason = 0; 00734 00735 } 00736 00737 00738 zero.QuadPart = 0; 00739 00740 if(info == NULL) { 00741 return; 00742 } 00743 00744 status = KeWaitForMutexObject(&info->MediaChangeMutex, 00745 Executive, 00746 KernelMode, 00747 FALSE, 00748 ((Wait == TRUE) ? NULL : &zero)); 00749 00750 if(status == STATUS_TIMEOUT) { 00751 00752 // 00753 // Someone else is in the process of setting the media state 00754 // 00755 00756 DBGWARN(("ClasspSetMediaChangeStateEx - timed out waiting for mutex")); 00757 return; 00758 } 00759 00760 // 00761 // Change the media present state and signal an event, if applicable 00762 // 00763 00764 ClasspInternalSetMediaChangeState(FdoExtension, NewState, KnownStateChange); 00765 00766 KeReleaseMutex(&info->MediaChangeMutex, FALSE); 00767 00768 DBGTRACE(ClassDebugMCN, ("< ClasspSetMediaChangeStateEx")); 00769 00770 return; 00771 } // end ClassSetMediaChangeStateEx() 00772 VOID 00773 ClassSetMediaChangeState( 00774 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00775 IN MEDIA_CHANGE_DETECTION_STATE NewState, 00776 IN BOOLEAN Wait 00777 ) 00778 { 00779 ClasspSetMediaChangeStateEx(FdoExtension, NewState, Wait, FALSE); 00780 return; 00781 } 00782 00783 /*++//////////////////////////////////////////////////////////////////////////// 00784 00785 ClasspMediaChangeDetectionCompletion() 00786 00787 Routine Description: 00788 00789 This routine handles the completion of the test unit ready irps used to 00790 determine if the media has changed. If the media has changed, this code 00791 signals the named event to wake up other system services that react to 00792 media change (aka AutoPlay). 00793 00794 Arguments: 00795 00796 DeviceObject - the object for the completion 00797 Irp - the IRP being completed 00798 Context - the SRB from the IRP 00799 00800 Return Value: 00801 00802 NTSTATUS 00803 00804 --*/ 00805 NTSTATUS 00806 ClasspMediaChangeDetectionCompletion( 00807 PDEVICE_OBJECT DeviceObject, 00808 PIRP Irp, 00809 PSCSI_REQUEST_BLOCK Srb 00810 ) 00811 { 00812 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 00813 PCLASS_PRIVATE_FDO_DATA fdoData; 00814 PMEDIA_CHANGE_DETECTION_INFO info; 00815 PIO_STACK_LOCATION nextIrpStack; 00816 NTSTATUS status; 00817 BOOLEAN retryImmediately = FALSE; 00818 00819 // 00820 // Since the class driver created this request, it's completion routine 00821 // will not get a valid device object handed in. Use the one in the 00822 // irp stack instead 00823 // 00824 00825 DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject; 00826 fdoExtension = DeviceObject->DeviceExtension; 00827 fdoData = fdoExtension->PrivateFdoData; 00828 info = fdoExtension->MediaChangeDetectionInfo; 00829 00830 ASSERT(info->MediaChangeIrp != NULL); 00831 ASSERT(!TEST_FLAG(Srb->SrbStatus, SRB_STATUS_QUEUE_FROZEN)); 00832 DBGTRACE(ClassDebugMCN, ("> ClasspMediaChangeDetectionCompletion: Device %p completed MCN irp %p.", DeviceObject, Irp)); 00833 00834 /* 00835 * HACK for IoMega 2GB Jaz drive: 00836 * This drive spins down on its own to preserve the media. 00837 * When spun down, TUR fails with 2/4/0 (SCSI_SENSE_NOT_READY/SCSI_ADSENSE_LUN_NOT_READY/?). 00838 * ClassInterpretSenseInfo would then call ClassSendStartUnit to spin the media up, which defeats the 00839 * purpose of the spindown. 00840 * So in this case, make this into a successful TUR. 00841 * This allows the drive to stay spun down until it is actually accessed again. 00842 * (If the media were actually removed, TUR would fail with 2/3a/0 ). 00843 * This hack only applies to drives with the CAUSE_NOT_REPORTABLE_HACK bit set; this 00844 * is set by disk.sys when HackCauseNotReportableHack is set for the drive in its BadControllers list. 00845 */ 00846 if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) && 00847 TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK) && 00848 (Srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode))){ 00849 00850 PSENSE_DATA senseData = Srb->SenseInfoBuffer; 00851 00852 if ((senseData->SenseKey == SCSI_SENSE_NOT_READY) && 00853 (senseData->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)){ 00854 Srb->SrbStatus = SRB_STATUS_SUCCESS; 00855 } 00856 } 00857 00858 00859 // 00860 // use ClassInterpretSenseInfo() to check for media state, and also 00861 // to call ClassError() with correct parameters. 00862 // 00863 status = STATUS_SUCCESS; 00864 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) { 00865 00866 DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - failed - srb status=%s, sense=%s/%s/%s.", DBGGETSRBSTATUSSTR(Srb), DBGGETSENSECODESTR(Srb), DBGGETADSENSECODESTR(Srb), DBGGETADSENSEQUALIFIERSTR(Srb))); 00867 00868 ClassInterpretSenseInfo(DeviceObject, 00869 Srb, 00870 IRP_MJ_SCSI, 00871 0, 00872 0, 00873 &status, 00874 NULL); 00875 00876 } 00877 else { 00878 00879 fdoData->LoggedTURFailureSinceLastIO = FALSE; 00880 00881 if (!info->Gesn.Supported) { 00882 00883 DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - succeeded and GESN NOT supported, setting MediaPresent.")); 00884 00885 // 00886 // success != media for GESN case 00887 // 00888 00889 ClassSetMediaChangeState(fdoExtension, MediaPresent, FALSE); 00890 00891 } 00892 else { 00893 DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - succeeded (GESN supported).")); 00894 } 00895 } 00896 00897 if (info->Gesn.Supported) { 00898 00899 if (status == STATUS_DATA_OVERRUN) { 00900 DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - Overrun")); 00901 status = STATUS_SUCCESS; 00902 } 00903 00904 if (!NT_SUCCESS(status)) { 00905 DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion: GESN failed with status %x", status)); 00906 } else { 00907 00908 // 00909 // for GESN, need to interpret the results of the data. 00910 // this may also require an immediate retry 00911 // 00912 00913 if (Irp->IoStatus.Information == 8 ) { 00914 ClasspInterpretGesnData(fdoExtension, 00915 (PVOID)info->Gesn.Buffer, 00916 &retryImmediately); 00917 } 00918 00919 } // end of NT_SUCCESS(status) 00920 00921 } // end of Info->Gesn.Supported 00922 00923 // 00924 // free port-allocated sense buffer, if any. 00925 // 00926 00927 if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) { 00928 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb); 00929 } 00930 00931 // 00932 // Remember the IRP and SRB for use the next time. 00933 // 00934 00935 ASSERT(IoGetNextIrpStackLocation(Irp)); 00936 IoGetNextIrpStackLocation(Irp)->Parameters.Scsi.Srb = Srb; 00937 00938 // 00939 // Reset the MCN timer. 00940 // 00941 00942 ClassResetMediaChangeTimer(fdoExtension); 00943 00944 // 00945 // run a sanity check to make sure we're not recursing continuously 00946 // 00947 00948 if (retryImmediately) { 00949 00950 info->MediaChangeRetryCount++; 00951 if (info->MediaChangeRetryCount > MAXIMUM_IMMEDIATE_MCN_RETRIES) { 00952 ASSERT(!"Recursing too often in MCN?"); 00953 info->MediaChangeRetryCount = 0; 00954 retryImmediately = FALSE; 00955 } 00956 00957 } else { 00958 00959 info->MediaChangeRetryCount = 0; 00960 00961 } 00962 00963 00964 // 00965 // release the remove lock.... 00966 // 00967 00968 { 00969 UCHAR uniqueValue; 00970 ClassAcquireRemoveLock(DeviceObject, (PIRP)(&uniqueValue)); 00971 ClassReleaseRemoveLock(DeviceObject, Irp); 00972 00973 00974 // 00975 // set the irp as not in use 00976 // 00977 { 00978 volatile LONG irpWasInUse; 00979 irpWasInUse = InterlockedCompareExchange(&info->MediaChangeIrpInUse, 0, 1); 00980 #if _MSC_FULL_VER != 13009111 // This compiler always takes the wrong path here. 00981 ASSERT(irpWasInUse); 00982 #endif 00983 } 00984 00985 // 00986 // now send it again before we release our last remove lock 00987 // 00988 00989 if (retryImmediately) { 00990 ClasspSendMediaStateIrp(fdoExtension, info, 0); 00991 } 00992 else { 00993 DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - not retrying immediately")); 00994 } 00995 00996 // 00997 // release the temporary remove lock 00998 // 00999 01000 ClassReleaseRemoveLock(DeviceObject, (PIRP)(&uniqueValue)); 01001 } 01002 01003 DBGTRACE(ClassDebugMCN, ("< ClasspMediaChangeDetectionCompletion")); 01004 01005 return STATUS_MORE_PROCESSING_REQUIRED; 01006 } 01007 01008 /*++//////////////////////////////////////////////////////////////////////////// 01009 01010 ClasspSendTestUnitIrp() - ISSUE-2000/02/20-henrygab - not documented 01011 01012 Routine Description: 01013 01014 This routine 01015 01016 Arguments: 01017 01018 DeviceObject - 01019 Irp - 01020 01021 Return Value: 01022 01023 01024 --*/ 01025 PIRP 01026 ClasspPrepareMcnIrp( 01027 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 01028 IN PMEDIA_CHANGE_DETECTION_INFO Info, 01029 IN BOOLEAN UseGesn 01030 ) 01031 { 01032 PSCSI_REQUEST_BLOCK srb; 01033 PIO_STACK_LOCATION irpStack; 01034 PIO_STACK_LOCATION nextIrpStack; 01035 NTSTATUS status; 01036 PCDB cdb; 01037 PIRP irp; 01038 PVOID buffer; 01039 01040 // 01041 // Setup the IRP to perform a test unit ready. 01042 // 01043 01044 irp = Info->MediaChangeIrp; 01045 01046 ASSERT(irp); 01047 01048 if (irp == NULL) { 01049 return NULL; 01050 } 01051 01052 // 01053 // don't keep sending this if the device is being removed. 01054 // 01055 01056 status = ClassAcquireRemoveLock(FdoExtension->DeviceObject, irp); 01057 if (status == REMOVE_COMPLETE) { 01058 ASSERT(status != REMOVE_COMPLETE); 01059 return NULL; 01060 } 01061 else if (status == REMOVE_PENDING) { 01062 ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp); 01063 return NULL; 01064 } 01065 else { 01066 ASSERT(status == NO_REMOVE); 01067 } 01068 01069 irp->IoStatus.Status = STATUS_SUCCESS; 01070 irp->IoStatus.Information = 0; 01071 irp->Flags = 0; 01072 irp->UserBuffer = NULL; 01073 01074 // 01075 // If the irp is sent down when the volume needs to be 01076 // verified, CdRomUpdateGeometryCompletion won't complete 01077 // it since it's not associated with a thread. Marking 01078 // it to override the verify causes it always be sent 01079 // to the port driver 01080 // 01081 01082 irpStack = IoGetCurrentIrpStackLocation(irp); 01083 irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 01084 01085 nextIrpStack = IoGetNextIrpStackLocation(irp); 01086 nextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 01087 nextIrpStack->Parameters.Scsi.Srb = &(Info->MediaChangeSrb); 01088 01089 // 01090 // Prepare the SRB for execution. 01091 // 01092 01093 srb = nextIrpStack->Parameters.Scsi.Srb; 01094 buffer = srb->SenseInfoBuffer; 01095 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 01096 RtlZeroMemory(buffer, SENSE_BUFFER_SIZE); 01097 01098 01099 srb->QueueTag = SP_UNTAGGED; 01100 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 01101 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 01102 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 01103 srb->SenseInfoBuffer = buffer; 01104 srb->SrbStatus = 0; 01105 srb->ScsiStatus = 0; 01106 srb->OriginalRequest = irp; 01107 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 01108 01109 srb->SrbFlags = FdoExtension->SrbFlags; 01110 SET_FLAG(srb->SrbFlags, Info->SrbFlags); 01111 01112 srb->TimeOutValue = FdoExtension->TimeOutValue * 2; 01113 01114 if (srb->TimeOutValue == 0) { 01115 01116 if (FdoExtension->TimeOutValue == 0) { 01117 01118 KdPrintEx((DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL, 01119 "ClassSendTestUnitIrp: FdoExtension->TimeOutValue " 01120 "is set to zero?! -- resetting to 10\n")); 01121 srb->TimeOutValue = 10 * 2; // reasonable default 01122 01123 } else { 01124 01125 KdPrintEx((DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL, 01126 "ClassSendTestUnitIrp: Someone set " 01127 "srb->TimeOutValue to zero?! -- resetting to %x\n", 01128 FdoExtension->TimeOutValue * 2)); 01129 srb->TimeOutValue = FdoExtension->TimeOutValue * 2; 01130 01131 } 01132 01133 } 01134 01135 if (!UseGesn) { 01136 01137 srb->CdbLength = 6; 01138 srb->DataTransferLength = 0; 01139 SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER); 01140 nextIrpStack->Parameters.DeviceIoControl.IoControlCode = 01141 IOCTL_SCSI_EXECUTE_NONE; 01142 srb->DataBuffer = NULL; 01143 srb->DataTransferLength = 0; 01144 irp->MdlAddress = NULL; 01145 01146 cdb = (PCDB) &srb->Cdb[0]; 01147 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 01148 01149 } else { 01150 01151 ASSERT(Info->Gesn.Buffer); 01152 01153 srb->TimeOutValue = GESN_TIMEOUT_VALUE; // much shorter timeout for GESN 01154 01155 srb->CdbLength = 10; 01156 SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN); 01157 nextIrpStack->Parameters.DeviceIoControl.IoControlCode = 01158 IOCTL_SCSI_EXECUTE_IN; 01159 srb->DataBuffer = Info->Gesn.Buffer; 01160 srb->DataTransferLength = Info->Gesn.BufferSize; 01161 irp->MdlAddress = Info->Gesn.Mdl; 01162 01163 cdb = (PCDB) &srb->Cdb[0]; 01164 cdb->GET_EVENT_STATUS_NOTIFICATION.OperationCode = 01165 SCSIOP_GET_EVENT_STATUS; 01166 cdb->GET_EVENT_STATUS_NOTIFICATION.Immediate = 1; 01167 cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[0] = 01168 (UCHAR)((Info->Gesn.BufferSize) >> 8); 01169 cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[1] = 01170 (UCHAR)((Info->Gesn.BufferSize) & 0xff); 01171 cdb->GET_EVENT_STATUS_NOTIFICATION.NotificationClassRequest = 01172 Info->Gesn.EventMask; 01173 01174 } 01175 01176 IoSetCompletionRoutine(irp, 01177 ClasspMediaChangeDetectionCompletion, 01178 srb, 01179 TRUE, 01180 TRUE, 01181 TRUE); 01182 01183 return irp; 01184 01185 } 01186 01187 /*++//////////////////////////////////////////////////////////////////////////// 01188 01189 ClasspSendMediaStateIrp() - ISSUE-2000/02/20-henrygab - not documented 01190 01191 Routine Description: 01192 01193 This routine 01194 01195 Arguments: 01196 01197 DeviceObject - 01198 Irp - 01199 01200 Return Value: 01201 01202 --*/ 01203 VOID 01204 ClasspSendMediaStateIrp( 01205 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 01206 IN PMEDIA_CHANGE_DETECTION_INFO Info, 01207 IN ULONG CountDown 01208 ) 01209 { 01210 BOOLEAN requestPending = FALSE; 01211 LONG irpInUse; 01212 LARGE_INTEGER zero; 01213 NTSTATUS status; 01214 01215 DBGTRACE(ClassDebugMCN, ("> ClasspSendMediaStateIrp")); 01216 01217 if (((FdoExtension->CommonExtension.CurrentState != IRP_MN_START_DEVICE) || 01218 (FdoExtension->DevicePowerState != PowerDeviceD0) 01219 ) && 01220 (!Info->MediaChangeIrpLost)) { 01221 01222 // 01223 // the device may be stopped, powered down, or otherwise queueing io, 01224 // so should not timeout the autorun irp (yet) -- set to zero ticks. 01225 // scattered code relies upon this to not prematurely "lose" an 01226 // autoplay irp that was queued. 01227 // 01228 01229 Info->MediaChangeIrpTimeInUse = 0; 01230 } 01231 01232 // 01233 // if the irp is not in use, mark it as such. 01234 // 01235 01236 irpInUse = InterlockedCompareExchange(&Info->MediaChangeIrpInUse, 1, 0); 01237 01238 if (irpInUse) { 01239 01240 LONG timeInUse; 01241 01242 timeInUse = InterlockedIncrement(&Info->MediaChangeIrpTimeInUse); 01243 01244 DebugPrint((ClassDebugMCN, "ClasspSendMediaStateIrp: irp in use for " 01245 "%x seconds when synchronizing for MCD\n", timeInUse)); 01246 01247 if (Info->MediaChangeIrpLost == FALSE) { 01248 01249 if (timeInUse > MEDIA_CHANGE_TIMEOUT_TIME) { 01250 01251 // 01252 // currently set to five minutes. hard to imagine a drive 01253 // taking that long to spin up. 01254 // 01255 01256 DebugPrint((ClassDebugError, 01257 "CdRom%d: Media Change Notification has lost " 01258 "it's irp and doesn't know where to find it. " 01259 "Leave it alone and it'll come home dragging " 01260 "it's stack behind it.\n", 01261 FdoExtension->DeviceNumber)); 01262 Info->MediaChangeIrpLost = TRUE; 01263 } 01264 } 01265 01266 DBGTRACE(ClassDebugMCN, ("< ClasspSendMediaStateIrp - irpInUse")); 01267 return; 01268 01269 } 01270 01271 TRY { 01272 01273 if (Info->MediaChangeDetectionDisableCount != 0) { 01274 DebugPrint((ClassDebugTrace, "ClassCheckMediaState: device %p has " 01275 " detection disabled \n", FdoExtension->DeviceObject)); 01276 LEAVE; 01277 } 01278 01279 if (FdoExtension->DevicePowerState != PowerDeviceD0) { 01280 01281 if (TEST_FLAG(Info->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE)) { 01282 DebugPrint((ClassDebugMCN, 01283 "ClassCheckMediaState: device %p is powered " 01284 "down and flags are set to let it sleep\n", 01285 FdoExtension->DeviceObject)); 01286 ClassResetMediaChangeTimer(FdoExtension); 01287 LEAVE; 01288 } 01289 01290 // 01291 // NOTE: we don't increment the time in use until our power state 01292 // changes above. this way, we won't "lose" the autoplay irp. 01293 // it's up to the lower driver to determine if powering up is a 01294 // good idea. 01295 // 01296 01297 DebugPrint((ClassDebugMCN, 01298 "ClassCheckMediaState: device %p needs to powerup " 01299 "to handle this io (may take a few extra seconds).\n", 01300 FdoExtension->DeviceObject)); 01301 01302 } 01303 01304 Info->MediaChangeIrpTimeInUse = 0; 01305 Info->MediaChangeIrpLost = FALSE; 01306 01307 if (CountDown == 0) { 01308 01309 PIRP irp; 01310 01311 DebugPrint((ClassDebugTrace, 01312 "ClassCheckMediaState: timer expired\n")); 01313 01314 if (Info->MediaChangeDetectionDisableCount != 0) { 01315 DebugPrint((ClassDebugTrace, 01316 "ClassCheckMediaState: detection disabled\n")); 01317 LEAVE; 01318 } 01319 01320 // 01321 // Prepare the IRP for the test unit ready 01322 // 01323 01324 irp = ClasspPrepareMcnIrp(FdoExtension, 01325 Info, 01326 Info->Gesn.Supported); 01327 01328 // 01329 // Issue the request. 01330 // 01331 01332 DebugPrint((ClassDebugTrace, 01333 "ClasspSendMediaStateIrp: Device %p getting TUR " 01334 " irp %p\n", FdoExtension->DeviceObject, irp)); 01335 01336 if (irp == NULL) { 01337 LEAVE; 01338 } 01339 01340 01341 // 01342 // note: if we send it to the class dispatch routines, there is 01343 // a timing window here (since they grab the remove lock) 01344 // where we'd be removed. ELIMINATE the window by grabbing 01345 // the lock ourselves above and sending it to the lower 01346 // device object directly or to the device's StartIo 01347 // routine (which doesn't acquire the lock). 01348 // 01349 01350 requestPending = TRUE; 01351 01352 DBGTRACE(ClassDebugMCN, (" ClasspSendMediaStateIrp - calling IoCallDriver.")); 01353 IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject, irp); 01354 } 01355 01356 } FINALLY { 01357 01358 if(requestPending == FALSE) { 01359 irpInUse = InterlockedCompareExchange(&Info->MediaChangeIrpInUse, 0, 1); 01360 #if _MSC_FULL_VER != 13009111 // This compiler always takes the wrong path here. 01361 ASSERT(irpInUse); 01362 #endif 01363 } 01364 01365 } 01366 01367 DBGTRACE(ClassDebugMCN, ("< ClasspSendMediaStateIrp")); 01368 01369 return; 01370 } // end ClasspSendMediaStateIrp() 01371 01372 /*++//////////////////////////////////////////////////////////////////////////// 01373 01374 ClassCheckMediaState() 01375 01376 Routine Description: 01377 01378 This routine is called by the class driver to test for a media change 01379 condition and/or poll for disk failure prediction. It should be called 01380 from the class driver's IO timer routine once per second. 01381 01382 Arguments: 01383 01384 FdoExtension - the device extension 01385 01386 Return Value: 01387 01388 none 01389 01390 --*/ 01391 VOID 01392 ClassCheckMediaState( 01393 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 01394 ) 01395 { 01396 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo; 01397 LONG countDown; 01398 01399 if(info == NULL) { 01400 DebugPrint((ClassDebugTrace, 01401 "ClassCheckMediaState: detection not enabled\n")); 01402 return; 01403 } 01404 01405 // 01406 // Media change support is active and the IRP is waiting. Decrement the 01407 // timer. There is no MP protection on the timer counter. This code 01408 // is the only code that will manipulate the timer counter and only one 01409 // instance of it should be running at any given time. 01410 // 01411 01412 countDown = InterlockedDecrement(&(info->MediaChangeCountDown)); 01413 01414 // 01415 // Try to acquire the media change event. If we can't do it immediately 01416 // then bail out and assume the caller will try again later. 01417 // 01418 ClasspSendMediaStateIrp(FdoExtension, 01419 info, 01420 countDown); 01421 01422 return; 01423 } // end ClassCheckMediaState() 01424 01425 /*++//////////////////////////////////////////////////////////////////////////// 01426 01427 ClassResetMediaChangeTimer() 01428 01429 Routine Description: 01430 01431 Resets the media change count down timer to the default number of seconds. 01432 01433 Arguments: 01434 01435 FdoExtension - the device to reset the timer for 01436 01437 Return Value: 01438 01439 None 01440 01441 --*/ 01442 VOID 01443 ClassResetMediaChangeTimer( 01444 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 01445 ) 01446 { 01447 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo; 01448 01449 if(info != NULL) { 01450 InterlockedExchange(&(info->MediaChangeCountDown), 01451 MEDIA_CHANGE_DEFAULT_TIME); 01452 } 01453 return; 01454 } // end ClassResetMediaChangeTimer() 01455 01456 /*++//////////////////////////////////////////////////////////////////////////// 01457 01458 ClasspInitializePolling() - ISSUE-2000/02/20-henrygab - not documented 01459 01460 Routine Description: 01461 01462 This routine 01463 01464 Arguments: 01465 01466 DeviceObject - 01467 Irp - 01468 01469 Return Value: 01470 01471 --*/ 01472 NTSTATUS 01473 ClasspInitializePolling( 01474 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 01475 IN BOOLEAN AllowDriveToSleep 01476 ) 01477 { 01478 PDEVICE_OBJECT fdo = FdoExtension->DeviceObject; 01479 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData; 01480 01481 ULONG size; 01482 PMEDIA_CHANGE_DETECTION_INFO info; 01483 PIRP irp; 01484 01485 PAGED_CODE(); 01486 01487 if (FdoExtension->MediaChangeDetectionInfo != NULL) { 01488 return STATUS_SUCCESS; 01489 } 01490 01491 info = ExAllocatePoolWithTag(NonPagedPool, 01492 sizeof(MEDIA_CHANGE_DETECTION_INFO), 01493 CLASS_TAG_MEDIA_CHANGE_DETECTION); 01494 01495 if(info != NULL) { 01496 RtlZeroMemory(info, sizeof(MEDIA_CHANGE_DETECTION_INFO)); 01497 01498 FdoExtension->KernelModeMcnContext.FileObject = (PVOID)-1; 01499 FdoExtension->KernelModeMcnContext.DeviceObject = (PVOID)-1; 01500 FdoExtension->KernelModeMcnContext.LockCount = 0; 01501 FdoExtension->KernelModeMcnContext.McnDisableCount = 0; 01502 01503 /* 01504 * Allocate an IRP to carry the Test-Unit-Ready. 01505 * Allocate an extra IRP stack location 01506 * so we can cache our device object in the top location. 01507 */ 01508 irp = IoAllocateIrp((CCHAR)(fdo->StackSize+1), FALSE); 01509 01510 if (irp != NULL) { 01511 01512 PVOID buffer; 01513 01514 buffer = ExAllocatePoolWithTag( 01515 NonPagedPoolCacheAligned, 01516 SENSE_BUFFER_SIZE, 01517 CLASS_TAG_MEDIA_CHANGE_DETECTION); 01518 01519 if (buffer != NULL) { 01520 PIO_STACK_LOCATION irpStack; 01521 PSCSI_REQUEST_BLOCK srb; 01522 PCDB cdb; 01523 01524 srb = &(info->MediaChangeSrb); 01525 info->MediaChangeIrp = irp; 01526 info->SenseBuffer = buffer; 01527 01528 /* 01529 * For the driver that creates an IRP, there is no 'current' stack location. 01530 * Step down one IRP stack location so that the extra top one 01531 * becomes our 'current' one. 01532 */ 01533 IoSetNextIrpStackLocation(irp); 01534 01535 /* 01536 * Cache our device object in the extra top IRP stack location 01537 * so we have it in our completion routine. 01538 */ 01539 irpStack = IoGetCurrentIrpStackLocation(irp); 01540 irpStack->DeviceObject = fdo; 01541 01542 /* 01543 * Now start setting up the next IRP stack location for the call like any driver would. 01544 */ 01545 irpStack = IoGetNextIrpStackLocation(irp); 01546 irpStack->Parameters.Scsi.Srb = srb; 01547 info->MediaChangeIrp = irp; 01548 01549 // 01550 // Initialize the SRB 01551 // 01552 01553 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 01554 01555 // 01556 // Initialize and set up the sense information buffer 01557 // 01558 01559 RtlZeroMemory(buffer, SENSE_BUFFER_SIZE); 01560 srb->SenseInfoBuffer = buffer; 01561 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 01562 01563 // 01564 // Set default values for the media change notification 01565 // configuration. 01566 // 01567 01568 info->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME; 01569 info->MediaChangeDetectionDisableCount = 0; 01570 01571 // 01572 // Assume that there is initially no media in the device 01573 // only notify upper layers if there is something there 01574 // 01575 01576 info->MediaChangeDetectionState = MediaUnknown; 01577 01578 info->MediaChangeIrpTimeInUse = 0; 01579 info->MediaChangeIrpLost = FALSE; 01580 01581 // 01582 // setup all extra flags we'll be setting for this irp 01583 // 01584 info->SrbFlags = 0; 01585 if (AllowDriveToSleep) { 01586 SET_FLAG(info->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE); 01587 } 01588 SET_FLAG(info->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY); 01589 SET_FLAG(info->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); 01590 SET_FLAG(info->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 01591 01592 KeInitializeMutex(&info->MediaChangeMutex, 0x100); 01593 01594 // 01595 // It is ok to support media change events on this 01596 // device. 01597 // 01598 01599 FdoExtension->MediaChangeDetectionInfo = info; 01600 01601 // 01602 // NOTE: the DeviceType is FILE_DEVICE_CD_ROM even 01603 // when the device supports DVD (no need to 01604 // check for FILE_DEVICE_DVD, as it's not a 01605 // valid check). 01606 // 01607 01608 if (FdoExtension->DeviceObject->DeviceType == FILE_DEVICE_CD_ROM){ 01609 01610 NTSTATUS status; 01611 01612 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 01613 "ClasspInitializePolling: Testing for GESN\n")); 01614 status = ClasspInitializeGesn(FdoExtension, info); 01615 if (NT_SUCCESS(status)) { 01616 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 01617 "ClasspInitializePolling: GESN available " 01618 "for %p\n", FdoExtension->DeviceObject)); 01619 ASSERT(info->Gesn.Supported ); 01620 ASSERT(info->Gesn.Buffer != NULL); 01621 ASSERT(info->Gesn.BufferSize != 0); 01622 ASSERT(info->Gesn.EventMask != 0); 01623 // must return here, for ASSERTs to be valid. 01624 return STATUS_SUCCESS; 01625 } 01626 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 01627 "ClasspInitializePolling: GESN *NOT* available " 01628 "for %p\n", FdoExtension->DeviceObject)); 01629 } 01630 01631 ASSERT(info->Gesn.Supported == 0); 01632 ASSERT(info->Gesn.Buffer == NULL); 01633 ASSERT(info->Gesn.BufferSize == 0); 01634 ASSERT(info->Gesn.EventMask == 0); 01635 info->Gesn.Supported = 0; // just in case.... 01636 return STATUS_SUCCESS; 01637 } 01638 01639 IoFreeIrp(irp); 01640 } 01641 01642 ExFreePool(info); 01643 } 01644 01645 // 01646 // nothing to free here 01647 // 01648 return STATUS_INSUFFICIENT_RESOURCES; 01649 01650 } // end ClasspInitializePolling() 01651 01652 NTSTATUS 01653 ClasspInitializeGesn( 01654 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 01655 IN PMEDIA_CHANGE_DETECTION_INFO Info 01656 ) 01657 { 01658 PNOTIFICATION_EVENT_STATUS_HEADER header; 01659 CLASS_DETECTION_STATE detectionState = ClassDetectionUnknown; 01660 PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor; 01661 NTSTATUS status = STATUS_NOT_SUPPORTED; 01662 PIRP irp; 01663 KEVENT event; 01664 BOOLEAN retryImmediately; 01665 ULONG i; 01666 ULONG atapiResets; 01667 01668 01669 PAGED_CODE(); 01670 ASSERT(Info == FdoExtension->MediaChangeDetectionInfo); 01671 01672 // 01673 // read if we already know the abilities of the device 01674 // 01675 01676 ClassGetDeviceParameter(FdoExtension, 01677 CLASSP_REG_SUBKEY_NAME, 01678 CLASSP_REG_MMC_DETECTION_VALUE_NAME, 01679 (PULONG)&detectionState); 01680 01681 if (detectionState == ClassDetectionUnsupported) { 01682 goto ExitWithError; 01683 } 01684 01685 // 01686 // check if the device has a hack flag saying never to try this. 01687 // 01688 01689 if (TEST_FLAG(FdoExtension->PrivateFdoData->HackFlags, 01690 FDO_HACK_GESN_IS_BAD)) { 01691 01692 detectionState = ClassDetectionUnsupported; 01693 ClassSetDeviceParameter(FdoExtension, 01694 CLASSP_REG_SUBKEY_NAME, 01695 CLASSP_REG_MMC_DETECTION_VALUE_NAME, 01696 ClassDetectionSupported); 01697 goto ExitWithError; 01698 01699 } 01700 01701 01702 // 01703 // else go through the process since we allocate buffers and 01704 // get all sorts of device settings. 01705 // 01706 01707 if (Info->Gesn.Buffer == NULL) { 01708 Info->Gesn.Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 01709 GESN_BUFFER_SIZE, 01710 '??cS'); 01711 } 01712 if (Info->Gesn.Buffer == NULL) { 01713 status = STATUS_INSUFFICIENT_RESOURCES; 01714 goto ExitWithError; 01715 } 01716 if (Info->Gesn.Mdl != NULL) { 01717 IoFreeMdl(Info->Gesn.Mdl); 01718 } 01719 Info->Gesn.Mdl = IoAllocateMdl(Info->Gesn.Buffer, 01720 GESN_BUFFER_SIZE, 01721 FALSE, FALSE, NULL); 01722 if (Info->Gesn.Mdl == NULL) { 01723 status = STATUS_INSUFFICIENT_RESOURCES; 01724 goto ExitWithError; 01725 } 01726 01727 MmBuildMdlForNonPagedPool(Info->Gesn.Mdl); 01728 Info->Gesn.BufferSize = GESN_BUFFER_SIZE; 01729 Info->Gesn.EventMask = 0; 01730 01731 // 01732 // all items are prepared to use GESN (except the event mask, so don't 01733 // optimize this part out!). 01734 // 01735 // now see if it really works. we have to loop through this because 01736 // many SAMSUNG (and one COMPAQ) drives timeout when requesting 01737 // NOT_READY events, even when the IMMEDIATE bit is set. :( 01738 // 01739 // using a drive list is cumbersome, so this might fix the problem. 01740 // 01741 01742 adapterDescriptor = FdoExtension->AdapterDescriptor; 01743 atapiResets = 0; 01744 retryImmediately = TRUE; 01745 for (i = 0; i < 16 && retryImmediately == TRUE; i++) { 01746 01747 irp = ClasspPrepareMcnIrp(FdoExtension, Info, TRUE); 01748 if (irp == NULL) { 01749 status = STATUS_INSUFFICIENT_RESOURCES; 01750 goto ExitWithError; 01751 } 01752 01753 ASSERT(TEST_FLAG(Info->MediaChangeSrb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE)); 01754 01755 // 01756 // replace the completion routine with a different one this time... 01757 // 01758 01759 IoSetCompletionRoutine(irp, 01760 ClassSignalCompletion, 01761 &event, 01762 TRUE, TRUE, TRUE); 01763 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 01764 01765 status = IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject, irp); 01766 01767 if (status == STATUS_PENDING) { 01768 status = KeWaitForSingleObject(&event, 01769 Executive, 01770 KernelMode, 01771 FALSE, 01772 NULL); 01773 ASSERT(NT_SUCCESS(status)); 01774 } 01775 ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp); 01776 01777 if (SRB_STATUS(Info->MediaChangeSrb.SrbStatus) != SRB_STATUS_SUCCESS) { 01778 ClassInterpretSenseInfo(FdoExtension->DeviceObject, 01779 &(Info->MediaChangeSrb), 01780 IRP_MJ_SCSI, 01781 0, 01782 0, 01783 &status, 01784 NULL); 01785 } 01786 01787 if ((adapterDescriptor->BusType == BusTypeAtapi) && 01788 (Info->MediaChangeSrb.SrbStatus == SRB_STATUS_BUS_RESET) 01789 ) { 01790 01791 // 01792 // ATAPI unfortunately returns SRB_STATUS_BUS_RESET instead 01793 // of SRB_STATUS_TIMEOUT, so we cannot differentiate between 01794 // the two. if we get this status four time consecutively, 01795 // stop trying this command. it is too late to change ATAPI 01796 // at this point, so special-case this here. (07/10/2001) 01797 // NOTE: any value more than 4 may cause the device to be 01798 // marked missing. 01799 // 01800 01801 atapiResets++; 01802 if (atapiResets >= 4) { 01803 status = STATUS_IO_DEVICE_ERROR; 01804 goto ExitWithError; 01805 } 01806 } 01807 01808 if (status == STATUS_DATA_OVERRUN) { 01809 status = STATUS_SUCCESS; 01810 } 01811 01812 if ((status == STATUS_INVALID_DEVICE_REQUEST) || 01813 (status == STATUS_TIMEOUT) || 01814 (status == STATUS_IO_DEVICE_ERROR) || 01815 (status == STATUS_IO_TIMEOUT) 01816 ) { 01817 01818 // 01819 // with these error codes, we don't ever want to try this command 01820 // again on this device, since it reacts poorly. 01821 // 01822 01823 ClassSetDeviceParameter(FdoExtension, 01824 CLASSP_REG_SUBKEY_NAME, 01825 CLASSP_REG_MMC_DETECTION_VALUE_NAME, 01826 ClassDetectionUnsupported); 01827 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugWarning, 01828 "Classpnp => GESN test failed %x for fdo %p\n", 01829 status, FdoExtension->DeviceObject)); 01830 goto ExitWithError; 01831 01832 01833 } 01834 01835 if (!NT_SUCCESS(status)) { 01836 01837 // 01838 // this may be other errors that should not disable GESN 01839 // for all future start_device calls. 01840 // 01841 01842 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugWarning, 01843 "Classpnp => GESN test failed %x for fdo %p\n", 01844 status, FdoExtension->DeviceObject)); 01845 goto ExitWithError; 01846 } 01847 01848 if (i == 0) { 01849 01850 // 01851 // the first time, the request was just retrieving a mask of 01852 // available bits. use this to mask future requests. 01853 // 01854 01855 header = (PNOTIFICATION_EVENT_STATUS_HEADER)(Info->Gesn.Buffer); 01856 01857 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 01858 "Classpnp => Fdo %p supports event mask %x\n", 01859 FdoExtension->DeviceObject, header->SupportedEventClasses)); 01860 01861 01862 if (TEST_FLAG(header->SupportedEventClasses, 01863 NOTIFICATION_MEDIA_STATUS_CLASS_MASK)) { 01864 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 01865 "Classpnp => GESN supports MCN\n")); 01866 } 01867 if (TEST_FLAG(header->SupportedEventClasses, 01868 NOTIFICATION_DEVICE_BUSY_CLASS_MASK)) { 01869 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 01870 "Classpnp => GESN supports DeviceBusy\n")); 01871 } 01872 Info->Gesn.EventMask = header->SupportedEventClasses; 01873 01874 // 01875 // realistically, we are only considering the following events: 01876 // EXTERNAL REQUEST - this is being tested for play/stop/etc. 01877 // MEDIA STATUS - autorun and ejection requests. 01878 // DEVICE BUSY - to allow us to predict when media will be ready. 01879 // therefore, we should not bother querying for the other, 01880 // unknown events. clear all but the above flags. 01881 // 01882 01883 Info->Gesn.EventMask &= 01884 NOTIFICATION_EXTERNAL_REQUEST_CLASS_MASK | 01885 NOTIFICATION_MEDIA_STATUS_CLASS_MASK | 01886 NOTIFICATION_DEVICE_BUSY_CLASS_MASK ; 01887 01888 01889 // 01890 // HACKHACK - REF #0001 01891 // Some devices will *never* report an event if we've also requested 01892 // that it report lower-priority events. this is due to a 01893 // misunderstanding in the specification wherein a "No Change" is 01894 // interpreted to be a real event. what should occur is that the 01895 // device should ignore "No Change" events when multiple event types 01896 // are requested unless there are no other events waiting. this 01897 // greatly reduces the number of requests that the host must send 01898 // to determine if an event has occurred. Since we must work on all 01899 // drives, default to enabling the hack until we find evidence of 01900 // proper firmware. 01901 // 01902 01903 if (CountOfSetBitsUChar(Info->Gesn.EventMask) == 1) { 01904 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 01905 "Classpnp => GESN hack %s for FDO %p\n", 01906 "not required", FdoExtension->DeviceObject)); 01907 } else { 01908 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 01909 "Classpnp => GESN hack %s for FDO %p\n", 01910 "enabled", FdoExtension->DeviceObject)); 01911 Info->Gesn.HackEventMask = 1; 01912 } 01913 01914 } else { 01915 01916 // 01917 // not the first time looping through, so interpret the results. 01918 // 01919 01920 ClasspInterpretGesnData(FdoExtension, 01921 (PVOID)Info->Gesn.Buffer, 01922 &retryImmediately); 01923 01924 } 01925 01926 } // end loop of GESN requests.... 01927 01928 // 01929 // we can only use this if it can be relied upon for media changes, 01930 // since we are (by definition) no longer going to be polling via 01931 // a TEST_UNIT_READY irp, and drives will not report UNIT ATTENTION 01932 // for this command (although a filter driver, such as one for burning 01933 // cd's, might still fake those errors). 01934 // 01935 // since we also rely upon NOT_READY events to change the cursor 01936 // into a "wait" cursor, we can't use GESN without NOT_READY support. 01937 // 01938 01939 if (TEST_FLAG(Info->Gesn.EventMask, 01940 NOTIFICATION_MEDIA_STATUS_CLASS_MASK) && 01941 TEST_FLAG(Info->Gesn.EventMask, 01942 NOTIFICATION_DEVICE_BUSY_CLASS_MASK) 01943 ) { 01944 01945 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 01946 "Classpnp => Enabling GESN support for fdo %p\n", 01947 FdoExtension->DeviceObject)); 01948 Info->Gesn.Supported = TRUE; 01949 01950 ClassSetDeviceParameter(FdoExtension, 01951 CLASSP_REG_SUBKEY_NAME, 01952 CLASSP_REG_MMC_DETECTION_VALUE_NAME, 01953 ClassDetectionSupported); 01954 01955 return STATUS_SUCCESS; 01956 01957 } 01958 01959 KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN, 01960 "Classpnp => GESN available but not enabled for fdo %p\n", 01961 FdoExtension->DeviceObject)); 01962 goto ExitWithError; 01963 01964 // fall through... 01965 01966 ExitWithError: 01967 if (Info->Gesn.Mdl) { 01968 IoFreeMdl(Info->Gesn.Mdl); 01969 Info->Gesn.Mdl = NULL; 01970 } 01971 if (Info->Gesn.Buffer) { 01972 ExFreePool(Info->Gesn.Buffer); 01973 Info->Gesn.Buffer = NULL; 01974 } 01975 Info->Gesn.Supported = 0; 01976 Info->Gesn.EventMask = 0; 01977 Info->Gesn.BufferSize = 0; 01978 return STATUS_NOT_SUPPORTED; 01979 01980 } 01981 01982 /*++//////////////////////////////////////////////////////////////////////////// 01983 01984 ClassInitializeTestUnitPolling() 01985 01986 Routine Description: 01987 01988 This routine will initialize MCN regardless of the settings stored 01989 in the registry. This should be used with caution, as some devices 01990 react badly to constant io. (i.e. never spin down, continuously cycling 01991 media in changers, ejection of media, etc.) It is highly suggested to 01992 use ClassInitializeMediaChangeDetection() instead. 01993 01994 Arguments: 01995 01996 FdoExtension is the device to poll 01997 01998 AllowDriveToSleep says whether to attempt to allow the drive to sleep 01999 or not. This only affects system-known spin down states, so if a 02000 drive spins itself down, this has no effect until the system spins 02001 it down. 02002 02003 Return Value: 02004 02005 --*/ 02006 NTSTATUS 02007 ClassInitializeTestUnitPolling( 02008 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 02009 IN BOOLEAN AllowDriveToSleep 02010 ) 02011 { 02012 return ClasspInitializePolling(FdoExtension, AllowDriveToSleep); 02013 } // end ClassInitializeTestUnitPolling() 02014 02015 /*++//////////////////////////////////////////////////////////////////////////// 02016 02017 ClassInitializeMediaChangeDetection() 02018 02019 Routine Description: 02020 02021 This routine checks to see if it is safe to initialize MCN (the back end 02022 to autorun) for a given device. It will then check the device-type wide 02023 key "Autorun" in the service key (for legacy reasons), and then look in 02024 the device-specific key to potentially override that setting. 02025 02026 If MCN is to be enabled, all neccessary structures and memory are 02027 allocated and initialized. 02028 02029 This routine MUST be called only from the ClassInit() callback. 02030 02031 Arguments: 02032 02033 FdoExtension - the device to initialize MCN for, if appropriate 02034 02035 EventPrefix - unused, legacy argument. Set to zero. 02036 02037 Return Value: 02038 02039 --*/ 02040 VOID 02041 ClassInitializeMediaChangeDetection( 02042 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 02043 IN PUCHAR EventPrefix 02044 ) 02045 { 02046 PDEVICE_OBJECT fdo = FdoExtension->DeviceObject; 02047 NTSTATUS status; 02048 02049 PCLASS_DRIVER_EXTENSION driverExtension = ClassGetDriverExtension( 02050 fdo->DriverObject); 02051 02052 BOOLEAN disabledForBadHardware; 02053 BOOLEAN disabled; 02054 BOOLEAN instanceOverride; 02055 02056 PAGED_CODE(); 02057 02058 // 02059 // NOTE: This assumes that ClassInitializeMediaChangeDetection is always 02060 // called in the context of the ClassInitDevice callback. If called 02061 // after then this check will have already been made and the 02062 // once a second timer will not have been enabled. 02063 // 02064 02065 disabledForBadHardware = ClasspIsMediaChangeDisabledDueToHardwareLimitation( 02066 FdoExtension, 02067 &(driverExtension->RegistryPath) 02068 ); 02069 02070 if (disabledForBadHardware) { 02071 DebugPrint((ClassDebugMCN, 02072 "ClassInitializeMCN: Disabled due to hardware" 02073 "limitations for this device")); 02074 return; 02075 } 02076 02077 // 02078 // autorun should now be enabled by default for all media types. 02079 // 02080 02081 disabled = ClasspIsMediaChangeDisabledForClass( 02082 FdoExtension, 02083 &(driverExtension->RegistryPath) 02084 ); 02085 02086 DebugPrint((ClassDebugMCN, 02087 "ClassInitializeMCN: Class MCN is %s\n", 02088 (disabled ? "disabled" : "enabled"))); 02089 02090 status = ClasspMediaChangeDeviceInstanceOverride( 02091 FdoExtension, 02092 &instanceOverride); // default value 02093 02094 if (!NT_SUCCESS(status)) { 02095 DebugPrint((ClassDebugMCN, 02096 "ClassInitializeMCN: Instance using default\n")); 02097 } else { 02098 DebugPrint((ClassDebugMCN, 02099 "ClassInitializeMCN: Instance override: %s MCN\n", 02100 (instanceOverride ? "Enabling" : "Disabling"))); 02101 disabled = !instanceOverride; 02102 } 02103 02104 DebugPrint((ClassDebugMCN, 02105 "ClassInitializeMCN: Instance MCN is %s\n", 02106 (disabled ? "disabled" : "enabled"))); 02107 02108 if (disabled) { 02109 return; 02110 } 02111 02112 // 02113 // if the drive is not a CDROM, allow the drive to sleep 02114 // 02115 if (FdoExtension->DeviceObject->DeviceType == FILE_DEVICE_CD_ROM) { 02116 ClasspInitializePolling(FdoExtension, FALSE); 02117 } else { 02118 ClasspInitializePolling(FdoExtension, TRUE); 02119 } 02120 02121 return; 02122 } // end ClassInitializeMediaChangeDetection() 02123 02124 /*++//////////////////////////////////////////////////////////////////////////// 02125 02126 ClasspMediaChangeDeviceInstanceOverride() 02127 02128 Routine Description: 02129 02130 The user can override the global setting to enable or disable Autorun on a 02131 specific cdrom device via the control panel. This routine checks and/or 02132 sets this value. 02133 02134 Arguments: 02135 02136 FdoExtension - the device to set/get the value for 02137 Value - the value to use in a set 02138 SetValue - whether to set the value 02139 02140 Return Value: 02141 02142 TRUE - Autorun is disabled 02143 FALSE - Autorun is not disabled (Default) 02144 02145 --*/ 02146 NTSTATUS 02147 ClasspMediaChangeDeviceInstanceOverride( 02148 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 02149 OUT PBOOLEAN Enabled 02150 ) 02151 { 02152 HANDLE deviceParameterHandle; // cdrom instance key 02153 HANDLE driverParameterHandle; // cdrom specific key 02154 RTL_QUERY_REGISTRY_TABLE queryTable[3]; 02155 OBJECT_ATTRIBUTES objectAttributes; 02156 UNICODE_STRING subkeyName; 02157 NTSTATUS status; 02158 ULONG alwaysEnable; 02159 ULONG alwaysDisable; 02160 ULONG i; 02161 02162 02163 PAGED_CODE(); 02164 02165 deviceParameterHandle = NULL; 02166 driverParameterHandle = NULL; 02167 status = STATUS_UNSUCCESSFUL; 02168 alwaysEnable = FALSE; 02169 alwaysDisable = FALSE; 02170 02171 TRY { 02172 02173 status = IoOpenDeviceRegistryKey( FdoExtension->LowerPdo, 02174 PLUGPLAY_REGKEY_DEVICE, 02175 KEY_ALL_ACCESS, 02176 &deviceParameterHandle 02177 ); 02178 if (!NT_SUCCESS(status)) { 02179 02180 // 02181 // this can occur when a new device is added to the system 02182 // this is due to cdrom.sys being an 'essential' driver 02183 // 02184 DebugPrint((ClassDebugMCN, 02185 "ClassMediaChangeDeviceInstanceDisabled: " 02186 "Could not open device registry key [%lx]\n", status)); 02187 LEAVE; 02188 } 02189 02190 RtlInitUnicodeString(&subkeyName, MCN_REG_SUBKEY_NAME); 02191 InitializeObjectAttributes(&objectAttributes, 02192 &subkeyName, 02193 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 02194 deviceParameterHandle, 02195 (PSECURITY_DESCRIPTOR) NULL); 02196 02197 status = ZwCreateKey(&driverParameterHandle, 02198 KEY_READ, 02199 &objectAttributes, 02200 0, 02201 (PUNICODE_STRING) NULL, 02202 REG_OPTION_NON_VOLATILE, 02203 NULL); 02204 02205 if (!NT_SUCCESS(status)) { 02206 DebugPrint((ClassDebugMCN, 02207 "ClassMediaChangeDeviceInstanceDisabled: " 02208 "subkey could not be created. %lx\n", status)); 02209 LEAVE; 02210 } 02211 02212 // 02213 // Default to not changing autorun behavior, based upon setting 02214 // registryValue to zero. 02215 // 02216 02217 for (i=0;i<2;i++) { 02218 02219 RtlZeroMemory(&queryTable[0], sizeof(queryTable)); 02220 02221 queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 02222 queryTable[0].DefaultType = REG_DWORD; 02223 queryTable[0].DefaultLength = 0; 02224 02225 if (i==0) { 02226 queryTable[0].Name = MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME; 02227 queryTable[0].EntryContext = &alwaysDisable; 02228 queryTable[0].DefaultData = &alwaysDisable; 02229 } else { 02230 queryTable[0].Name = MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME; 02231 queryTable[0].EntryContext = &alwaysEnable; 02232 queryTable[0].DefaultData = &alwaysEnable; 02233 } 02234 02235 // 02236 // don't care if it succeeds, since we set defaults above 02237 // 02238 02239 RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 02240 (PWSTR)driverParameterHandle, 02241 queryTable, 02242 NULL, 02243 NULL); 02244 } 02245 02246 } FINALLY { 02247 02248 if (driverParameterHandle) ZwClose(driverParameterHandle); 02249 if (deviceParameterHandle) ZwClose(deviceParameterHandle); 02250 02251 } 02252 02253 if (alwaysEnable && alwaysDisable) { 02254 02255 DebugPrint((ClassDebugMCN, 02256 "ClassMediaChangeDeviceInstanceDisabled: %s selected\n", 02257 "Both Enable and Disable set -- DISABLE")); 02258 ASSERT(NT_SUCCESS(status)); 02259 status = STATUS_SUCCESS; 02260 *Enabled = FALSE; 02261 02262 } else if (alwaysDisable) { 02263 02264 DebugPrint((ClassDebugMCN, 02265 "ClassMediaChangeDeviceInstanceDisabled: %s selected\n", 02266 "DISABLE")); 02267 ASSERT(NT_SUCCESS(status)); 02268 status = STATUS_SUCCESS; 02269 *Enabled = FALSE; 02270 02271 } else if (alwaysEnable) { 02272 02273 DebugPrint((ClassDebugMCN, 02274 "ClassMediaChangeDeviceInstanceDisabled: %s selected\n", 02275 "ENABLE")); 02276 ASSERT(NT_SUCCESS(status)); 02277 status = STATUS_SUCCESS; 02278 *Enabled = TRUE; 02279 02280 } else { 02281 02282 DebugPrint((ClassDebugMCN, 02283 "ClassMediaChangeDeviceInstanceDisabled: %s selected\n", 02284 "DEFAULT")); 02285 status = STATUS_UNSUCCESSFUL; 02286 02287 } 02288 02289 return status; 02290 02291 } // end ClasspMediaChangeDeviceInstanceOverride() 02292 02293 /*++//////////////////////////////////////////////////////////////////////////// 02294 02295 ClasspIsMediaChangeDisabledDueToHardwareLimitation() 02296 02297 Routine Description: 02298 02299 The key AutoRunAlwaysDisable contains a MULTI_SZ of hardware IDs for 02300 which to never enable MediaChangeNotification. 02301 02302 The user can override the global setting to enable or disable Autorun on a 02303 specific cdrom device via the control panel. 02304 02305 Arguments: 02306 02307 FdoExtension - 02308 RegistryPath - pointer to the unicode string inside 02309 ...\CurrentControlSet\Services\Cdrom 02310 02311 Return Value: 02312 02313 TRUE - no autorun. 02314 FALSE - Autorun may be enabled 02315 02316 --*/ 02317 BOOLEAN 02318 ClasspIsMediaChangeDisabledDueToHardwareLimitation( 02319 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 02320 IN PUNICODE_STRING RegistryPath 02321 ) 02322 { 02323 PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = FdoExtension->DeviceDescriptor; 02324 OBJECT_ATTRIBUTES objectAttributes; 02325 HANDLE serviceKey = NULL; 02326 RTL_QUERY_REGISTRY_TABLE parameters[2]; 02327 02328 UNICODE_STRING deviceUnicodeString; 02329 ANSI_STRING deviceString; 02330 ULONG mediaChangeNotificationDisabled = FALSE; 02331 02332 NTSTATUS status; 02333 02334 02335 PAGED_CODE(); 02336 02337 // 02338 // open the service key. 02339 // 02340 02341 InitializeObjectAttributes(&objectAttributes, 02342 RegistryPath, 02343 OBJ_CASE_INSENSITIVE, 02344 NULL, 02345 NULL); 02346 02347 status = ZwOpenKey(&serviceKey, 02348 KEY_READ, 02349 &objectAttributes); 02350 02351 ASSERT(NT_SUCCESS(status)); 02352 02353 02354 if(!NT_SUCCESS(status)) { 02355 02356 // 02357 // always take the safe path. if we can't open the service key, 02358 // disable autorun 02359 // 02360 02361 return TRUE; 02362 02363 } 02364 02365 TRY { 02366 // 02367 // Determine if drive is in a list of those requiring 02368 // autorun to be disabled. this is stored in a REG_MULTI_SZ 02369 // named AutoRunAlwaysDisable. this is required as some autochangers 02370 // must load the disc to reply to ChkVerify request, causing them 02371 // to cycle discs continuously. 02372 // 02373 02374 PWSTR nullMultiSz; 02375 PUCHAR vendorId; 02376 PUCHAR productId; 02377 PUCHAR revisionId; 02378 ULONG length; 02379 ULONG offset; 02380 02381 deviceString.Buffer = NULL; 02382 deviceUnicodeString.Buffer = NULL; 02383 02384 // 02385 // there may be nothing to check against 02386 // 02387 02388 if ((deviceDescriptor->VendorIdOffset == 0) && 02389 (deviceDescriptor->ProductIdOffset == 0)) { 02390 LEAVE; 02391 } 02392 02393 length = 0; 02394 02395 if (deviceDescriptor->VendorIdOffset == 0) { 02396 vendorId = NULL; 02397 } else { 02398 vendorId = (PUCHAR) deviceDescriptor + deviceDescriptor->VendorIdOffset; 02399 length = strlen(vendorId); 02400 } 02401 02402 if ( deviceDescriptor->ProductIdOffset == 0 ) { 02403 productId = NULL; 02404 } else { 02405 productId = (PUCHAR) deviceDescriptor + deviceDescriptor->ProductIdOffset; 02406 length += strlen(productId); 02407 } 02408 02409 if ( deviceDescriptor->ProductRevisionOffset == 0 ) { 02410 revisionId = NULL; 02411 } else { 02412 revisionId = (PUCHAR) deviceDescriptor + deviceDescriptor->ProductRevisionOffset; 02413 length += strlen(revisionId); 02414 } 02415 02416 // 02417 // allocate a buffer for the string 02418 // 02419 02420 deviceString.Length = (USHORT)( length ); 02421 deviceString.MaximumLength = deviceString.Length + 1; 02422 deviceString.Buffer = (PUCHAR)ExAllocatePoolWithTag( NonPagedPool, 02423 deviceString.MaximumLength, 02424 CLASS_TAG_AUTORUN_DISABLE 02425 ); 02426 if (deviceString.Buffer == NULL) { 02427 DebugPrint((ClassDebugMCN, 02428 "ClassMediaChangeDisabledForHardware: Unable to alloc " 02429 "string buffer\n" )); 02430 LEAVE; 02431 } 02432 02433 // 02434 // copy strings to the buffer 02435 // 02436 offset = 0; 02437 02438 if (vendorId != NULL) { 02439 RtlCopyMemory(deviceString.Buffer + offset, 02440 vendorId, 02441 strlen(vendorId)); 02442 offset += strlen(vendorId); 02443 } 02444 02445 if ( productId != NULL ) { 02446 RtlCopyMemory(deviceString.Buffer + offset, 02447 productId, 02448 strlen(productId)); 02449 offset += strlen(productId); 02450 } 02451 if ( revisionId != NULL ) { 02452 RtlCopyMemory(deviceString.Buffer + offset, 02453 revisionId, 02454 strlen(revisionId)); 02455 offset += strlen(revisionId); 02456 } 02457 02458 ASSERT(offset == deviceString.Length); 02459 02460 deviceString.Buffer[deviceString.Length] = '\0'; // Null-terminated 02461 02462 // 02463 // convert to unicode as registry deals with unicode strings 02464 // 02465 02466 status = RtlAnsiStringToUnicodeString( &deviceUnicodeString, 02467 &deviceString, 02468 TRUE 02469 ); 02470 if (!NT_SUCCESS(status)) { 02471 DebugPrint((ClassDebugMCN, 02472 "ClassMediaChangeDisabledForHardware: cannot convert " 02473 "to unicode %lx\n", status)); 02474 LEAVE; 02475 } 02476 02477 // 02478 // query the value, setting valueFound to true if found 02479 // 02480 02481 RtlZeroMemory(parameters, sizeof(parameters)); 02482 02483 nullMultiSz = L"\0"; 02484 parameters[0].QueryRoutine = ClasspMediaChangeRegistryCallBack; 02485 parameters[0].Flags = RTL_QUERY_REGISTRY_REQUIRED; 02486 parameters[0].Name = L"AutoRunAlwaysDisable"; 02487 parameters[0].EntryContext = &mediaChangeNotificationDisabled; 02488 parameters[0].DefaultType = REG_MULTI_SZ; 02489 parameters[0].DefaultData = nullMultiSz; 02490 parameters[0].DefaultLength = 0; 02491 02492 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 02493 serviceKey, 02494 parameters, 02495 &deviceUnicodeString, 02496 NULL); 02497 02498 if ( !NT_SUCCESS(status) ) { 02499 LEAVE; 02500 } 02501 02502 } FINALLY { 02503 02504 if (deviceString.Buffer != NULL) { 02505 ExFreePool( deviceString.Buffer ); 02506 } 02507 if (deviceUnicodeString.Buffer != NULL) { 02508 RtlFreeUnicodeString( &deviceUnicodeString ); 02509 } 02510 02511 ZwClose(serviceKey); 02512 } 02513 02514 if (mediaChangeNotificationDisabled) { 02515 DebugPrint((ClassDebugMCN, "ClassMediaChangeDisabledForHardware: " 02516 "Device is on disable list\n")); 02517 return TRUE; 02518 } 02519 return FALSE; 02520 02521 } // end ClasspIsMediaChangeDisabledDueToHardwareLimitation() 02522 02523 /*++//////////////////////////////////////////////////////////////////////////// 02524 02525 ClasspIsMediaChangeDisabledForClass() 02526 02527 Routine Description: 02528 02529 The user must specify that AutoPlay is to run on the platform 02530 by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\ 02531 Services<SERVICE>\Autorun:REG_DWORD:1. 02532 02533 The user can override the global setting to enable or disable Autorun on a 02534 specific cdrom device via the control panel. 02535 02536 Arguments: 02537 02538 FdoExtension - 02539 RegistryPath - pointer to the unicode string inside 02540 ...\CurrentControlSet\Services\Cdrom 02541 02542 Return Value: 02543 02544 TRUE - Autorun is disabled for this class 02545 FALSE - Autorun is enabled for this class 02546 02547 --*/ 02548 BOOLEAN 02549 ClasspIsMediaChangeDisabledForClass( 02550 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 02551 IN PUNICODE_STRING RegistryPath 02552 ) 02553 { 02554 PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor = FdoExtension->DeviceDescriptor; 02555 02556 OBJECT_ATTRIBUTES objectAttributes; 02557 HANDLE serviceKey = NULL; 02558 HANDLE parametersKey = NULL; 02559 RTL_QUERY_REGISTRY_TABLE parameters[3]; 02560 02561 UNICODE_STRING paramStr; 02562 UNICODE_STRING deviceUnicodeString; 02563 ANSI_STRING deviceString; 02564 02565 // 02566 // Default to ENABLING MediaChangeNotification (!) 02567 // 02568 02569 ULONG mcnRegistryValue = 1; 02570 02571 NTSTATUS status; 02572 02573 02574 PAGED_CODE(); 02575 02576 // 02577 // open the service key. 02578 // 02579 02580 InitializeObjectAttributes(&objectAttributes, 02581 RegistryPath, 02582 OBJ_CASE_INSENSITIVE, 02583 NULL, 02584 NULL); 02585 02586 status = ZwOpenKey(&serviceKey, 02587 KEY_READ, 02588 &objectAttributes); 02589 02590 ASSERT(NT_SUCCESS(status)); 02591 02592 if(!NT_SUCCESS(status)) { 02593 02594 // 02595 // return the default value, which is the 02596 // inverse of the registry setting default 02597 // since this routine asks if it's disabled 02598 // 02599 02600 DebugPrint((ClassDebugMCN, "ClassCheckServiceMCN: Defaulting to %s\n", 02601 (mcnRegistryValue ? "Enabled" : "Disabled"))); 02602 return (BOOLEAN)(!mcnRegistryValue); 02603 02604 } 02605 02606 RtlZeroMemory(parameters, sizeof(parameters)); 02607 02608 // 02609 // Open the parameters key (if any) beneath the services key. 02610 // 02611 02612 RtlInitUnicodeString(¶mStr, L"Parameters"); 02613 02614 InitializeObjectAttributes(&objectAttributes, 02615 ¶mStr, 02616 OBJ_CASE_INSENSITIVE, 02617 serviceKey, 02618 NULL); 02619 02620 status = ZwOpenKey(¶metersKey, 02621 KEY_READ, 02622 &objectAttributes); 02623 02624 if (!NT_SUCCESS(status)) { 02625 parametersKey = NULL; 02626 } 02627 02628 02629 02630 // 02631 // Check for the Autorun value. 02632 // 02633 02634 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 02635 parameters[0].Name = L"Autorun"; 02636 parameters[0].EntryContext = &mcnRegistryValue; 02637 parameters[0].DefaultType = REG_DWORD; 02638 parameters[0].DefaultData = &mcnRegistryValue; 02639 parameters[0].DefaultLength = sizeof(ULONG); 02640 02641 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE | RTL_REGISTRY_OPTIONAL, 02642 serviceKey, 02643 parameters, 02644 NULL, 02645 NULL); 02646 02647 DebugPrint((ClassDebugMCN, "ClassCheckServiceMCN: " 02648 "<Service>/Autorun flag = %d\n", mcnRegistryValue)); 02649 02650 if(parametersKey != NULL) { 02651 02652 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE | RTL_REGISTRY_OPTIONAL, 02653 parametersKey, 02654 parameters, 02655 NULL, 02656 NULL); 02657 DebugPrint((ClassDebugMCN, "ClassCheckServiceMCN: " 02658 "<Service>/Parameters/Autorun flag = %d\n", 02659 mcnRegistryValue)); 02660 ZwClose(parametersKey); 02661 02662 } 02663 ZwClose(serviceKey); 02664 02665 DebugPrint((ClassDebugMCN, "ClassCheckServiceMCN: " 02666 "Autoplay for device %p is %s\n", 02667 FdoExtension->DeviceObject, 02668 (mcnRegistryValue ? "on" : "off") 02669 )); 02670 02671 // 02672 // return if it is _disabled_, which is the 02673 // inverse of the registry setting 02674 // 02675 02676 return (BOOLEAN)(!mcnRegistryValue); 02677 } // end ClasspIsMediaChangeDisabledForClass() 02678 02679 /*++//////////////////////////////////////////////////////////////////////////// 02680 02681 ClassEnableMediaChangeDetection() ISSUE-2000/02/20-henrygab - why public? 02682 ClassEnableMediaChangeDetection() ISSUE-2000/02/20-henrygab - not documented 02683 02684 Routine Description: 02685 02686 This routine 02687 02688 Arguments: 02689 02690 DeviceObject - 02691 Irp - 02692 02693 Return Value: 02694 02695 --*/ 02696 VOID 02697 ClassEnableMediaChangeDetection( 02698 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 02699 ) 02700 { 02701 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo; 02702 LONG oldCount; 02703 02704 PAGED_CODE(); 02705 02706 if(info == NULL) { 02707 DebugPrint((ClassDebugMCN, 02708 "ClassEnableMediaChangeDetection: not initialized\n")); 02709 return; 02710 } 02711 02712 KeWaitForMutexObject(&info->MediaChangeMutex, 02713 UserRequest, 02714 KernelMode, 02715 FALSE, 02716 NULL); 02717 02718 oldCount = --info->MediaChangeDetectionDisableCount; 02719 02720 ASSERT(oldCount >= 0); 02721 02722 DebugPrint((ClassDebugMCN, "ClassEnableMediaChangeDetection: Disable count " 02723 "reduced to %d - ", 02724 info->MediaChangeDetectionDisableCount)); 02725 02726 if(oldCount == 0) { 02727 02728 // 02729 // We don't know what state the media is in anymore. 02730 // 02731 02732 ClasspInternalSetMediaChangeState(FdoExtension, 02733 MediaUnknown, 02734 FALSE 02735 ); 02736 02737 // 02738 // Reset the MCN timer. 02739 // 02740 02741 ClassResetMediaChangeTimer(FdoExtension); 02742 02743 DebugPrint((ClassDebugMCN, "MCD is enabled\n")); 02744 02745 } else { 02746 02747 DebugPrint((ClassDebugMCN, "MCD still disabled\n")); 02748 02749 } 02750 02751 02752 // 02753 // Let something else run. 02754 // 02755 02756 KeReleaseMutex(&info->MediaChangeMutex, FALSE); 02757 02758 return; 02759 } // end ClassEnableMediaChangeDetection() 02760 02761 /*++//////////////////////////////////////////////////////////////////////////// 02762 02763 ClassDisableMediaChangeDetection() ISSUE-2000/02/20-henrygab - why public? 02764 ClassDisableMediaChangeDetection() ISSUE-2000/02/20-henrygab - not documented 02765 02766 Routine Description: 02767 02768 This routine 02769 02770 Arguments: 02771 02772 DeviceObject - 02773 Irp - 02774 02775 Return Value: 02776 02777 --*/ 02778 ULONG BreakOnMcnDisable = FALSE; 02779 02780 VOID 02781 ClassDisableMediaChangeDetection( 02782 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 02783 ) 02784 { 02785 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo; 02786 02787 PAGED_CODE(); 02788 02789 if(info == NULL) { 02790 return; 02791 } 02792 02793 KeWaitForMutexObject(&info->MediaChangeMutex, 02794 UserRequest, 02795 KernelMode, 02796 FALSE, 02797 NULL); 02798 02799 info->MediaChangeDetectionDisableCount++; 02800 02801 DebugPrint((ClassDebugMCN, "ClassDisableMediaChangeDetection: " 02802 "disable count is %d\n", 02803 info->MediaChangeDetectionDisableCount)); 02804 02805 KeReleaseMutex(&info->MediaChangeMutex, FALSE); 02806 02807 return; 02808 } // end ClassDisableMediaChangeDetection() 02809 02810 /*++//////////////////////////////////////////////////////////////////////////// 02811 02812 ClassCleanupMediaChangeDetection() ISSUE-2000/02/20-henrygab - why public?! 02813 02814 Routine Description: 02815 02816 This routine will cleanup any resources allocated for MCN. It is called 02817 by classpnp during remove device, and therefore is not typically required 02818 by external drivers. 02819 02820 Arguments: 02821 02822 Return Value: 02823 02824 --*/ 02825 VOID 02826 ClassCleanupMediaChangeDetection( 02827 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 02828 ) 02829 { 02830 PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo; 02831 02832 PAGED_CODE() 02833 02834 if(info == NULL) { 02835 return; 02836 } 02837 02838 FdoExtension->MediaChangeDetectionInfo = NULL; 02839 02840 if (info->Gesn.Buffer) { 02841 ExFreePool(info->Gesn.Buffer); 02842 } 02843 IoFreeIrp(info->MediaChangeIrp); 02844 ExFreePool(info->SenseBuffer); 02845 ExFreePool(info); 02846 return; 02847 } // end ClassCleanupMediaChangeDetection() 02848 02849 /*++//////////////////////////////////////////////////////////////////////////// 02850 02851 ClasspMcnControl() - ISSUE-2000/02/20-henrygab - not documented 02852 02853 Routine Description: 02854 02855 This routine 02856 02857 Arguments: 02858 02859 DeviceObject - 02860 Irp - 02861 02862 Return Value: 02863 02864 --*/ 02865 NTSTATUS 02866 ClasspMcnControl( 02867 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 02868 IN PIRP Irp, 02869 IN PSCSI_REQUEST_BLOCK Srb 02870 ) 02871 { 02872 PCOMMON_DEVICE_EXTENSION commonExtension = 02873 (PCOMMON_DEVICE_EXTENSION) FdoExtension; 02874 02875 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 02876 PPREVENT_MEDIA_REMOVAL request = Irp->AssociatedIrp.SystemBuffer; 02877 02878 PFILE_OBJECT fileObject = irpStack->FileObject; 02879 PFILE_OBJECT_EXTENSION fsContext = NULL; 02880 02881 NTSTATUS status = STATUS_SUCCESS; 02882 02883 PAGED_CODE(); 02884 02885 // 02886 // Check to make sure we have a file object extension to keep track of this 02887 // request. If not we'll fail it before synchronizing. 02888 // 02889 02890 TRY { 02891 02892 if(fileObject != NULL) { 02893 fsContext = ClasspGetFsContext(commonExtension, fileObject); 02894 }else if(Irp->RequestorMode == KernelMode) { // && fileObject == NULL 02895 fsContext = &FdoExtension->KernelModeMcnContext; 02896 } 02897 02898 if (fsContext == NULL) { 02899 02900 // 02901 // This handle isn't setup correctly. We can't let the 02902 // operation go. 02903 // 02904 02905 status = STATUS_INVALID_PARAMETER; 02906 LEAVE; 02907 } 02908 02909 if(request->PreventMediaRemoval) { 02910 02911 // 02912 // This is a lock command. Reissue the command in case bus or 02913 // device was reset and the lock was cleared. 02914 // 02915 02916 ClassDisableMediaChangeDetection(FdoExtension); 02917 InterlockedIncrement(&(fsContext->McnDisableCount)); 02918 02919 } else { 02920 02921 if(fsContext->McnDisableCount == 0) { 02922 status = STATUS_INVALID_DEVICE_STATE; 02923 LEAVE; 02924 } 02925 02926 InterlockedDecrement(&(fsContext->McnDisableCount)); 02927 ClassEnableMediaChangeDetection(FdoExtension); 02928 } 02929 02930 } FINALLY { 02931 02932 Irp->IoStatus.Status = status; 02933 02934 if(Srb) { 02935 ExFreePool(Srb); 02936 } 02937 02938 ClassReleaseRemoveLock(FdoExtension->DeviceObject, Irp); 02939 ClassCompleteRequest(FdoExtension->DeviceObject, 02940 Irp, 02941 IO_NO_INCREMENT); 02942 } 02943 return status; 02944 } // end ClasspMcnControl( 02945 02946 /*++//////////////////////////////////////////////////////////////////////////// 02947 02948 ClasspMediaChangeRegistryCallBack() 02949 02950 Routine Description: 02951 02952 This callback for a registry SZ or MULTI_SZ is called once for each 02953 SZ in the value. It will attempt to match the data with the 02954 UNICODE_STRING passed in as Context, and modify EntryContext if a 02955 match is found. Written for ClasspCheckRegistryForMediaChangeCompletion 02956 02957 Arguments: 02958 02959 ValueName - name of the key that was opened 02960 ValueType - type of data stored in the value (REG_SZ for this routine) 02961 ValueData - data in the registry, in this case a wide string 02962 ValueLength - length of the data including the terminating null 02963 Context - unicode string to compare against ValueData 02964 EntryContext - should be initialized to 0, will be set to 1 if match found 02965 02966 Return Value: 02967 02968 STATUS_SUCCESS 02969 EntryContext will be 1 if found 02970 02971 --*/ 02972 NTSTATUS 02973 ClasspMediaChangeRegistryCallBack( 02974 IN PWSTR ValueName, 02975 IN ULONG ValueType, 02976 IN PVOID ValueData, 02977 IN ULONG ValueLength, 02978 IN PVOID Context, 02979 IN PVOID EntryContext 02980 ) 02981 { 02982 PULONG valueFound; 02983 PUNICODE_STRING deviceString; 02984 PWSTR keyValue; 02985 02986 PAGED_CODE(); 02987 UNREFERENCED_PARAMETER(ValueName); 02988 02989 02990 // 02991 // if we have already set the value to true, exit 02992 // 02993 02994 valueFound = EntryContext; 02995 if ((*valueFound) != 0) { 02996 DebugPrint((ClassDebugMCN, "ClasspMcnRegCB: already set to true\n")); 02997 return STATUS_SUCCESS; 02998 } 02999 03000 if (ValueLength == sizeof(WCHAR)) { 03001 DebugPrint((ClassDebugError, "ClasspMcnRegCB: NULL string should " 03002 "never be passed to registry call-back!\n")); 03003 return STATUS_SUCCESS; 03004 } 03005 03006 03007 // 03008 // if the data is not a terminated string, exit 03009 // 03010 03011 if (ValueType != REG_SZ) { 03012 return STATUS_SUCCESS; 03013 } 03014 03015 deviceString = Context; 03016 keyValue = ValueData; 03017 ValueLength -= sizeof(WCHAR); // ignore the null character 03018 03019 // 03020 // do not compare more memory than is in deviceString 03021 // 03022 03023 if (ValueLength > deviceString->Length) { 03024 ValueLength = deviceString->Length; 03025 } 03026 03027 // 03028 // if the strings match, disable autorun 03029 // 03030 03031 if (RtlCompareMemory(deviceString->Buffer, keyValue, ValueLength) == ValueLength) { 03032 DebugPrint((ClassDebugMCN, "ClasspRegMcnCB: Match found\n")); 03033 DebugPrint((ClassDebugMCN, "ClasspRegMcnCB: DeviceString at %p\n", 03034 deviceString->Buffer)); 03035 DebugPrint((ClassDebugMCN, "ClasspRegMcnCB: KeyValue at %p\n", 03036 keyValue)); 03037 (*valueFound) = TRUE; 03038 } 03039 03040 return STATUS_SUCCESS; 03041 } // end ClasspMediaChangeRegistryCallBack() 03042 03043 /*++//////////////////////////////////////////////////////////////////////////// 03044 03045 ClasspTimerTick() - ISSUE-2000/02/20-henrygab - not documented 03046 03047 Routine Description: 03048 03049 This routine 03050 03051 Arguments: 03052 03053 DeviceObject - 03054 Irp - 03055 03056 Return Value: 03057 03058 --*/ 03059 VOID 03060 ClasspTimerTick( 03061 PDEVICE_OBJECT DeviceObject, 03062 PVOID Context 03063 ) 03064 { 03065 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 03066 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 03067 ULONG isRemoved; 03068 03069 ASSERT(commonExtension->IsFdo); 03070 03071 // 03072 // Do any media change work 03073 // 03074 isRemoved = ClassAcquireRemoveLock(DeviceObject, (PIRP)ClasspTimerTick); 03075 03076 // 03077 // We stop the timer before deleting the device. It's safe to keep going 03078 // if the flag value is REMOVE_PENDING because the removal thread will be 03079 // blocked trying to stop the timer. 03080 // 03081 03082 ASSERT(isRemoved != REMOVE_COMPLETE); 03083 03084 // 03085 // This routine is reasonably safe even if the device object has a pending 03086 // remove 03087 03088 if(!isRemoved) { 03089 03090 PFAILURE_PREDICTION_INFO info = fdoExtension->FailurePredictionInfo; 03091 03092 // 03093 // Do any media change detection work 03094 // 03095 03096 if (fdoExtension->MediaChangeDetectionInfo != NULL) { 03097 03098 ClassCheckMediaState(fdoExtension); 03099 03100 } 03101 03102 // 03103 // Do any failure prediction work 03104 // 03105 if ((info != NULL) && (info->Method != FailurePredictionNone)) { 03106 03107 ULONG countDown; 03108 ULONG active; 03109 03110 if (ClasspCanSendPollingIrp(fdoExtension)) { 03111 03112 // 03113 // Synchronization is not required here since the Interlocked 03114 // locked instruction guarantees atomicity. Other code that 03115 // resets CountDown uses InterlockedExchange which is also 03116 // atomic. 03117 // 03118 countDown = InterlockedDecrement(&info->CountDown); 03119 if (countDown == 0) { 03120 03121 DebugPrint((4, "ClasspTimerTick: Send FP irp for %p\n", 03122 DeviceObject)); 03123 03124 if(info->WorkQueueItem == NULL) { 03125 03126 info->WorkQueueItem = 03127 IoAllocateWorkItem(fdoExtension->DeviceObject); 03128 03129 if(info->WorkQueueItem == NULL) { 03130 03131 // 03132 // Set the countdown to one minute in the future. 03133 // we'll try again then in the hopes there's more 03134 // free memory. 03135 // 03136 03137 DebugPrint((1, "ClassTimerTick: Couldn't allocate " 03138 "item - try again in one minute\n")); 03139 InterlockedExchange(&info->CountDown, 60); 03140 03141 } else { 03142 03143 // 03144 // Grab the remove lock so that removal will block 03145 // until the work item is done. 03146 // 03147 03148 ClassAcquireRemoveLock(fdoExtension->DeviceObject, 03149 info->WorkQueueItem); 03150 03151 IoQueueWorkItem(info->WorkQueueItem, 03152 ClasspFailurePredict, 03153 DelayedWorkQueue, 03154 info); 03155 } 03156 03157 } else { 03158 03159 DebugPrint((3, "ClasspTimerTick: Failure " 03160 "Prediction work item is " 03161 "already active for device %p\n", 03162 DeviceObject)); 03163 03164 } 03165 } // end (countdown == 0) 03166 03167 } else { 03168 // 03169 // If device is sleeping then just rearm polling timer 03170 DebugPrint((4, "ClassTimerTick, SHHHH!!! device is %p is sleeping\n", 03171 DeviceObject)); 03172 } 03173 03174 } // end failure prediction polling 03175 03176 // 03177 // Give driver a chance to do its own specific work 03178 // 03179 03180 if (commonExtension->DriverExtension->InitData.ClassTick != NULL) { 03181 03182 commonExtension->DriverExtension->InitData.ClassTick(DeviceObject); 03183 03184 } // end device specific tick handler 03185 } // end check for removed 03186 03187 ClassReleaseRemoveLock(DeviceObject, (PIRP)ClasspTimerTick); 03188 } // end ClasspTimerTick() 03189 03190 /*++//////////////////////////////////////////////////////////////////////////// 03191 03192 ClasspEnableTimer() - ISSUE-2000/02/20-henrygab - not documented 03193 03194 Routine Description: 03195 03196 This routine 03197 03198 Arguments: 03199 03200 DeviceObject - 03201 Irp - 03202 03203 Return Value: 03204 03205 --*/ 03206 NTSTATUS 03207 ClasspEnableTimer( 03208 PDEVICE_OBJECT DeviceObject 03209 ) 03210 { 03211 NTSTATUS status; 03212 03213 PAGED_CODE(); 03214 03215 if (DeviceObject->Timer == NULL) { 03216 03217 status = IoInitializeTimer(DeviceObject, ClasspTimerTick, NULL); 03218 03219 } else { 03220 03221 status = STATUS_SUCCESS; 03222 03223 } 03224 03225 if (NT_SUCCESS(status)) { 03226 03227 IoStartTimer(DeviceObject); 03228 DebugPrint((1, "ClasspEnableTimer: Once a second timer enabled " 03229 "for device %p\n", DeviceObject)); 03230 03231 } 03232 03233 DebugPrint((1, "ClasspEnableTimer: Device %p, Status %lx " 03234 "initializing timer\n", DeviceObject, status)); 03235 03236 return status; 03237 03238 } // end ClasspEnableTimer() 03239 03240 /*++//////////////////////////////////////////////////////////////////////////// 03241 03242 ClasspDisableTimer() - ISSUE-2000/02/20-henrygab - not documented 03243 03244 Routine Description: 03245 03246 This routine 03247 03248 Arguments: 03249 03250 DeviceObject - 03251 Irp - 03252 03253 Return Value: 03254 03255 --*/ 03256 NTSTATUS 03257 ClasspDisableTimer( 03258 PDEVICE_OBJECT DeviceObject 03259 ) 03260 { 03261 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 03262 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 03263 PMEDIA_CHANGE_DETECTION_INFO mCDInfo = fdoExtension->MediaChangeDetectionInfo; 03264 PFAILURE_PREDICTION_INFO fPInfo = fdoExtension->FailurePredictionInfo; 03265 NTSTATUS status; 03266 03267 PAGED_CODE(); 03268 03269 if (DeviceObject->Timer != NULL) { 03270 03271 // 03272 // we are only going to stop the actual timer in remove device routine. 03273 // it is the responsibility of the code within the timer routine to 03274 // check if the device is removed and not processing io for the final 03275 // call. 03276 // this keeps the code clean and prevents lots of bugs. 03277 // 03278 03279 03280 IoStopTimer(DeviceObject); 03281 DebugPrint((3, "ClasspDisableTimer: Once a second timer disabled " 03282 "for device %p\n", DeviceObject)); 03283 03284 } else { 03285 03286 DebugPrint((1, "ClasspDisableTimer: Timer never enabled\n")); 03287 03288 } 03289 03290 return STATUS_SUCCESS; 03291 } // end ClasspDisableTimer() 03292 03293 /*++//////////////////////////////////////////////////////////////////////////// 03294 03295 ClasspFailurePredict() - ISSUE-2000/02/20-henrygab - not documented 03296 03297 Routine Description: 03298 03299 This routine 03300 03301 Arguments: 03302 03303 DeviceObject - 03304 Irp - 03305 03306 Return Value: 03307 03308 Note: this function can be called (via the workitem callback) after the paging device is shut down, 03309 so it must be PAGE LOCKED. 03310 --*/ 03311 VOID 03312 ClasspFailurePredict( 03313 IN PDEVICE_OBJECT DeviceObject, 03314 IN PFAILURE_PREDICTION_INFO Info 03315 ) 03316 { 03317 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 03318 PIO_WORKITEM workItem; 03319 STORAGE_PREDICT_FAILURE checkFailure; 03320 SCSI_ADDRESS scsiAddress; 03321 03322 NTSTATUS status; 03323 03324 ASSERT(Info != NULL); 03325 03326 DebugPrint((1, "ClasspFailurePredict: Polling for failure\n")); 03327 03328 // 03329 // Mark the work item as inactive and reset the countdown timer. we 03330 // can't risk freeing the work item until we've released the remove-lock 03331 // though - if we do it might get resused as a tag before we can release 03332 // the lock. 03333 // 03334 03335 InterlockedExchange(&Info->CountDown, Info->Period); 03336 workItem = InterlockedExchangePointer(&(Info->WorkQueueItem), NULL); 03337 03338 if (ClasspCanSendPollingIrp(fdoExtension)) { 03339 03340 KEVENT event; 03341 PDEVICE_OBJECT topOfStack; 03342 PIRP irp = NULL; 03343 IO_STATUS_BLOCK ioStatus; 03344 03345 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 03346 03347 topOfStack = IoGetAttachedDeviceReference(DeviceObject); 03348 03349 // 03350 // Send down irp to see if drive is predicting failure 03351 // 03352 03353 irp = IoBuildDeviceIoControlRequest( 03354 IOCTL_STORAGE_PREDICT_FAILURE, 03355 topOfStack, 03356 NULL, 03357 0, 03358 &checkFailure, 03359 sizeof(STORAGE_PREDICT_FAILURE), 03360 FALSE, 03361 &event, 03362 &ioStatus); 03363 03364 03365 if (irp != NULL) { 03366 status = IoCallDriver(topOfStack, irp); 03367 if (status == STATUS_PENDING) { 03368 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 03369 status = ioStatus.Status; 03370 } 03371 } else { 03372 status = STATUS_INSUFFICIENT_RESOURCES; 03373 } 03374 03375 if (NT_SUCCESS(status) && (checkFailure.PredictFailure)) { 03376 03377 checkFailure.PredictFailure = 512; 03378 03379 // 03380 // Send down irp to get scsi address 03381 // 03382 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 03383 03384 RtlZeroMemory(&scsiAddress, sizeof(SCSI_ADDRESS)); 03385 irp = IoBuildDeviceIoControlRequest( 03386 IOCTL_SCSI_GET_ADDRESS, 03387 topOfStack, 03388 NULL, 03389 0, 03390 &scsiAddress, 03391 sizeof(SCSI_ADDRESS), 03392 FALSE, 03393 &event, 03394 &ioStatus); 03395 03396 if (irp != NULL) { 03397 status = IoCallDriver(topOfStack, irp); 03398 if (status == STATUS_PENDING) { 03399 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 03400 status = ioStatus.Status; 03401 } 03402 } 03403 03404 ClassNotifyFailurePredicted(fdoExtension, 03405 (PUCHAR)&checkFailure, 03406 sizeof(checkFailure), 03407 (BOOLEAN)(fdoExtension->FailurePredicted == FALSE), 03408 2, 03409 scsiAddress.PathId, 03410 scsiAddress.TargetId, 03411 scsiAddress.Lun); 03412 03413 fdoExtension->FailurePredicted = TRUE; 03414 03415 } 03416 03417 ObDereferenceObject(topOfStack); 03418 } 03419 03420 ClassReleaseRemoveLock(DeviceObject, (PIRP) workItem); 03421 IoFreeWorkItem(workItem); 03422 return; 03423 } // end ClasspFailurePredict() 03424 03425 /*++//////////////////////////////////////////////////////////////////////////// 03426 03427 ClassNotifyFailurePredicted() ISSUE-alanwar-2000/02/20 - not documented 03428 03429 Routine Description: 03430 03431 Arguments: 03432 03433 Return Value: 03434 03435 --*/ 03436 VOID 03437 ClassNotifyFailurePredicted( 03438 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 03439 PUCHAR Buffer, 03440 ULONG BufferSize, 03441 BOOLEAN LogError, 03442 ULONG UniqueErrorValue, 03443 UCHAR PathId, 03444 UCHAR TargetId, 03445 UCHAR Lun 03446 ) 03447 { 03448 PIO_ERROR_LOG_PACKET logEntry; 03449 03450 DebugPrint((1, "ClasspFailurePredictPollCompletion: Failure predicted for device %p\n", FdoExtension->DeviceObject)); 03451 03452 // 03453 // Fire off a WMI event 03454 // 03455 ClassWmiFireEvent(FdoExtension->DeviceObject, 03456 &StoragePredictFailureEventGuid, 03457 0, 03458 BufferSize, 03459 Buffer); 03460 03461 // 03462 // Log an error into the eventlog 03463 // 03464 03465 if (LogError) 03466 { 03467 logEntry = IoAllocateErrorLogEntry( 03468 FdoExtension->DeviceObject, 03469 sizeof(IO_ERROR_LOG_PACKET) + (3 * sizeof(ULONG))); 03470 03471 if (logEntry != NULL) 03472 { 03473 03474 logEntry->FinalStatus = STATUS_SUCCESS; 03475 logEntry->ErrorCode = IO_WRN_FAILURE_PREDICTED; 03476 logEntry->SequenceNumber = 0; 03477 logEntry->MajorFunctionCode = IRP_MJ_DEVICE_CONTROL; 03478 logEntry->IoControlCode = IOCTL_STORAGE_PREDICT_FAILURE; 03479 logEntry->RetryCount = 0; 03480 logEntry->UniqueErrorValue = UniqueErrorValue; 03481 logEntry->DumpDataSize = 3; 03482 03483 logEntry->DumpData[0] = PathId; 03484 logEntry->DumpData[1] = TargetId; 03485 logEntry->DumpData[2] = Lun; 03486 03487 // 03488 // Write the error log packet. 03489 // 03490 03491 IoWriteErrorLogEntry(logEntry); 03492 } 03493 } 03494 } // end ClassNotifyFailurePredicted() 03495 03496 /*++//////////////////////////////////////////////////////////////////////////// 03497 03498 ClassSetFailurePredictionPoll() 03499 03500 Routine Description: 03501 03502 This routine enables polling for failure prediction, setting the timer 03503 to fire every N seconds as specified by the PollingPeriod. 03504 03505 Arguments: 03506 03507 FdoExtension - the device to setup failure prediction for. 03508 03509 FailurePredictionMethod - specific failure prediction method to use 03510 if set to FailurePredictionNone, will disable failure detection 03511 03512 PollingPeriod - if 0 then no change to current polling timer 03513 03514 Return Value: 03515 03516 NT Status 03517 03518 --*/ 03519 NTSTATUS 03520 ClassSetFailurePredictionPoll( 03521 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 03522 FAILURE_PREDICTION_METHOD FailurePredictionMethod, 03523 ULONG PollingPeriod 03524 ) 03525 { 03526 PFAILURE_PREDICTION_INFO info; 03527 NTSTATUS status; 03528 DEVICE_POWER_STATE powerState; 03529 03530 PAGED_CODE(); 03531 03532 if (FdoExtension->FailurePredictionInfo == NULL) { 03533 03534 if (FailurePredictionMethod != FailurePredictionNone) { 03535 03536 info = ExAllocatePoolWithTag(NonPagedPool, 03537 sizeof(FAILURE_PREDICTION_INFO), 03538 CLASS_TAG_FAILURE_PREDICT); 03539 03540 if (info == NULL) { 03541 03542 return STATUS_INSUFFICIENT_RESOURCES; 03543 03544 } 03545 03546 KeInitializeEvent(&info->Event, SynchronizationEvent, TRUE); 03547 03548 info->WorkQueueItem = NULL; 03549 info->Period = DEFAULT_FAILURE_PREDICTION_PERIOD; 03550 03551 } else { 03552 03553 // 03554 // FaultPrediction has not been previously initialized, nor 03555 // is it being initialized now. No need to do anything. 03556 // 03557 return STATUS_SUCCESS; 03558 03559 } 03560 03561 FdoExtension->FailurePredictionInfo = info; 03562 03563 } else { 03564 03565 info = FdoExtension->FailurePredictionInfo; 03566 03567 } 03568 03569 KeWaitForSingleObject(&info->Event, 03570 UserRequest, 03571 UserMode, 03572 FALSE, 03573 NULL); 03574 03575 03576 // 03577 // Reset polling period and counter. Setup failure detection type 03578 // 03579 03580 if (PollingPeriod != 0) { 03581 03582 InterlockedExchange(&info->Period, PollingPeriod); 03583 03584 } 03585 03586 InterlockedExchange(&info->CountDown, info->Period); 03587 03588 info->Method = FailurePredictionMethod; 03589 if (FailurePredictionMethod != FailurePredictionNone) { 03590 03591 status = ClasspEnableTimer(FdoExtension->DeviceObject); 03592 03593 if (NT_SUCCESS(status)) { 03594 DebugPrint((3, "ClassEnableFailurePredictPoll: Enabled for " 03595 "device %p\n", FdoExtension->DeviceObject)); 03596 } 03597 03598 } else { 03599 03600 status = ClasspDisableTimer(FdoExtension->DeviceObject); 03601 DebugPrint((3, "ClassEnableFailurePredictPoll: Disabled for " 03602 "device %p\n", FdoExtension->DeviceObject)); 03603 status = STATUS_SUCCESS; 03604 03605 } 03606 03607 KeSetEvent(&info->Event, IO_NO_INCREMENT, FALSE); 03608 03609 return status; 03610 } // end ClassSetFailurePredictionPoll() 03611 Generated on Sun May 27 2012 04:28:16 for ReactOS by
1.7.6.1
|