📄 autorun.c
字号:
/*
* Cache our device object in the extra top IRP stack location
* so we have it in our completion routine.
*/
irpStack = IoGetCurrentIrpStackLocation(irp);
irpStack->DeviceObject = FdoExtension->DeviceObject;
//
// 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->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 = Info->SenseBuffer;
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -