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

📄 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 页
字号:
            irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
            irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
            irpStack->Parameters.Scsi.Srb = srb;

            srb->Length = SCSI_REQUEST_BLOCK_SIZE;
            srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
            srb->SrbStatus = srb->ScsiStatus = 0;
            srb->NextSrb = 0;
            srb->OriginalRequest = irp2;
            srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
            srb->SenseInfoBuffer = senseBuffer;

            transferByteCount = (use6Byte) ? sizeof(ERROR_RECOVERY_DATA) : sizeof(ERROR_RECOVERY_DATA10);

            dataBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
                                               transferByteCount,
                                               CDROM_TAG_RAW);

            if (!dataBuffer) {
                ExFreePool(senseBuffer);
                ExFreePool(srb);
                IoFreeIrp(irp2);
                Irp->IoStatus.Information = 0;
                Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

                BAIL_OUT(Irp);
                CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
                return;
            }

            /*
             *  Zero out input buffer in case the device returns fewer bytes than advertized,
             *  which would cause us to return uninitialized kernel memory.
             */
            RtlZeroMemory(dataBuffer, transferByteCount);

            irp2->MdlAddress = IoAllocateMdl(dataBuffer,
                                            transferByteCount,
                                            FALSE,
                                            FALSE,
                                            (PIRP) NULL);

            if (!irp2->MdlAddress) {
                ExFreePool(senseBuffer);
                ExFreePool(srb);
                ExFreePool(dataBuffer);
                IoFreeIrp(irp2);
                Irp->IoStatus.Information = 0;
                Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

                BAIL_OUT(Irp);
                CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
                return;
            }

            //
            // Prepare the MDL
            //

            MmBuildMdlForNonPagedPool(irp2->MdlAddress);

            srb->DataBuffer = dataBuffer;

            //
            // Set the new block size in the descriptor.
            //

            if (use6Byte) {
                cdData->BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
                cdData->BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >>  8) & 0xFF;
                cdData->BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
            } else {
                cdData->BlockDescriptor10.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
                cdData->BlockDescriptor10.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >>  8) & 0xFF;
                cdData->BlockDescriptor10.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
            }

            //
            // Move error page into dataBuffer.
            //

            RtlCopyMemory(srb->DataBuffer, &cdData->Header, transferByteCount);

            //
            // Build and send a mode select to switch into raw mode.
            //

            srb->SrbFlags = fdoExtension->SrbFlags;
            SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
            SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
            srb->DataTransferLength = transferByteCount;
            srb->TimeOutValue = fdoExtension->TimeOutValue * 2;

            if (use6Byte) {
                srb->CdbLength = 6;
                cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
                cdb->MODE_SELECT.PFBit = 1;
                cdb->MODE_SELECT.ParameterListLength = (UCHAR)transferByteCount;
            } else {
                srb->CdbLength = 10;
                cdb->MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
                cdb->MODE_SELECT10.PFBit = 1;
                cdb->MODE_SELECT10.ParameterListLength[0] = (UCHAR)(transferByteCount >> 8);
                cdb->MODE_SELECT10.ParameterListLength[1] = (UCHAR)(transferByteCount & 0xFF);
            }

            //
            // Update completion routine.
            //

            IoSetCompletionRoutine(irp2,
                                   CdRomSwitchModeCompletion,
                                   srb,
                                   TRUE,
                                   TRUE,
                                   TRUE);

            IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
            return;
        }


        //
        // Request needs to be split. Completion of each portion of the
        // request will fire off the next portion. The final request will
        // signal Io to send a new request.
        //

        transferPages =
            fdoExtension->AdapterDescriptor->MaximumPhysicalPages - 1;

        if(maximumTransferLength > (transferPages << PAGE_SHIFT)) {
            maximumTransferLength = transferPages << PAGE_SHIFT;
        }

        //
        // Check that the maximum transfer size is not zero
        //

        if(maximumTransferLength == 0) {
            maximumTransferLength = PAGE_SIZE;
        }

        ClassSplitRequest(Fdo, Irp, maximumTransferLength);
        return;

    } else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {

        //
        // Allocate an irp, srb and associated structures.
        //

        irp2 = IoAllocateIrp((CCHAR)(Fdo->StackSize+1),
                              FALSE);

        if (!irp2) {
            Irp->IoStatus.Information = 0;
            Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

            BAIL_OUT(Irp);
            CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
            return;
        }

        srb = ExAllocatePoolWithTag(NonPagedPool,
                                    sizeof(SCSI_REQUEST_BLOCK),
                                    CDROM_TAG_SRB);
        if (!srb) {
            IoFreeIrp(irp2);
            Irp->IoStatus.Information = 0;
            Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

            BAIL_OUT(Irp);
            CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
            return;
        }

        RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));

        cdb = (PCDB)srb->Cdb;

        //
        // Allocate sense buffer.
        //

        senseBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
                                            SENSE_BUFFER_SIZE,
                                            CDROM_TAG_SENSE_INFO);

        if (!senseBuffer) {
            ExFreePool(srb);
            IoFreeIrp(irp2);
            Irp->IoStatus.Information = 0;
            Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;

            BAIL_OUT(Irp);
            CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
            return;
        }

        RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);

        //
        // Set up the irp.
        //

        IoSetNextIrpStackLocation(irp2);
        irp2->IoStatus.Status = STATUS_SUCCESS;
        irp2->IoStatus.Information = 0;
        irp2->Flags = 0;
        irp2->UserBuffer = NULL;

        //
        // Save the device object and irp in a private stack location.
        //

        irpStack = IoGetCurrentIrpStackLocation(irp2);
        irpStack->DeviceObject = Fdo;
        irpStack->Parameters.Others.Argument2 = (PVOID) Irp;

        //
        // The retry count will be in the real Irp, as the retry logic will
        // recreate our private irp.
        //

        if (!(nextIrpStack->Parameters.Others.Argument1)) {

            //
            // Only jam this in if it doesn't exist. The completion routines can
            // call StartIo directly in the case of retries and resetting it will
            // cause infinite loops.
            //

            nextIrpStack->Parameters.Others.Argument1 = (PVOID) MAXIMUM_RETRIES;
        }

        //
        // keep track of the new irp as Argument3
        //

        nextIrpStack->Parameters.Others.Argument3 = irp2;


        //
        // Construct the IRP stack for the lower level driver.
        //

        irpStack = IoGetNextIrpStackLocation(irp2);
        irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
        irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
        irpStack->Parameters.Scsi.Srb = srb;

        IoSetCompletionRoutine(irp2,
                               CdRomDeviceControlCompletion,
                               srb,
                               TRUE,
                               TRUE,
                               TRUE);
        //
        // Setup those fields that are generic to all requests.
        //

        srb->Length = SCSI_REQUEST_BLOCK_SIZE;
        srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
        srb->SrbStatus = srb->ScsiStatus = 0;
        srb->NextSrb = 0;
        srb->OriginalRequest = irp2;
        srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
        srb->SenseInfoBuffer = senseBuffer;

        if ((currentIrpStack->Parameters.DeviceIoControl.IoControlCode & 3) == METHOD_BUFFERED){
            /*
             *  The kernel allocated the output buffer for us and did not initialize it.
             *  We may not return the entire read length, so zero out the return buffer in order to avoid
             *  returning part of an uninitialized kernel buffer.
             */
            if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength > currentIrpStack->Parameters.DeviceIoControl.InputBufferLength){
                RtlZeroMemory((PUCHAR)Irp->AssociatedIrp.SystemBuffer+currentIrpStack->Parameters.DeviceIoControl.InputBufferLength,
                                        currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength-currentIrpStack->Parameters.DeviceIoControl.InputBufferLength);
            }
        }


        switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {


        case IOCTL_CDROM_RAW_READ: {
            //
            // Determine whether the drive is currently in raw or cooked mode,
            // and which command to use to read the data.
            //
            RAW_READ_INFO rawReadInfo;
            PVOID outputVirtAddr = NULL;

            /*
             *  Since this ioctl is METHOD_OUT_DIRECT, we need to copy away the input buffer before interpreting it.
             *  This prevents a malicious app from messing with the input buffer while we are interpreting it.
             */
            rawReadInfo = *(PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;

            if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength){
                /*
                 *  Make sure that any user buffer that we pass down to the hardware is properly aligned
                 */
                ASSERT(Irp->MdlAddress);
                outputVirtAddr = MmGetMdlVirtualAddress(Irp->MdlAddress);
                if ((ULONG_PTR)outputVirtAddr & fdoExtension->AdapterDescriptor->AlignmentMask){
                    ASSERT(!((ULONG_PTR)outputVirtAddr & fdoExtension->AdapterDescriptor->AlignmentMask));
                    ExFreePool(senseBuffer);
                    ExFreePool(srb);
                    IoFreeIrp(irp2);
                    Irp->IoStatus.Information = 0;
                    Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
                    BAIL_OUT(Irp);
                    CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
                    return;
                }
            }

            if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
                ULONG          maximumTransferLength;

                if (cdData->RawAccess) {
                    ULONG rawTransferPages;

                    ULONG  startingSector;
                    UCHAR  min, sec, frame;

                    //
                    // Free the recently allocated irp, as we don't need it.
                    //

                    IoFreeIrp(irp2);

                    cdb = (PCDB)srb->Cdb;
                    RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);

                    //
                    // Calculate starting offset.
                    //

                    startingSector = (ULONG)(rawReadInfo.DiskOffset.QuadPart >> fdoExtension->SectorShift);
                    transferByteCount  = rawReadInfo.SectorCount * RAW_SECTOR_SIZE;
                    maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
                    rawTransferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(outputVirtAddr, transferByteCount);

                    //
                    // Determine if request is within limits imposed by miniport.
                    //
                    if (transferByteCount > maximumTransferLength ||
                        rawTransferPages > fdoExtension->AdapterDescriptor->MaximumPhysicalPages) {

                        //
                        // The claim is that this won't happen, and is backed up by
                        // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
                        // we get only 4 sector requests.
                        //

                        ExFreePool(senseBuffer);
                        ExFreePool(srb);

                        Irp->IoStatus.Information = 0;
                        Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;

                        BAIL_OUT(Irp);
                        CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
                        return;

                    }

                    srb->OriginalRequest = Irp;
                    srb->SrbFlags = fdoExtension->SrbFlags;
                    SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
                    SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
                    srb->DataTransferLength = transferByteCount;
                    srb->TimeOutValue = fdoExtension->TimeOutValue;
                    srb->CdbLength = 10;
                    srb->DataBuffer = outputVirtAddr;

                    if (rawReadInfo.TrackMode == CDDA) {
                        if (TEST_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA)) {

                            srb->CdbLength = 12;

                            cdb->PLXTR_READ_CDDA.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
                            cdb->PLXTR_READ_CDDA.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
                            cdb->PLXTR_READ_CDDA.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
                            cdb->PLXTR_READ_CDDA.LogicalBlockByte0  = (UCHAR) ((startingSector >> 24) & 0xFF);

                            cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo.SectorCount & 0xFF);
                            cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo.SectorCount >> 8);
                            cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
                            cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;

                            cdb->PLXTR_READ_CDDA.SubCode = 0;
                            cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;

                        } else if (TEST_FLAG(cdData->XAFlags, XA_NEC_CDDA)) {

                            cdb->NEC_READ_CDDA.LogicalBlockByte3  = (UCHAR) (startingSector & 0xFF);
                            cdb->NEC_READ_CDDA.LogicalBlockByte2  = (UCHAR) ((startingSector >>  8) & 0xFF);
                            cdb->NEC_READ_CDDA.LogicalBlockByte1  = (UCHAR) ((startingSector >> 16) & 0xFF);
                            cdb->NEC_READ_CDDA.LogicalBlo

⌨️ 快捷键说明

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