/drivers/storage/classpnp/autorun.c
C | 3611 lines | 1851 code | 666 blank | 1094 comment | 334 complexity | 0b28795eb0c425014724262cac15eb77 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-3.0, CC-BY-SA-3.0, AGPL-3.0, GPL-3.0, CPL-1.0
Large files files are truncated, but you can click here to view the full file
- /*++
- Copyright (C) Microsoft Corporation, 1991 - 1999
- Module Name:
- autorun.c
- Abstract:
- Code for support of media change detection in the class driver
- Environment:
- kernel mode only
- Notes:
- Revision History:
- --*/
- #include "classp.h"
- #include "debug.h"
- #define GESN_TIMEOUT_VALUE (0x4)
- #define GESN_BUFFER_SIZE (0x8)
- #define MAXIMUM_IMMEDIATE_MCN_RETRIES (0x20)
- #define MCN_REG_SUBKEY_NAME (L"MediaChangeNotification")
- #define MCN_REG_AUTORUN_DISABLE_INSTANCE_NAME (L"AlwaysDisableMCN")
- #define MCN_REG_AUTORUN_ENABLE_INSTANCE_NAME (L"AlwaysEnableMCN")
- GUID StoragePredictFailureEventGuid = WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID;
- //
- // Only send polling irp when device is fully powered up and a
- // power down irp is not in progress.
- //
- // NOTE: This helps close a window in time where a polling irp could cause
- // a drive to spin up right after it has powered down. The problem is
- // that SCSIPORT, ATAPI and SBP2 will be in the process of powering
- // down (which may take a few seconds), but won't know that. It would
- // then get a polling irp which will be put into its queue since it
- // the disk isn't powered down yet. Once the disk is powered down it
- // will find the polling irp in the queue and then power up the
- // device to do the poll. They do not want to check if the polling
- // irp has the SRB_NO_KEEP_AWAKE flag here since it is in a critical
- // path and would slow down all I/Os. A better way to fix this
- // would be to serialize the polling and power down irps so that
- // only one of them is sent to the device at a time.
- //
- #define ClasspCanSendPollingIrp(fdoExtension) \
- ((fdoExtension->DevicePowerState == PowerDeviceD0) && \
- (! fdoExtension->PowerDownInProgress) )
- BOOLEAN
- ClasspIsMediaChangeDisabledDueToHardwareLimitation(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN PUNICODE_STRING RegistryPath
- );
- NTSTATUS
- ClasspMediaChangeDeviceInstanceOverride(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- OUT PBOOLEAN Enabled
- );
- BOOLEAN
- ClasspIsMediaChangeDisabledForClass(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN PUNICODE_STRING RegistryPath
- );
- VOID
- ClasspSetMediaChangeStateEx(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN MEDIA_CHANGE_DETECTION_STATE NewState,
- IN BOOLEAN Wait,
- IN BOOLEAN KnownStateChange // can ignore oldstate == unknown
- );
- NTSTATUS
- ClasspMediaChangeRegistryCallBack(
- IN PWSTR ValueName,
- IN ULONG ValueType,
- IN PVOID ValueData,
- IN ULONG ValueLength,
- IN PVOID Context,
- IN PVOID EntryContext
- );
- VOID
- ClasspSendMediaStateIrp(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN PMEDIA_CHANGE_DETECTION_INFO Info,
- IN ULONG CountDown
- );
- VOID
- ClasspFailurePredict(
- IN PDEVICE_OBJECT DeviceObject,
- IN PFAILURE_PREDICTION_INFO Info
- );
- NTSTATUS
- ClasspInitializePolling(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN BOOLEAN AllowDriveToSleep
- );
- #if ALLOC_PRAGMA
- #pragma alloc_text(PAGE, ClassInitializeMediaChangeDetection)
- #pragma alloc_text(PAGE, ClassEnableMediaChangeDetection)
- #pragma alloc_text(PAGE, ClassDisableMediaChangeDetection)
- #pragma alloc_text(PAGE, ClassCleanupMediaChangeDetection)
- #pragma alloc_text(PAGE, ClasspMediaChangeRegistryCallBack)
- #pragma alloc_text(PAGE, ClasspInitializePolling)
- #pragma alloc_text(PAGE, ClasspIsMediaChangeDisabledDueToHardwareLimitation)
- #pragma alloc_text(PAGE, ClasspMediaChangeDeviceInstanceOverride)
- #pragma alloc_text(PAGE, ClasspIsMediaChangeDisabledForClass)
- #pragma alloc_text(PAGE, ClassSetFailurePredictionPoll)
- #pragma alloc_text(PAGE, ClasspDisableTimer)
- #pragma alloc_text(PAGE, ClasspEnableTimer)
- #endif
- // ISSUE -- make this public?
- VOID
- ClassSendEjectionNotification(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
- )
- {
- //
- // For post-NT5.1 work, need to move EjectSynchronizationEvent
- // to be a MUTEX so we can attempt to grab it here and benefit
- // from deadlock detection. This will allow checking if the media
- // has been locked by programs before broadcasting these events.
- // (what's the point of broadcasting if the media is not locked?)
- //
- // This would currently only be a slight optimization. For post-NT5.1,
- // it would allow us to send a single PERSISTENT_PREVENT to MMC devices,
- // thereby cleaning up a lot of the ejection code. Then, when the
- // ejection request occured, we could see if any locks for the media
- // existed. if locked, broadcast. if not, we send the eject irp.
- //
-
- //
- // for now, just always broadcast. make this a public routine,
- // so class drivers can add special hacks to broadcast this for their
- // non-MMC-compliant devices also from sense codes.
- //
- DBGTRACE(ClassDebugTrace, ("ClassSendEjectionNotification: media EJECT_REQUEST"));
- ClasspSendNotification(FdoExtension,
- &GUID_IO_MEDIA_EJECT_REQUEST,
- 0,
- NULL);
- return;
- }
- VOID
- ClasspSendNotification(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN const GUID * Guid,
- IN ULONG ExtraDataSize,
- IN PVOID ExtraData
- )
- {
- PTARGET_DEVICE_CUSTOM_NOTIFICATION notification;
- ULONG requiredSize;
-
- requiredSize =
- (sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION) - sizeof(UCHAR)) +
- ExtraDataSize;
- if (requiredSize > 0x0000ffff) {
- // MAX_USHORT, max total size for these events!
- KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugWarning,
- "Error sending event: size too large! (%x)\n",
- requiredSize));
- return;
- }
-
- notification = ExAllocatePoolWithTag(NonPagedPool,
- requiredSize,
- 'oNcS');
-
- //
- // if none allocated, exit
- //
- if (notification == NULL) {
- return;
- }
- //
- // Prepare and send the request!
- //
-
- RtlZeroMemory(notification, requiredSize);
- notification->Version = 1;
- notification->Size = (USHORT)(requiredSize);
- notification->FileObject = NULL;
- notification->NameBufferOffset = -1;
- notification->Event = *Guid;
- RtlCopyMemory(notification->CustomDataBuffer, ExtraData, ExtraDataSize);
- IoReportTargetDeviceChangeAsynchronous(FdoExtension->LowerPdo,
- notification,
- NULL, NULL);
-
- ExFreePool(notification);
- notification = NULL;
- return;
- }
- /*++////////////////////////////////////////////////////////////////////////////
- ClasspInterpretGesnData()
- Routine Description:
- This routine will interpret the data returned for a GESN command, and
- (if appropriate) set the media change event, and broadcast the
- appropriate events to user mode for applications who care.
- Arguments:
- FdoExtension - the device
-
- DataBuffer - the resulting data from a GESN event.
- requires at least EIGHT valid bytes (header == 4, data == 4)
- ResendImmediately - whether or not to immediately resend the request.
- this should be FALSE if there was no event, FALSE if the reported
- event was of the DEVICE BUSY class, else true.
- Return Value:
-
- None
-
- Notes:
- DataBuffer must be at least four bytes of valid data (header == 4 bytes),
- and have at least eight bytes of allocated memory (all events == 4 bytes).
-
- The call to StartNextPacket may occur before this routine is completed.
- the operational change notifications are informational in nature, and
- while useful, are not neccessary to ensure proper operation. For example,
- if the device morphs to no longer supporting WRITE commands, all further
- write commands will fail. There exists a small timing window wherein
- IOCTL_IS_DISK_WRITABLE may be called and get an incorrect response. If
- a device supports software write protect, it is expected that the
- application can handle such a case.
-
- NOTE: perhaps setting the updaterequired byte to one should be done here.
- if so, it relies upon the setting of a 32-byte value to be an atomic
- operation. unfortunately, there is no simple way to notify a class driver
- which wants to know that the device behavior requires updating.
-
- Not ready events may be sent every second. For example, if we were
- to minimize the number of asynchronous notifications, an application may
- register just after a large busy time was reported. This would then
- prevent the application from knowing the device was busy until some
- arbitrarily chosen timeout has occurred. Also, the GESN request would
- have to still occur, since it checks for non-busy events (such as user
- keybutton presses and media change events) as well. The specification
- states that the lower-numered events get reported first, so busy events,
- while repeating, will only be reported when all other events have been
- cleared from the device.
- --*/
- VOID
- ClasspInterpretGesnData(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN PNOTIFICATION_EVENT_STATUS_HEADER Header,
- IN PBOOLEAN ResendImmediately
- )
- {
- PMEDIA_CHANGE_DETECTION_INFO info;
- LONG dataLength;
- LONG requiredLength;
- info = FdoExtension->MediaChangeDetectionInfo;
- //
- // note: don't allocate anything in this routine so that we can
- // always just 'return'.
- //
- *ResendImmediately = FALSE;
- if (Header->NEA) {
- return;
- }
- if (Header->NotificationClass == NOTIFICATION_NO_CLASS_EVENTS) {
- return;
- }
- //
- // HACKHACK - REF #0001
- // This loop is only taken initially, due to the inability to reliably
- // auto-detect drives that report events correctly at boot. When we
- // detect this behavior during the normal course of running, we will
- // disable the hack, allowing more efficient use of the system. This
- // should occur "nearly" instantly, as the drive should have multiple
- // events queue'd (ie. power, morphing, media).
- //
- if (info->Gesn.HackEventMask) {
- //
- // all events use the low four bytes of zero to indicate
- // that there was no change in status.
- //
- UCHAR thisEvent = Header->ClassEventData[0] & 0xf;
- UCHAR lowestSetBit;
- UCHAR thisEventBit = (1 << Header->NotificationClass);
- ASSERT(TEST_FLAG(info->Gesn.EventMask, thisEventBit));
- //
- // some bit magic here... this results in the lowest set bit only
- //
- lowestSetBit = info->Gesn.EventMask;
- lowestSetBit &= (info->Gesn.EventMask - 1);
- lowestSetBit ^= (info->Gesn.EventMask);
- if (thisEventBit != lowestSetBit) {
-
- //
- // HACKHACK - REF #0001
- // the first time we ever see an event set that is not the lowest
- // set bit in the request (iow, highest priority), we know that the
- // hack is no longer required, as the device is ignoring "no change"
- // events when a real event is waiting in the other requested queues.
- //
- KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
- "Classpnp => GESN::NONE: Compliant drive found, "
- "removing GESN hack (%x, %x)\n",
- thisEventBit, info->Gesn.EventMask));
-
- info->Gesn.HackEventMask = FALSE;
- } else if (thisEvent == 0) {
-
- //
- // HACKHACK - REF #0001
- // note: this hack prevents poorly implemented firmware from constantly
- // returning "No Event". we do this by cycling through the
- // supported list of events here.
- //
- SET_FLAG(info->Gesn.NoChangeEventMask, thisEventBit);
- CLEAR_FLAG(info->Gesn.EventMask, thisEventBit);
- //
- // if we have cycled through all supported event types, then
- // we need to reset the events we are asking about. else we
- // want to resend this request immediately in case there was
- // another event pending.
- //
- if (info->Gesn.EventMask == 0) {
- info->Gesn.EventMask = info->Gesn.NoChangeEventMask;
- info->Gesn.NoChangeEventMask = 0;
- } else {
- *ResendImmediately = TRUE;
- }
- return;
- }
- } // end if (info->Gesn.HackEventMask)
- dataLength =
- (Header->EventDataLength[0] << 8) |
- (Header->EventDataLength[1] & 0xff);
- dataLength -= 2;
- requiredLength = 4; // all events are four bytes
- if (dataLength < requiredLength) {
- KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugWarning,
- "Classpnp => GESN returned only %x bytes data for fdo %p\n",
- dataLength, FdoExtension->DeviceObject));
- return;
- }
- if (dataLength != requiredLength) {
- KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugWarning,
- "Classpnp => GESN returned too many (%x) bytes data for fdo %p\n",
- dataLength, FdoExtension->DeviceObject));
- dataLength = 4;
- }
- /*
- ClasspSendNotification(FdoExtension,
- &GUID_IO_GENERIC_GESN_EVENT,
- sizeof(NOTIFICATION_EVENT_STATUS_HEADER) + dataLength,
- Header)
- */
- switch (Header->NotificationClass) {
- case NOTIFICATION_EXTERNAL_REQUEST_CLASS_EVENTS: { // 0x3
-
- PNOTIFICATION_EXTERNAL_STATUS externalInfo =
- (PNOTIFICATION_EXTERNAL_STATUS)(Header->ClassEventData);
- DEVICE_EVENT_EXTERNAL_REQUEST externalData;
- //
- // unfortunately, due to time constraints, we will only notify
- // about keys being pressed, and not released. this makes keys
- // single-function, but simplifies the code significantly.
- //
-
- if (externalInfo->ExternalEvent !=
- NOTIFICATION_EXTERNAL_EVENT_BUTTON_DOWN) {
- break;
- }
-
- *ResendImmediately = TRUE;
- KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
- "Classpnp => GESN::EXTERNAL: Event: %x Status %x Req %x\n",
- externalInfo->ExternalEvent, externalInfo->ExternalStatus,
- (externalInfo->Request[0] >> 8) | externalInfo->Request[1]
- ));
- RtlZeroMemory(&externalData, sizeof(DEVICE_EVENT_EXTERNAL_REQUEST));
- externalData.Version = 1;
- externalData.DeviceClass = 0;
- externalData.ButtonStatus = externalInfo->ExternalEvent;
- externalData.Request =
- (externalInfo->Request[0] << 8) |
- (externalInfo->Request[1] & 0xff);
- KeQuerySystemTime(&(externalData.SystemTime));
- externalData.SystemTime.QuadPart *= (LONGLONG)KeQueryTimeIncrement();
- DBGTRACE(ClassDebugTrace, ("ClasspInterpretGesnData: media DEVICE_EXTERNAL_REQUEST"));
- ClasspSendNotification(FdoExtension,
- &GUID_IO_DEVICE_EXTERNAL_REQUEST,
- sizeof(DEVICE_EVENT_EXTERNAL_REQUEST),
- &externalData);
- return;
- }
-
- case NOTIFICATION_MEDIA_STATUS_CLASS_EVENTS: { // 0x4
-
- PNOTIFICATION_MEDIA_STATUS mediaInfo =
- (PNOTIFICATION_MEDIA_STATUS)(Header->ClassEventData);
-
- if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_NO_CHANGE) {
- break;
- }
-
- *ResendImmediately = TRUE;
- KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
- "Classpnp => GESN::MEDIA: Event: %x Status %x\n",
- mediaInfo->MediaEvent, mediaInfo->MediaStatus));
-
- if ((mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_NEW_MEDIA) ||
- (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_MEDIA_CHANGE)) {
- if (TEST_FLAG(FdoExtension->DeviceObject->Characteristics,
- FILE_REMOVABLE_MEDIA) &&
- (ClassGetVpb(FdoExtension->DeviceObject) != NULL) &&
- (ClassGetVpb(FdoExtension->DeviceObject)->Flags & VPB_MOUNTED)
- ) {
- SET_FLAG(FdoExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
- }
- InterlockedIncrement(&FdoExtension->MediaChangeCount);
- ClasspSetMediaChangeStateEx(FdoExtension,
- MediaPresent,
- FALSE,
- TRUE);
- } else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_MEDIA_REMOVAL) {
-
- ClasspSetMediaChangeStateEx(FdoExtension,
- MediaNotPresent,
- FALSE,
- TRUE);
-
- } else if (mediaInfo->MediaEvent == NOTIFICATION_MEDIA_EVENT_EJECT_REQUEST) {
- KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugError,
- "Classpnp => GESN Ejection request received!\n"));
- ClassSendEjectionNotification(FdoExtension);
-
- }
- break;
- }
-
- case NOTIFICATION_DEVICE_BUSY_CLASS_EVENTS: { // lowest priority events...
-
- PNOTIFICATION_BUSY_STATUS busyInfo =
- (PNOTIFICATION_BUSY_STATUS)(Header->ClassEventData);
- DEVICE_EVENT_BECOMING_READY busyData;
-
- //
- // NOTE: we never actually need to immediately retry for these
- // events: if one exists, the device is busy, and if not,
- // we still don't want to retry.
- //
- if (busyInfo->DeviceBusyStatus == NOTIFICATION_BUSY_STATUS_NO_EVENT) {
- break;
- }
-
- //
- // else we want to report the approximated time till it's ready.
- //
- RtlZeroMemory(&busyData, sizeof(DEVICE_EVENT_BECOMING_READY));
- busyData.Version = 1;
- busyData.Reason = busyInfo->DeviceBusyStatus;
- busyData.Estimated100msToReady = (busyInfo->Time[0] << 8) |
- (busyInfo->Time[1] & 0xff);
-
- KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
- "Classpnp => GESN::BUSY: Event: %x Status %x Time %x\n",
- busyInfo->DeviceBusyEvent, busyInfo->DeviceBusyStatus,
- busyData.Estimated100msToReady
- ));
- DBGTRACE(ClassDebugTrace, ("ClasspInterpretGesnData: media BECOMING_READY"));
- ClasspSendNotification(FdoExtension,
- &GUID_IO_DEVICE_BECOMING_READY,
- sizeof(DEVICE_EVENT_BECOMING_READY),
- &busyData);
- break;
- }
-
- default: {
-
- break;
- }
-
- } // end switch on notification class
- return;
- }
- /*++////////////////////////////////////////////////////////////////////////////
- ClasspInternalSetMediaChangeState()
- Routine Description:
- This routine will (if appropriate) set the media change event for the
- device. The event will be set if the media state is changed and
- media change events are enabled. Otherwise the media state will be
- tracked but the event will not be set.
- This routine will lock out the other media change routines if possible
- but if not a media change notification may be lost after the enable has
- been completed.
- Arguments:
- FdoExtension - the device
- MediaPresent - indicates whether the device has media inserted into it
- (TRUE) or not (FALSE).
-
- Return Value:
- none
- --*/
- VOID
- ClasspInternalSetMediaChangeState(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN MEDIA_CHANGE_DETECTION_STATE NewState,
- IN BOOLEAN KnownStateChange // can ignore oldstate == unknown
- )
- {
- #if DBG
- PUCHAR states[] = {"Unknown", "Present", "Not Present"};
- #endif
- MEDIA_CHANGE_DETECTION_STATE oldMediaState;
- PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
- ULONG data;
- NTSTATUS status;
- ASSERT((NewState >= MediaUnknown) && (NewState <= MediaNotPresent));
- if(info == NULL) {
- return;
- }
- oldMediaState = InterlockedExchange(
- (PLONG)(&info->MediaChangeDetectionState),
- (LONG)NewState);
- if((oldMediaState == MediaUnknown) && (!KnownStateChange)) {
- //
- // The media was in an indeterminate state before - don't notify for
- // this change.
- //
- DebugPrint((ClassDebugMCN,
- "ClassSetMediaChangeState: State was unknown - this may "
- "not be a change\n"));
- return;
- } else if(oldMediaState == NewState) {
- //
- // Media is in the same state it was before.
- //
- return;
- }
- if(info->MediaChangeDetectionDisableCount != 0) {
- DBGTRACE(ClassDebugMCN,
- ("ClassSetMediaChangeState: MCN not enabled, state "
- "changed from %s to %s\n",
- states[oldMediaState], states[NewState]));
- return;
- }
- DBGTRACE(ClassDebugMCN,
- ("ClassSetMediaChangeState: State change from %s to %s\n",
- states[oldMediaState], states[NewState]));
- //
- // make the data useful -- it used to always be zero.
- //
- data = FdoExtension->MediaChangeCount;
- if (NewState == MediaPresent) {
- DBGTRACE(ClassDebugTrace, ("ClasspInternalSetMediaChangeState: media ARRIVAL"));
- ClasspSendNotification(FdoExtension,
- &GUID_IO_MEDIA_ARRIVAL,
- sizeof(ULONG),
- &data);
- }
- else if (NewState == MediaNotPresent) {
- DBGTRACE(ClassDebugTrace, ("ClasspInternalSetMediaChangeState: media REMOVAL"));
- ClasspSendNotification(FdoExtension,
- &GUID_IO_MEDIA_REMOVAL,
- sizeof(ULONG),
- &data);
- } else {
- //
- // Don't notify of changed going to unknown.
- //
- return;
- }
-
- return;
- } // end ClasspInternalSetMediaChangeState()
- /*++////////////////////////////////////////////////////////////////////////////
- ClassSetMediaChangeState()
- Routine Description:
- This routine will (if appropriate) set the media change event for the
- device. The event will be set if the media state is changed and
- media change events are enabled. Otherwise the media state will be
- tracked but the event will not be set.
- This routine will lock out the other media change routines if possible
- but if not a media change notification may be lost after the enable has
- been completed.
- Arguments:
- FdoExtension - the device
- MediaPresent - indicates whether the device has media inserted into it
- (TRUE) or not (FALSE).
- Wait - indicates whether the function should wait until it can acquire
- the synchronization lock or not.
- Return Value:
- none
- --*/
- VOID
- ClasspSetMediaChangeStateEx(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN MEDIA_CHANGE_DETECTION_STATE NewState,
- IN BOOLEAN Wait,
- IN BOOLEAN KnownStateChange // can ignore oldstate == unknown
- )
- {
- PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
- LARGE_INTEGER zero;
- NTSTATUS status;
- DBGTRACE(ClassDebugMCN, ("> ClasspSetMediaChangeStateEx"));
- //
- // Reset SMART status on media removal as the old status may not be
- // valid when there is no media in the device or when new media is
- // inserted.
- //
- if (NewState == MediaNotPresent) {
- FdoExtension->FailurePredicted = FALSE;
- FdoExtension->FailureReason = 0;
- }
- zero.QuadPart = 0;
- if(info == NULL) {
- return;
- }
- status = KeWaitForMutexObject(&info->MediaChangeMutex,
- Executive,
- KernelMode,
- FALSE,
- ((Wait == TRUE) ? NULL : &zero));
- if(status == STATUS_TIMEOUT) {
- //
- // Someone else is in the process of setting the media state
- //
- DBGWARN(("ClasspSetMediaChangeStateEx - timed out waiting for mutex"));
- return;
- }
- //
- // Change the media present state and signal an event, if applicable
- //
- ClasspInternalSetMediaChangeState(FdoExtension, NewState, KnownStateChange);
- KeReleaseMutex(&info->MediaChangeMutex, FALSE);
- DBGTRACE(ClassDebugMCN, ("< ClasspSetMediaChangeStateEx"));
- return;
- } // end ClassSetMediaChangeStateEx()
- VOID
- ClassSetMediaChangeState(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN MEDIA_CHANGE_DETECTION_STATE NewState,
- IN BOOLEAN Wait
- )
- {
- ClasspSetMediaChangeStateEx(FdoExtension, NewState, Wait, FALSE);
- return;
- }
- /*++////////////////////////////////////////////////////////////////////////////
- ClasspMediaChangeDetectionCompletion()
- Routine Description:
- This routine handles the completion of the test unit ready irps used to
- determine if the media has changed. If the media has changed, this code
- signals the named event to wake up other system services that react to
- media change (aka AutoPlay).
- Arguments:
- DeviceObject - the object for the completion
- Irp - the IRP being completed
- Context - the SRB from the IRP
- Return Value:
- NTSTATUS
- --*/
- NTSTATUS
- ClasspMediaChangeDetectionCompletion(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp,
- PSCSI_REQUEST_BLOCK Srb
- )
- {
- PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
- PCLASS_PRIVATE_FDO_DATA fdoData;
- PMEDIA_CHANGE_DETECTION_INFO info;
- PIO_STACK_LOCATION nextIrpStack;
- NTSTATUS status;
- BOOLEAN retryImmediately = FALSE;
- //
- // Since the class driver created this request, it's completion routine
- // will not get a valid device object handed in. Use the one in the
- // irp stack instead
- //
- DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
- fdoExtension = DeviceObject->DeviceExtension;
- fdoData = fdoExtension->PrivateFdoData;
- info = fdoExtension->MediaChangeDetectionInfo;
- ASSERT(info->MediaChangeIrp != NULL);
- ASSERT(!TEST_FLAG(Srb->SrbStatus, SRB_STATUS_QUEUE_FROZEN));
- DBGTRACE(ClassDebugMCN, ("> ClasspMediaChangeDetectionCompletion: Device %p completed MCN irp %p.", DeviceObject, Irp));
- /*
- * HACK for IoMega 2GB Jaz drive:
- * This drive spins down on its own to preserve the media.
- * When spun down, TUR fails with 2/4/0 (SCSI_SENSE_NOT_READY/SCSI_ADSENSE_LUN_NOT_READY/?).
- * ClassInterpretSenseInfo would then call ClassSendStartUnit to spin the media up, which defeats the
- * purpose of the spindown.
- * So in this case, make this into a successful TUR.
- * This allows the drive to stay spun down until it is actually accessed again.
- * (If the media were actually removed, TUR would fail with 2/3a/0 ).
- * This hack only applies to drives with the CAUSE_NOT_REPORTABLE_HACK bit set; this
- * is set by disk.sys when HackCauseNotReportableHack is set for the drive in its BadControllers list.
- */
- if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
- TEST_FLAG(fdoExtension->ScanForSpecialFlags, CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK) &&
- (Srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode))){
-
- PSENSE_DATA senseData = Srb->SenseInfoBuffer;
-
- if ((senseData->SenseKey == SCSI_SENSE_NOT_READY) &&
- (senseData->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)){
- Srb->SrbStatus = SRB_STATUS_SUCCESS;
- }
- }
-
- //
- // use ClassInterpretSenseInfo() to check for media state, and also
- // to call ClassError() with correct parameters.
- //
- status = STATUS_SUCCESS;
- if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
- DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - failed - srb status=%s, sense=%s/%s/%s.", DBGGETSRBSTATUSSTR(Srb), DBGGETSENSECODESTR(Srb), DBGGETADSENSECODESTR(Srb), DBGGETADSENSEQUALIFIERSTR(Srb)));
- ClassInterpretSenseInfo(DeviceObject,
- Srb,
- IRP_MJ_SCSI,
- 0,
- 0,
- &status,
- NULL);
- }
- else {
-
- fdoData->LoggedTURFailureSinceLastIO = FALSE;
-
- if (!info->Gesn.Supported) {
- DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - succeeded and GESN NOT supported, setting MediaPresent."));
-
- //
- // success != media for GESN case
- //
- ClassSetMediaChangeState(fdoExtension, MediaPresent, FALSE);
- }
- else {
- DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - succeeded (GESN supported)."));
- }
- }
-
- if (info->Gesn.Supported) {
- if (status == STATUS_DATA_OVERRUN) {
- DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - Overrun"));
- status = STATUS_SUCCESS;
- }
- if (!NT_SUCCESS(status)) {
- DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion: GESN failed with status %x", status));
- } else {
- //
- // for GESN, need to interpret the results of the data.
- // this may also require an immediate retry
- //
-
- if (Irp->IoStatus.Information == 8 ) {
- ClasspInterpretGesnData(fdoExtension,
- (PVOID)info->Gesn.Buffer,
- &retryImmediately);
- }
- } // end of NT_SUCCESS(status)
- } // end of Info->Gesn.Supported
- //
- // free port-allocated sense buffer, if any.
- //
- if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) {
- FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb);
- }
- //
- // Remember the IRP and SRB for use the next time.
- //
- ASSERT(IoGetNextIrpStackLocation(Irp));
- IoGetNextIrpStackLocation(Irp)->Parameters.Scsi.Srb = Srb;
- //
- // Reset the MCN timer.
- //
- ClassResetMediaChangeTimer(fdoExtension);
- //
- // run a sanity check to make sure we're not recursing continuously
- //
- if (retryImmediately) {
-
- info->MediaChangeRetryCount++;
- if (info->MediaChangeRetryCount > MAXIMUM_IMMEDIATE_MCN_RETRIES) {
- ASSERT(!"Recursing too often in MCN?");
- info->MediaChangeRetryCount = 0;
- retryImmediately = FALSE;
- }
- } else {
-
- info->MediaChangeRetryCount = 0;
- }
- //
- // release the remove lock....
- //
- {
- UCHAR uniqueValue;
- ClassAcquireRemoveLock(DeviceObject, (PIRP)(&uniqueValue));
- ClassReleaseRemoveLock(DeviceObject, Irp);
-
- //
- // set the irp as not in use
- //
- {
- volatile LONG irpWasInUse;
- irpWasInUse = InterlockedCompareExchange(&info->MediaChangeIrpInUse, 0, 1);
- #if _MSC_FULL_VER != 13009111 // This compiler always takes the wrong path here.
- ASSERT(irpWasInUse);
- #endif
- }
- //
- // now send it again before we release our last remove lock
- //
- if (retryImmediately) {
- ClasspSendMediaStateIrp(fdoExtension, info, 0);
- }
- else {
- DBGTRACE(ClassDebugMCN, ("ClasspMediaChangeDetectionCompletion - not retrying immediately"));
- }
-
- //
- // release the temporary remove lock
- //
-
- ClassReleaseRemoveLock(DeviceObject, (PIRP)(&uniqueValue));
- }
- DBGTRACE(ClassDebugMCN, ("< ClasspMediaChangeDetectionCompletion"));
- return STATUS_MORE_PROCESSING_REQUIRED;
- }
- /*++////////////////////////////////////////////////////////////////////////////
- ClasspSendTestUnitIrp() - ISSUE-2000/02/20-henrygab - not documented
- Routine Description:
- This routine
- Arguments:
- DeviceObject -
- Irp -
- Return Value:
- --*/
- PIRP
- ClasspPrepareMcnIrp(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN PMEDIA_CHANGE_DETECTION_INFO Info,
- IN BOOLEAN UseGesn
- )
- {
- PSCSI_REQUEST_BLOCK srb;
- PIO_STACK_LOCATION irpStack;
- PIO_STACK_LOCATION nextIrpStack;
- NTSTATUS status;
- PCDB cdb;
- PIRP irp;
- PVOID buffer;
- //
- // Setup the IRP to perform a test unit ready.
- //
- irp = Info->MediaChangeIrp;
- ASSERT(irp);
- if (irp == NULL) {
- return NULL;
- }
- //
- // don't keep sending this if the device is being removed.
- //
- status = ClassAcquireRemoveLock(FdoExtension->DeviceObject, irp);
- if (status == REMOVE_COMPLETE) {
- ASSERT(status != REMOVE_COMPLETE);
- return NULL;
- }
- else if (status == REMOVE_PENDING) {
- ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
- return NULL;
- }
- else {
- ASSERT(status == NO_REMOVE);
- }
- irp->IoStatus.Status = STATUS_SUCCESS;
- irp->IoStatus.Information = 0;
- irp->Flags = 0;
- irp->UserBuffer = NULL;
- //
- // If the irp is sent down when the volume needs to be
- // verified, CdRomUpdateGeometryCompletion won't complete
- // it since it's not associated with a thread. Marking
- // it to override the verify causes it always be sent
- // to the port driver
- //
- irpStack = IoGetCurrentIrpStackLocation(irp);
- irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
- nextIrpStack = IoGetNextIrpStackLocation(irp);
- nextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
- nextIrpStack->Parameters.Scsi.Srb = &(Info->MediaChangeSrb);
- //
- // Prepare the SRB for execution.
- //
- srb = nextIrpStack->Parameters.Scsi.Srb;
- buffer = srb->SenseInfoBuffer;
- RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
- RtlZeroMemory(buffer, SENSE_BUFFER_SIZE);
- srb->QueueTag = SP_UNTAGGED;
- srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
- srb->Length = sizeof(SCSI_REQUEST_BLOCK);
- srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
- srb->SenseInfoBuffer = buffer;
- srb->SrbStatus = 0;
- srb->ScsiStatus = 0;
- srb->OriginalRequest = irp;
- srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
-
- srb->SrbFlags = FdoExtension->SrbFlags;
- SET_FLAG(srb->SrbFlags, Info->SrbFlags);
- srb->TimeOutValue = FdoExtension->TimeOutValue * 2;
-
- if (srb->TimeOutValue == 0) {
- if (FdoExtension->TimeOutValue == 0) {
- KdPrintEx((DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL,
- "ClassSendTestUnitIrp: FdoExtension->TimeOutValue "
- "is set to zero?! -- resetting to 10\n"));
- srb->TimeOutValue = 10 * 2; // reasonable default
-
- } else {
-
- KdPrintEx((DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL,
- "ClassSendTestUnitIrp: Someone set "
- "srb->TimeOutValue to zero?! -- resetting to %x\n",
- FdoExtension->TimeOutValue * 2));
- srb->TimeOutValue = FdoExtension->TimeOutValue * 2;
- }
- }
-
- if (!UseGesn) {
-
- srb->CdbLength = 6;
- srb->DataTransferLength = 0;
- SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
- nextIrpStack->Parameters.DeviceIoControl.IoControlCode =
- IOCTL_SCSI_EXECUTE_NONE;
- srb->DataBuffer = NULL;
- srb->DataTransferLength = 0;
- irp->MdlAddress = NULL;
-
- cdb = (PCDB) &srb->Cdb[0];
- cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
- } else {
-
- ASSERT(Info->Gesn.Buffer);
- srb->TimeOutValue = GESN_TIMEOUT_VALUE; // much shorter timeout for GESN
-
- srb->CdbLength = 10;
- SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
- nextIrpStack->Parameters.DeviceIoControl.IoControlCode =
- IOCTL_SCSI_EXECUTE_IN;
- srb->DataBuffer = Info->Gesn.Buffer;
- srb->DataTransferLength = Info->Gesn.BufferSize;
- irp->MdlAddress = Info->Gesn.Mdl;
- cdb = (PCDB) &srb->Cdb[0];
- cdb->GET_EVENT_STATUS_NOTIFICATION.OperationCode =
- SCSIOP_GET_EVENT_STATUS;
- cdb->GET_EVENT_STATUS_NOTIFICATION.Immediate = 1;
- cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[0] =
- (UCHAR)((Info->Gesn.BufferSize) >> 8);
- cdb->GET_EVENT_STATUS_NOTIFICATION.EventListLength[1] =
- (UCHAR)((Info->Gesn.BufferSize) & 0xff);
- cdb->GET_EVENT_STATUS_NOTIFICATION.NotificationClassRequest =
- Info->Gesn.EventMask;
- }
- IoSetCompletionRoutine(irp,
- ClasspMediaChangeDetectionCompletion,
- srb,
- TRUE,
- TRUE,
- TRUE);
- return irp;
- }
- /*++////////////////////////////////////////////////////////////////////////////
- ClasspSendMediaStateIrp() - ISSUE-2000/02/20-henrygab - not documented
- Routine Description:
- This routine
- Arguments:
- DeviceObject -
- Irp -
- Return Value:
- --*/
- VOID
- ClasspSendMediaStateIrp(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN PMEDIA_CHANGE_DETECTION_INFO Info,
- IN ULONG CountDown
- )
- {
- BOOLEAN requestPending = FALSE;
- LONG irpInUse;
- LARGE_INTEGER zero;
- NTSTATUS status;
- DBGTRACE(ClassDebugMCN, ("> ClasspSendMediaStateIrp"));
- if (((FdoExtension->CommonExtension.CurrentState != IRP_MN_START_DEVICE) ||
- (FdoExtension->DevicePowerState != PowerDeviceD0)
- ) &&
- (!Info->MediaChangeIrpLost)) {
- //
- // the device may be stopped, powered down, or otherwise queueing io,
- // so should not timeout the autorun irp (yet) -- set to zero ticks.
- // scattered code relies upon this to not prematurely "lose" an
- // autoplay irp that was queued.
- //
- Info->MediaChangeIrpTimeInUse = 0;
- }
- //
- // if the irp is not in use, mark it as such.
- //
- irpInUse = InterlockedCompareExchange(&Info->MediaChangeIrpInUse, 1, 0);
- if (irpInUse) {
- LONG timeInUse;
- timeInUse = InterlockedIncrement(&Info->MediaChangeIrpTimeInUse);
- DebugPrint((ClassDebugMCN, "ClasspSendMediaStateIrp: irp in use for "
- "%x seconds when synchronizing for MCD\n", timeInUse));
- if (Info->MediaChangeIrpLost == FALSE) {
- if (timeInUse > MEDIA_CHANGE_TIMEOUT_TIME) {
- //
- // currently set to five minutes. hard to imagine a drive
- // taking that long to spin up.
- //
- DebugPrint((ClassDebugError,
- "CdRom%d: Media Change Notification has lost "
- "it's irp and doesn't know where to find it. "
- "Leave it alone and it'll come home dragging "
- "it's stack behind it.\n",
- FdoExtension->DeviceNumber));
- Info->MediaChangeIrpLost = TRUE;
- }
- }
- DBGTRACE(ClassDebugMCN, ("< ClasspSendMediaStateIrp - irpInUse"));
- return;
- }
- TRY {
- if (Info->MediaChangeDetectionDisableCount != 0) {
- DebugPrint((ClassDebugTrace, "ClassCheckMediaState: device %p has "
- " detection disabled \n", FdoExtension->DeviceObject));
- LEAVE;
- }
- if (FdoExtension->DevicePowerState != PowerDeviceD0) {
- if (TEST_FLAG(Info->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE)) {
- DebugPrint((ClassDebugMCN,
- "ClassCheckMediaState: device %p is powered "
- "down and flags are set to let it sleep\n",
- FdoExtension->DeviceObject));
- ClassResetMediaChangeTimer(FdoExtension);
- LEAVE;
- }
- //
- // NOTE: we don't increment the time in use until our power state
- // changes above. this way, we won't "lose" the autoplay irp.
- // it's up to the lower driver to determine if powering up is a
- // good idea.
- //
- DebugPrint((ClassDebugMCN,
- "ClassCheckMediaState: device %p needs to powerup "
- "to handle this io (may take a few extra seconds).\n",
- FdoExtension->DeviceObject));
- }
- Info->MediaChangeIrpTimeInUse = 0;
- Info->MediaChangeIrpLost = FALSE;
- if (CountDown == 0) {
- PIRP irp;
- DebugPrint((ClassDebugTrace,
- "ClassCheckMediaState: timer expired\n"));
- if (Info->MediaChangeDetectionDisableCount != 0) {
- DebugPrint((ClassDebugTrace,
- "ClassCheckMediaState: detection disabled\n"));
- LEAVE;
- }
- //
- // Prepare the IRP for the test unit ready
- //
- irp = ClasspPrepareMcnIrp(FdoExtension,
- Info,
- Info->Gesn.Supported);
- //
- // Issue the request.
- //
- DebugPrint((ClassDebugTrace,
- "ClasspSendMediaStateIrp: Device %p getting TUR "
- " irp %p\n", FdoExtension->DeviceObject, irp));
- if (irp == NULL) {
- LEAVE;
- }
- //
- // note: if we send it to the class dispatch routines, there is
- // a timing window here (since they grab the remove lock)
- // where we'd be removed. ELIMINATE the window by grabbing
- // the lock ourselves above and sending it to the lower
- // device object directly or to the device's StartIo
- // routine (which doesn't acquire the lock).
- //
-
- requestPending = TRUE;
- DBGTRACE(ClassDebugMCN, (" ClasspSendMediaStateIrp - calling IoCallDriver."));
- IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject, irp);
- }
- } FINALLY {
- if(requestPending == FALSE) {
- irpInUse = InterlockedCompareExchange(&Info->MediaChangeIrpInUse, 0, 1);
- #if _MSC_FULL_VER != 13009111 // This compiler always takes the wrong path here.
- ASSERT(irpInUse);
- #endif
- }
- }
- DBGTRACE(ClassDebugMCN, ("< ClasspSendMediaStateIrp"));
-
- return;
- } // end ClasspSendMediaStateIrp()
- /*++////////////////////////////////////////////////////////////////////////////
- ClassCheckMediaState()
- Routine Description:
- This routine is called by the class driver to test for a media change
- condition and/or poll for disk failure prediction. It should be called
- from the class driver's IO timer routine once per second.
- Arguments:
- FdoExtension - the device extension
- Return Value:
- none
- --*/
- VOID
- ClassCheckMediaState(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
- )
- {
- PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
- LONG countDown;
- if(info == NULL) {
- DebugPrint((ClassDebugTrace,
- "ClassCheckMediaState: detection not enabled\n"));
- return;
- }
- //
- // Media change support is active and the IRP is waiting. Decrement the
- // timer. There is no MP protection on the timer counter. This code
- // is the only code that will manipulate the timer counter and only one
- // instance of it should be running at any given time.
- //
- countDown = InterlockedDecrement(&(info->MediaChangeCountDown));
- //
- // Try to acquire the media change event. If we can't do it immediately
- // then bail out and assume the caller will try again later.
- //
- ClasspSendMediaStateIrp(FdoExtension,
- info,
- countDown);
- return;
- } // end ClassCheckMediaState()
- /*++////////////////////////////////////////////////////////////////////////////
- ClassResetMediaChangeTimer()
- Routine Description:
- Resets the media change count down timer to the default number of seconds.
-
- Arguments:
- FdoExtension - the device to reset the timer for
- Return Value:
- None
- --*/
- VOID
- ClassResetMediaChangeTimer(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
- )
- {
- PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo;
- if(info != NULL) {
- InterlockedExchange(&(info->MediaChangeCountDown),
- MEDIA_CHANGE_DEFAULT_TIME);
- }
- return;
- } // end ClassResetMediaChangeTimer()
- /*++////////////////////////////////////////////////////////////////////////////
- ClasspInitializePolling() - ISSUE-2000/02/20-henrygab - not documented
- Routine Description:
- This routine
- Arguments:
- DeviceObject -
- Irp -
- Return Value:
- --*/
- NTSTATUS
- ClasspInitializePolling(
- IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
- IN BOOLEAN AllowDriveToSleep
- )
- {
- PDEVICE_OBJECT fdo = FdoExtension->DeviceObject;
- PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
- ULONG size;
- PMEDIA_CHANGE_DETECTION_INFO info;
- PIRP irp;
- PAGED_CODE();
- if (FdoExtension->MediaChangeDetectionInfo != NULL) {
- return STATUS_SUCCESS;
- }
- info = ExAllocatePoolWithTag(NonPagedPool,
- sizeof(MEDIA_CHANGE_DETECTION_INFO),
- CLASS_TAG_MEDIA_CHANGE_DETECTION);
- if(info != NULL) {
- RtlZeroMemory(info, sizeof(MEDIA_CHANGE_DETECTION_INFO));
- FdoExtension->KernelModeMcnContext.FileObject = (PVOID)-1;
- FdoExtension->KernelModeMcnContext.DeviceObject = (PVOID)-1;
- FdoExtension->KernelModeMcnContext.LockCount = 0;
- FdoExtension->KernelModeMcnContext.McnDisableCount = 0;
- /*
- * Allocate an IRP to carry the Test-Unit-Ready.
- * Allocate an extra IRP stack location
- * so we can cache our device object in the top location.
- */
- irp = IoAllocateIrp((CCHAR)(fdo->StackSize+1), FALSE);
-
- if (irp != NULL) {
- PVOID buffer;
- buffer = ExAllocatePoolWithTag(
- NonPagedPoolCacheAligned,
- SENSE_BUFFER_SIZE,
- CLASS_TAG_MEDIA_CHANGE_DETECTION);
- if (buffer != NULL) {
- PIO_STACK_LOCATION irpStack;
- PSCSI_REQUEST_BLOCK srb;
- PCDB cdb;
- srb = &(info->MediaChangeSrb);
- info->MediaChangeIrp = irp;
- info->SenseBuffer = buffer;
- /*
- * For the driver that creates an IRP, there is no 'current' stack location.
- * Step down one IRP stack location so that the extra top one
- * becomes our 'current' one.
- */
- IoSetNextIrpStackLocation(irp);
- /*
- * Cache our device object in the extra top IRP stack location
- * so we have it in our completion routine.
- */
- irpStack = IoGetCurrentIrpStackLocation(irp);
- irpStack->DeviceObject = fdo;
- /*
- * Now start setting up the next IRP stack location for the call like any driver would.
- */
- irpStack = IoGetNextIrpStackLocation(irp);
- irpStack->Parameters.Scsi.Srb = srb;
- info->MediaChangeIrp = irp;
- //
- // Initialize the SRB
- //
- RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
- //
- // Initialize and set up the sense information buffer
- //
- RtlZeroMemory(buffer, SENSE_BUFFER_SIZE);
- srb->SenseInfoBuffer = buffer;
- srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
- //
- // Set default values for the media change notification
- // configuration.
- //
- info->MediaChangeCountDown = MEDIA_CHANGE_DEFAULT_TIME;
- info->MediaChangeDetectionDisableCount = 0;
- //
- // Assume that there is initially no media in the device
- // only notify upper layers if there is something there
- //
- info->MediaChangeDetectionState = MediaUnknown;
- info->MediaChangeIrpTimeInUse = 0;
- info->MediaChangeIrpLost = FALSE;
- //
- // setup all extra flags we'll be setting for this irp
- //
- info->SrbFlags = 0;
- if (AllowDriveToSleep) {
- SET_FLAG(info->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE);
- }
- SET_FLAG(info->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY);
- SET_FLAG(info->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
- SET_FLAG(info->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSF…
Large files files are truncated, but you can click here to view the full file