📄 autorun.c
字号:
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;
//
// 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_TRANSFER);
KeInitializeMutex(&info->MediaChangeMutex, 0x100);
//
// It is ok to support media change events on this
// device.
//
FdoExtension->MediaChangeDetectionInfo = info;
//
// NOTE: the DeviceType is FILE_DEVICE_CD_ROM even
// when the device supports DVD (no need to
// check for FILE_DEVICE_DVD, as it's not a
// valid check).
//
if (FdoExtension->DeviceObject->DeviceType == FILE_DEVICE_CD_ROM){
NTSTATUS status;
KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
"ClasspInitializePolling: Testing for GESN\n"));
status = ClasspInitializeGesn(FdoExtension, info);
if (NT_SUCCESS(status)) {
KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
"ClasspInitializePolling: GESN available "
"for %p\n", FdoExtension->DeviceObject));
ASSERT(info->Gesn.Supported );
ASSERT(info->Gesn.Buffer != NULL);
ASSERT(info->Gesn.BufferSize != 0);
ASSERT(info->Gesn.EventMask != 0);
// must return here, for ASSERTs to be valid.
return STATUS_SUCCESS;
}
KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
"ClasspInitializePolling: GESN *NOT* available "
"for %p\n", FdoExtension->DeviceObject));
}
ASSERT(info->Gesn.Supported == 0);
ASSERT(info->Gesn.Buffer == NULL);
ASSERT(info->Gesn.BufferSize == 0);
ASSERT(info->Gesn.EventMask == 0);
info->Gesn.Supported = 0; // just in case....
return STATUS_SUCCESS;
}
IoFreeIrp(irp);
}
ExFreePool(info);
}
//
// nothing to free here
//
return STATUS_INSUFFICIENT_RESOURCES;
} // end ClasspInitializePolling()
NTSTATUS
ClasspInitializeGesn(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
IN PMEDIA_CHANGE_DETECTION_INFO Info
)
{
PNOTIFICATION_EVENT_STATUS_HEADER header;
CLASS_DETECTION_STATE detectionState = ClassDetectionUnknown;
PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor;
NTSTATUS status = STATUS_NOT_SUPPORTED;
PIRP irp;
KEVENT event;
BOOLEAN retryImmediately;
ULONG i;
ULONG atapiResets;
PAGED_CODE();
ASSERT(Info == FdoExtension->MediaChangeDetectionInfo);
//
// read if we already know the abilities of the device
//
ClassGetDeviceParameter(FdoExtension,
CLASSP_REG_SUBKEY_NAME,
CLASSP_REG_MMC_DETECTION_VALUE_NAME,
(PULONG)&detectionState);
if (detectionState == ClassDetectionUnsupported) {
goto ExitWithError;
}
//
// check if the device has a hack flag saying never to try this.
//
if (TEST_FLAG(FdoExtension->PrivateFdoData->HackFlags,
FDO_HACK_GESN_IS_BAD)) {
ClassSetDeviceParameter(FdoExtension,
CLASSP_REG_SUBKEY_NAME,
CLASSP_REG_MMC_DETECTION_VALUE_NAME,
ClassDetectionUnsupported);
goto ExitWithError;
}
//
// else go through the process since we allocate buffers and
// get all sorts of device settings.
//
if (Info->Gesn.Buffer == NULL) {
Info->Gesn.Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
GESN_BUFFER_SIZE,
'??cS');
}
if (Info->Gesn.Buffer == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto ExitWithError;
}
if (Info->Gesn.Mdl != NULL) {
IoFreeMdl(Info->Gesn.Mdl);
}
Info->Gesn.Mdl = IoAllocateMdl(Info->Gesn.Buffer,
GESN_BUFFER_SIZE,
FALSE, FALSE, NULL);
if (Info->Gesn.Mdl == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto ExitWithError;
}
MmBuildMdlForNonPagedPool(Info->Gesn.Mdl);
Info->Gesn.BufferSize = GESN_BUFFER_SIZE;
Info->Gesn.EventMask = 0;
//
// all items are prepared to use GESN (except the event mask, so don't
// optimize this part out!).
//
// now see if it really works. we have to loop through this because
// many SAMSUNG (and one COMPAQ) drives timeout when requesting
// NOT_READY events, even when the IMMEDIATE bit is set. :(
//
// using a drive list is cumbersome, so this might fix the problem.
//
adapterDescriptor = FdoExtension->AdapterDescriptor;
atapiResets = 0;
retryImmediately = TRUE;
for (i = 0; i < 16 && retryImmediately == TRUE; i++) {
irp = ClasspPrepareMcnIrp(FdoExtension, Info, TRUE);
if (irp == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto ExitWithError;
}
ASSERT(TEST_FLAG(Info->MediaChangeSrb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE));
//
// replace the completion routine with a different one this time...
//
IoSetCompletionRoutine(irp,
ClassSignalCompletion,
&event,
TRUE, TRUE, TRUE);
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
status = IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject, irp);
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE,
NULL);
ASSERT(NT_SUCCESS(status));
}
ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
if (SRB_STATUS(Info->MediaChangeSrb.SrbStatus) != SRB_STATUS_SUCCESS) {
ClassInterpretSenseInfo(FdoExtension->DeviceObject,
&(Info->MediaChangeSrb),
IRP_MJ_SCSI,
0,
0,
&status,
NULL);
}
if ((adapterDescriptor->BusType == BusTypeAtapi) &&
(Info->MediaChangeSrb.SrbStatus == SRB_STATUS_BUS_RESET)
) {
//
// ATAPI unfortunately returns SRB_STATUS_BUS_RESET instead
// of SRB_STATUS_TIMEOUT, so we cannot differentiate between
// the two. if we get this status four time consecutively,
// stop trying this command. it is too late to change ATAPI
// at this point, so special-case this here. (07/10/2001)
// NOTE: any value more than 4 may cause the device to be
// marked missing.
//
atapiResets++;
if (atapiResets >= 4) {
status = STATUS_IO_DEVICE_ERROR;
goto ExitWithError;
}
}
if (status == STATUS_DATA_OVERRUN) {
status = STATUS_SUCCESS;
}
if ((status == STATUS_INVALID_DEVICE_REQUEST) ||
(status == STATUS_TIMEOUT) ||
(status == STATUS_IO_DEVICE_ERROR) ||
(status == STATUS_IO_TIMEOUT)
) {
//
// with these error codes, we don't ever want to try this command
// again on this device, since it reacts poorly.
//
ClassSetDeviceParameter(FdoExtension,
CLASSP_REG_SUBKEY_NAME,
CLASSP_REG_MMC_DETECTION_VALUE_NAME,
ClassDetectionUnsupported);
KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugWarning,
"Classpnp => GESN test failed %x for fdo %p\n",
status, FdoExtension->DeviceObject));
goto ExitWithError;
}
if (!NT_SUCCESS(status)) {
//
// this may be other errors that should not disable GESN
// for all future start_device calls.
//
KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugWarning,
"Classpnp => GESN test failed %x for fdo %p\n",
status, FdoExtension->DeviceObject));
goto ExitWithError;
}
if (i == 0) {
//
// the first time, the request was just retrieving a mask of
// available bits. use this to mask future requests.
//
header = (PNOTIFICATION_EVENT_STATUS_HEADER)(Info->Gesn.Buffer);
KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
"Classpnp => Fdo %p supports event mask %x\n",
FdoExtension->DeviceObject, header->SupportedEventClasses));
if (TEST_FLAG(header->SupportedEventClasses,
NOTIFICATION_MEDIA_STATUS_CLASS_MASK)) {
KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
"Classpnp => GESN supports MCN\n"));
}
if (TEST_FLAG(header->SupportedEventClasses,
NOTIFICATION_DEVICE_BUSY_CLASS_MASK)) {
KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
"Classpnp => GESN supports DeviceBusy\n"));
}
if (TEST_FLAG(header->SupportedEventClasses,
NOTIFICATION_OPERATIONAL_CHANGE_CLASS_MASK)) {
KdPrintEx((DPFLTR_CLASSPNP_ID, ClassDebugMCN,
"Classpnp => GESN supports OpChange\n"));
}
Info->Gesn.EventMask = header->SupportedEventClasses;
//
// realistically, we are only considering the following events:
// EXTERNAL REQUEST - this is being tested for play/stop/etc.
// MEDIA STATUS - autorun and ejection requests.
// DEVICE BUSY - to allow us to predict when media will be ready.
// therefore, we should not bother querying for the other,
// unknown events. clear all but the above flags.
//
Info->Gesn.EventMask &=
NOTIFICATION_OPERATIONAL_CHANGE_CLASS_MASK |
NOTIFICATION_EXTERNAL_REQUEST_CLASS_MASK |
NOTIFICATION_MEDIA
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -