⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 autorun.c

📁 This is the library for all storage drivers. It simplifies writing a storage driver by implementing
💻 C
📖 第 1 页 / 共 5 页
字号:
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 + -