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

📄 cdrom.c

📁 The CD ROM driver is used with Classpnp.sys to provide access to CD ROMs and DVD ROMs. It supports P
💻 C
📖 第 1 页 / 共 5 页
字号:
        //

        TraceLog((CdromDebugWarning,
                  "CdRomDetermineRawReadCapabilities: Devices for newer "
                  "busses must support READ_CD command for FDO %p, Bus %x\n",
                  Fdo, fdoExtension->DeviceDescriptor->BusType));
        SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
        SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);

    }

    //
    // now clear all our READ_CD flags if the drive should have supported
    // it, but we are not sure it actually does.  we still won't query
    // the drive more than one time if it supports the command.
    //

    if (TEST_FLAG(cddata->HackFlags, CDROM_HACK_FORCE_READ_CD_DETECTION)) {

        TraceLog((CdromDebugWarning,
                  "Forcing detection of READ_CD for FDO %p because "
                  "testing showed some firmware did not properly support it\n",
                  Fdo));
        CLEAR_FLAG(cddata->XAFlags, XA_USE_READ_CD);

    }


    //
    // read our READ_CD support in the registry if it was seeded.
    //
    {
        ULONG readCdSupported = 0;

        ClassGetDeviceParameter(fdoExtension,
                                CDROM_SUBKEY_NAME,
                                CDROM_READ_CD_NAME,
                                &readCdSupported
                                );

        if (readCdSupported != 0) {

            TraceLog((CdromDebugWarning,
                      "Defaulting to READ_CD because previously detected "
                      "that the device supports it for Fdo %p.\n",
                      Fdo
                      ));
            SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);

        }

    }


    //
    // backwards-compatible attempt to determine if the drive
    // supports any method of reading digital audio from the disc.
    //
    // NOTE: Deprecate this; remove this check in longhorn and
    //       always use READ_CD.

    if (!TEST_FLAG(cddata->XAFlags, XA_USE_READ_CD)) {

        SCSI_REQUEST_BLOCK srb = {0};
        PCDB cdb;
        ULONG length;
        PUCHAR buffer = NULL;
        ULONG count;

        //
        // ISSUE-2000/07/05-henrygab - use the mode page to determine
        //          READ_CD support, then fall back on the below
        //          method, which may not always detect this ability
        //          on older (pre-1999) drives.
        //

        //
        // Build the MODE SENSE CDB. The data returned will be kept in the
        // device extension and used to set block size.
        //

        length = max(sizeof(ERROR_RECOVERY_DATA),sizeof(ERROR_RECOVERY_DATA10));

        buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
                                       length,
                                       CDROM_TAG_MODE_DATA);

        if (!buffer) {
            TraceLog((CdromDebugWarning,
                        "CdRomDetermineRawReadCapabilities: cannot allocate "
                        "buffer, so leaving for FDO %p\n", Fdo));
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto CdRomInitDeviceExit;
        }

        for (count = 0; count < 2; count++) {

            if (count == 0) {
                length = sizeof(ERROR_RECOVERY_DATA);
            } else {
                length = sizeof(ERROR_RECOVERY_DATA10);
            }

            RtlZeroMemory(buffer, length);
            RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
            cdb = (PCDB)srb.Cdb;

            srb.TimeOutValue = fdoExtension->TimeOutValue;

            if (count == 0) {
                srb.CdbLength = 6;
                cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
                cdb->MODE_SENSE.PageCode = 0x1;
                // note: not setting DBD in order to get the block descriptor!
                cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
            } else {
                srb.CdbLength = 10;
                cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
                cdb->MODE_SENSE10.PageCode = 0x1;
                // note: not setting DBD in order to get the block descriptor!
                cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
                cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
            }

            status = ClassSendSrbSynchronous(Fdo,
                                             &srb,
                                             buffer,
                                             length,
                                             FALSE);


            if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {

                //
                // STATUS_DATA_OVERRUN means it's a newer drive with more info
                // to tell us, so it's probably able to support READ_CD
                //

                RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);

                srb.CdbLength = 12;
                cdb->READ_CD.OperationCode = SCSIOP_READ_CD;

                status = ClassSendSrbSynchronous(Fdo,
                                                 &srb,
                                                 NULL,
                                                 0,
                                                 FALSE);

                if (NT_SUCCESS(status) ||
                    (status == STATUS_NO_MEDIA_IN_DEVICE) ||
                    (status == STATUS_NONEXISTENT_SECTOR) ||
                    (status == STATUS_UNRECOGNIZED_MEDIA)
                    ) {

                    //
                    // READ_CD works
                    //

                    TraceLog((CdromDebugWarning,
                              "CdRomDetermineRawReadCapabilities: Using "
                              "READ_CD for FDO %p due to status %x\n",
                              Fdo,
                              status));
                    SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);

                    //
                    // ignore errors in saving this info
                    //

                    ClassSetDeviceParameter(fdoExtension,
                                            CDROM_SUBKEY_NAME,
                                            CDROM_READ_CD_NAME,
                                            1
                                            );


                    break; // out of the for loop

                }

                TraceLog((CdromDebugWarning,
                            "CdRomDetermineRawReadCapabilities: Using "
                            "%s-byte mode switching for FDO %p due to status "
                            "%x returned for READ_CD\n",
                            ((count == 0) ? "6" : "10"), Fdo, status));

                if (count == 0) {
                    SET_FLAG(cddata->XAFlags, XA_USE_6_BYTE);
                    RtlCopyMemory(&cddata->Header,
                                  buffer,
                                  sizeof(ERROR_RECOVERY_DATA));
                    cddata->Header.ModeDataLength = 0;
                } else {
                    SET_FLAG(cddata->XAFlags, XA_USE_10_BYTE);
                    RtlCopyMemory(&cddata->Header10,
                                  buffer,
                                  sizeof(ERROR_RECOVERY_DATA10));
                    cddata->Header10.ModeDataLength[0] = 0;
                    cddata->Header10.ModeDataLength[1] = 0;
                }
                break;  // out of for loop

            }
            TraceLog((CdromDebugWarning,
                      "FDO %p failed %x byte mode sense, status %x\n",
                      Fdo,
                      ((count == 0) ? 6 : 10),
                      status
                      ));

            //
            // mode sense failed
            //

        } // end of for loop to try 6 and 10-byte mode sense

        if (count == 2) {

            //
            // nothing worked.  we probably cannot support digital
            // audio extraction from this drive
            //

            TraceLog((CdromDebugWarning,
                        "CdRomDetermineRawReadCapabilities: FDO %p "
                        "cannot support READ_CD\n", Fdo));
            CLEAR_FLAG(cddata->XAFlags, XA_PLEXTOR_CDDA);
            CLEAR_FLAG(cddata->XAFlags, XA_NEC_CDDA);
            SET_FLAG(cddata->XAFlags, XA_NOT_SUPPORTED);

        } // end of count == 2

        //
        // free our resources
        //

        ExFreePool(buffer);

        //
        // set a successful status
        // (in case someone later checks this)
        //

        status = STATUS_SUCCESS;

    }

    //
    // Register interfaces for this device.
    //

    {
        UNICODE_STRING interfaceName = {0};

        RtlInitUnicodeString(&interfaceName, NULL);

        status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
                                           (LPGUID) &CdRomClassGuid,
                                           NULL,
                                           &interfaceName);

        if(NT_SUCCESS(status)) {

            cddata->CdromInterfaceString = interfaceName;

            status = IoSetDeviceInterfaceState(
                        &interfaceName,
                        TRUE);

            if(!NT_SUCCESS(status)) {

                TraceLog((CdromDebugWarning,
                            "CdromInitDevice: Unable to register cdrom "
                            "DCA for fdo %p [%lx]\n",
                            Fdo, status));
            }
        }
    }

    return(STATUS_SUCCESS);

CdRomInitDeviceExit:

    CdRomDeAllocateMmcResources(Fdo);
    RtlZeroMemory(&(cddata->Mmc), sizeof(CDROM_MMC_EXTENSION));

    return status;

}


NTSTATUS
CdRomStartDevice(
    IN PDEVICE_OBJECT Fdo
    )
/*++

Routine Description:

    This routine starts the timer for the cdrom

Arguments:

    Fdo - a pointer to the functional device object for this device

Return Value:

    status

--*/

{
    PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
    PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
    PDVD_COPY_PROTECT_KEY copyProtectKey;
    PDVD_RPC_KEY rpcKey;
    IO_STATUS_BLOCK ioStatus = {0};
    ULONG bufferLen;

    //
    // if we have a DVD-ROM
    //    if we have a rpc0 device
    //        fake a rpc2 device
    //    if device does not have a dvd region set
    //        select a dvd region for the user
    //

    cddata->DvdRpc0Device = FALSE;

    //
    // since StartIo() will call IoStartNextPacket() on error, allowing
    // StartIo() to be non-recursive prevents stack overflow bugchecks in
    // severe error cases (such as fault-injection in the verifier).
    //
    // the only difference is that the thread context may be different
    // in StartIo() than in the caller of IoStartNextPacket().
    //

    IoSetStartIoAttributes(Fdo, TRUE, TRUE);

    //
    // check to see if we have a DVD device
    //

    if (CdRomGetDeviceType(Fdo) != FILE_DEVICE_DVD) {
        return STATUS_SUCCESS;
    }

    //
    // we got a DVD drive.
    // now, figure out if we have a RPC0 device
    //

    bufferLen = DVD_RPC_KEY_LENGTH;
    copyProtectKey =
        (PDVD_COPY_PROTECT_KEY)ExAllocatePoolWithTag(PagedPool,
                                                     bufferLen,
                                                     DVD_TAG_RPC2_CHECK);

    if (copyProtectKey == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // get the device region
    //
    RtlZeroMemory (copyProtectKey, bufferLen);
    copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
    copyProtectKey->KeyType = DvdGetRpcKey;

    //
    // Build a request for READ_KEY
    //
    ClassSendDeviceIoControlSynchronous(
        IOCTL_DVD_READ_KEY,
        Fdo,
        copyProtectKey,
        DVD_RPC_KEY_LENGTH,
        DVD_RPC_KEY_LENGTH,
        FALSE,
        &ioStatus
        );

    if (!NT_SUCCESS(ioStatus.Status)) {

        //
        // we have a rpc0 device
        //
        // NOTE: THIS MODIFIES THE BEHAVIOR OF THE IOCTL
        //

        cddata->DvdRpc0Device = TRUE;

        TraceLog((CdromDebugWarning,
                    "CdromStartDevice (%p): RPC Phase 1 drive detected\n",
                    Fdo));

        //
        // note: we could force this chosen now, but it's better to reduce
        // the number of code paths that could be taken.  always delay to
        // increase the percentage code coverage.
        //

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -