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

📄 cdrom.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
                                             buffer,
                                             length,
                                             FALSE);
        if (status == STATUS_DATA_OVERRUN) {

            //
            // Build and issue the ReadCd command to ensure that this device supports it.
            //

            RtlZeroMemory(cdb, 12);

            cdb->READ_CD.OperationCode = SCSIOP_READ_CD;

            status = ScsiClassSendSrbSynchronous(deviceObject,
                                                 &srb,
                                                 NULL,
                                                 0,
                                                 FALSE);

            //
            // If the command wasn't rejected then support the READ_CD.
            //

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

                //
                // Using Read CD precludes issueing a mode select to
                // set the user data size. So, no buffer copy is
                // necessary.
                //

                cddata->XAFlags &= ~XA_USE_6_BYTE;
                cddata->XAFlags = XA_USE_READ_CD | XA_USE_10_BYTE;
            } else {

                RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
                cddata->u1.Header.ModeDataLength = 0;

                cddata->XAFlags &= ~XA_USE_6_BYTE;
                cddata->XAFlags |= XA_USE_10_BYTE;
            }

        } else if (NT_SUCCESS(status)) {

            RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA10));
            cddata->u1.Header.ModeDataLength = 0;

            cddata->XAFlags &= ~XA_USE_6_BYTE;
            cddata->XAFlags |= XA_USE_10_BYTE;

        } else {
            cddata->XAFlags |= XA_NOT_SUPPORTED;
        }
    } else {
        RtlCopyMemory(&cddata->u1.Header, buffer, sizeof(ERROR_RECOVERY_DATA));
        cddata->u1.Header.ModeDataLength = 0;
    }

    ExFreePool(buffer);

    //
    // Start the timer now regardless of if Autorun is enabled.
    // The timer must run forever since IoStopTimer faults.
    //

    IoInitializeTimer(deviceObject, CdRomTickHandler, NULL);
    IoStartTimer(deviceObject);

    return(STATUS_SUCCESS);

CreateCdRomDeviceObjectExit:

    //
    // Release the device since an error occured.
    //

    ScsiClassClaimDevice(PortDeviceObject,
                         LunInfo,
                         TRUE,
                         NULL);

    if (senseData != NULL) {
        ExFreePool(senseData);
    }

    if (deviceExtension->DiskGeometry != NULL) {
        ExFreePool(deviceExtension->DiskGeometry);
    }

    if (deviceObject != NULL) {
        if (srbListInitialized) {
            ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
        }
        IoDeleteDevice(deviceObject);
    }


    return status;

} // end CreateCdRomDeviceObject()


VOID
STDCALL
ScsiCdRomStartIo(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{

    PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
    PIO_STACK_LOCATION  nextIrpStack = IoGetNextIrpStackLocation(Irp);
    PIO_STACK_LOCATION  irpStack;
    PIRP                irp2 = NULL;
    ULONG               transferPages;
    ULONG               transferByteCount = currentIrpStack->Parameters.Read.Length;
    ULONG               maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
    LARGE_INTEGER       startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
    PCDROM_DATA         cdData;
    PSCSI_REQUEST_BLOCK srb = NULL;
    PCDB                cdb;
    PUCHAR              senseBuffer = NULL;
    PVOID               dataBuffer;
    NTSTATUS            status;
    BOOLEAN             use6Byte;

    //
    // Mark IRP with status pending.
    //

    IoMarkIrpPending(Irp);

    //
    // If the flag is set in the device object, force a verify.
    //

    if (DeviceObject->Flags & DO_VERIFY_VOLUME) {
        DebugPrint((2, "ScsiCdRomStartIo: [%lx] Volume needs verified\n", Irp));
        if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {

            if (Irp->Tail.Overlay.Thread) {
                IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
            }

            Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;

            DebugPrint((2, "ScsiCdRomStartIo: [%lx] Calling UpdateCapcity - "
                           "ioctl event = %lx\n",
                        Irp,
                        nextIrpStack->Parameters.Others.Argument1
                      ));

            //
            // our device control dispatch routine stores an event in the next
            // stack location to signal when startio has completed.  We need to
            // pass this in so that the update capacity completion routine can
            // set it rather than completing the Irp.
            //

            status = CdRomUpdateCapacity(deviceExtension,
                                         Irp,
                                         nextIrpStack->Parameters.Others.Argument1
                                         );

            DebugPrint((2, "ScsiCdRomStartIo: [%lx] UpdateCapacity returned %lx\n", Irp, status));
            ASSERT(status == STATUS_PENDING);
            return;
        }
    }

    cdData = (PCDROM_DATA)(deviceExtension + 1);
    use6Byte = cdData->XAFlags & XA_USE_6_BYTE;

    if (currentIrpStack->MajorFunction == IRP_MJ_READ) {

        //
        // Add partition byte offset to make starting byte relative to
        // beginning of disk. In addition, add in skew for DM Driver, if any.
        //

        currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart);

        //
        // Calculate number of pages in this transfer.
        //

        transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
                                                       currentIrpStack->Parameters.Read.Length);

        //
        // Check if request length is greater than the maximum number of
        // bytes that the hardware can transfer.
        //

        if (cdData->RawAccess) {

            ASSERT(!(cdData->XAFlags & XA_USE_READ_CD));

            //
            // Fire off a mode select to switch back to cooked sectors.
            //

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

            if (!irp2) {
                Irp->IoStatus.Information = 0;
                Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                IoCompleteRequest(Irp, IO_DISK_INCREMENT);
                IoStartNextPacket(DeviceObject, FALSE);
                return;
            }

            srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
            if (!srb) {
                Irp->IoStatus.Information = 0;
                Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                IoCompleteRequest(Irp, IO_DISK_INCREMENT);
                IoFreeIrp(irp2);
                IoStartNextPacket(DeviceObject, FALSE);
                return;
            }

            RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));

            cdb = (PCDB)srb->Cdb;

            //
            // Allocate sense buffer.
            //

            senseBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);

            if (!senseBuffer) {
                Irp->IoStatus.Information = 0;
                Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                IoCompleteRequest(Irp, IO_DISK_INCREMENT);
                ExFreePool(srb);
                IoFreeIrp(irp2);
                IoStartNextPacket(DeviceObject, FALSE);
                return;
            }

            //
            // 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 = deviceExtension->DeviceObject;
            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;
            }

            //
            // 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;

            srb->Length = SCSI_REQUEST_BLOCK_SIZE;
            srb->PathId = deviceExtension->PathId;
            srb->TargetId = deviceExtension->TargetId;
            srb->Lun = deviceExtension->Lun;
            srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
            srb->Cdb[1] |= deviceExtension->Lun << 5;
            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 = ExAllocatePool(NonPagedPoolCacheAligned, transferByteCount );
            if (!dataBuffer) {
                Irp->IoStatus.Information = 0;
                Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                IoCompleteRequest(Irp, IO_DISK_INCREMENT);
                ExFreePool(senseBuffer);
                ExFreePool(srb);
                IoFreeIrp(irp2);
                IoStartNextPacket(DeviceObject, FALSE);
                return;

            }

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

            if (!irp2->MdlAddress) {
                Irp->IoStatus.Information = 0;
                Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
                IoCompleteRequest(Irp, IO_DISK_INCREMENT);
                ExFreePool(senseBuffer);
                ExFreePool(srb);
                ExFreePool(dataBuffer);
                IoFreeIrp(irp2);
                IoStartNextPacket(DeviceObject, FALSE);
                return;
            }

            //
            // Prepare the MDL
            //

            MmBuildMdlForNonPagedPool(irp2->MdlAddress);

            srb->DataBuffer = dataBuffer;

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

            cdData->u1.BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
            cdData->u1.BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >>  8) & 0xFF;
            cdData->u1.BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);

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

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

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

            srb->SrbFlags = deviceExtension->SrbFlags;
            srb->SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_OUT);
            srb->DataTransferLength = transferByteCount;
            srb->TimeOutValue = deviceExtension->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(deviceExtension->PortDeviceObject, irp2);
            return;
        }

        if ((currentIrpStack->Parameters.Read.Length > maximumTransferLength) ||
            (transferPages >
                deviceExtension->PortCapabilities->MaximumPhysicalPages)) {

            //
            // 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 =
                deviceExtension->PortCapabilities->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;
            }

            ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
            return;

        } else {

            //

⌨️ 快捷键说明

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