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

📄 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,
                  "CdromStartDevice (%p): Delay DVD Region Selection\n",
                  Fdo));

        cddata->Rpc0SystemRegion           = 0xff;
        cddata->Rpc0SystemRegionResetCount = DVD_MAX_REGION_RESET_COUNT;
        cddata->PickDvdRegion              = 1;
        cddata->Rpc0RetryRegistryCallback  = 1;
        ExFreePool(copyProtectKey);
        return STATUS_SUCCESS;

    } else {

        rpcKey = (PDVD_RPC_KEY) copyProtectKey->KeyData;

        //
        // TypeCode of zero means that no region has been set.
        //

        if (rpcKey->TypeCode == 0) {
            TraceLog((CdromDebugWarning,
                        "CdromStartDevice (%p): must choose DVD region\n",
                        Fdo));
            cddata->PickDvdRegion = 1;
            CdRomPickDvdRegion(Fdo);
        }
    }

    ExFreePool (copyProtectKey);

    return STATUS_SUCCESS;
}


NTSTATUS
CdRomStopDevice(
    IN PDEVICE_OBJECT DeviceObject,
    IN UCHAR Type
    )
{
    return STATUS_SUCCESS;
}


VOID
CdRomStartIo(
    IN PDEVICE_OBJECT Fdo,
    IN PIRP Irp
    )
{

    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
    PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->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;
    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;
    KIRQL oldIrql;

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

    IoMarkIrpPending(Irp);

    cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData);
    use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);

    //
    // If this is a write request and writes are currently
    // not allowed then set the mmc state to update required.
    //

    if ((cdData->Mmc.WriteAllowed == FALSE) &&
        ((currentIrpStack->MajorFunction == IRP_MJ_WRITE) ||
         ((currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) &&
          ((currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_IS_WRITABLE) ||
           (currentIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_VERIFY))))) {

        //
        // The MMC update function queues and retries the requests in
        // CdRompFlushDelayedList. The request will be retried in infinite loop
        // if the write state is not changed. Set Argument3 to indicate that this
        // request is triggering MMC update. When the IRP is retried, do not
        // trigger update. This will let the request fall thru and appropriate
        // action will be taken by the request handler.
        //

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

            nextIrpStack->Parameters.Others.Argument3 =  (PVOID) 1;
            InterlockedCompareExchange(&(cdData->Mmc.UpdateState),
                                   CdromMmcUpdateRequired,
                                   CdromMmcUpdateComplete);

            KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                       "CdRomStartIo: Received request that requires write access [%p]. Update MMC capabilities.\n",
                       Irp));
        } else {

            nextIrpStack->Parameters.Others.Argument3 =  (PVOID) 0;
        }
    }

    //
    // if this test is true, then we will exit the routine within this
    // code block, queueing the irp for later completion.
    //

    if ((cdData->Mmc.IsMmc) &&
        (cdData->Mmc.UpdateState != CdromMmcUpdateComplete)
        ) {

        ULONG queueDepth;
        KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                   "CdRomStartIo: [%p] Device needs to update capabilities\n",
                   Irp));
        ASSERT(cdData->Mmc.IsMmc);
        ASSERT(cdData->Mmc.CapabilitiesIrp != NULL);
        ASSERT(cdData->Mmc.CapabilitiesIrp != Irp);

        //
        // NOTE - REF #0002
        //
        // the state was either UpdateRequired (which means we will
        // have to start the work item) or UpdateStarted (which means
        // we have already started the work item at least once -- may
        // transparently change to UpdateComplete).
        //
        // if it's update required, we just queue it, change to UpdateStarted,
        // start the workitem, and start the next packet.
        //
        // else, we must queue the item and check the queue depth.  if the
        // queue depth is equal to 1, that means the worker item from the
        // previous attempt has already de-queued the items, so we should
        // call this routine again (retry) as an optimization rather than
        // re-add it this irp to the queue.  since this is tail recursion,
        // it won't take much/any stack to do this.
        //
        // NOTE: This presumes the following items are true:
        //
        // we only add to the list from CdRomStartIo(), which is serialized.
        // we only set to UpdateStarted from CdRomStartIo(), and only if
        //    the state was UpdateRequired.
        // we only set to UpdateRequired from CdRomMmcErrorHandler(), and
        //    only if the state was UpdateComplete.
        // we only set to UpdateComplete from the workitem, and assert the
        //    state was UpdateStarted.
        // we flush the entire queue in one atomic operation in the workitem,
        //    except in the special case described above when we dequeue
        //    the request immediately.
        //
        // order of operations is vitally important: queue, then test the depth
        // this will prevent lost irps.
        //

        KeAcquireSpinLock(&cdData->Mmc.DelayedIrpsLock, &oldIrql);
        InsertTailList(&cdData->Mmc.DelayedIrpsList, &Irp->Tail.Overlay.ListEntry);
        queueDepth = ++cdData->Mmc.NumDelayedIrps;
        KeReleaseSpinLock(&cdData->Mmc.DelayedIrpsLock, oldIrql);

        if (queueDepth == 1) {

            if (cdData->Mmc.UpdateState == CdromMmcUpdateRequired) {
                LONG oldState;

                //
                // should free any old partition list info that
                // we've previously saved away and then start the WorkItem
                //

                oldState = InterlockedExchange(&cdData->Mmc.UpdateState,
                                               CdromMmcUpdateStarted);
                ASSERT(oldState == CdromMmcUpdateRequired);

                IoQueueWorkItem(cdData->Mmc.CapabilitiesWorkItem,
                                CdRomUpdateMmcDriveCapabilities,
                                DelayedWorkQueue,
                                NULL);

            } else {

                //
                // they *just* finished updating, so we should flush the list
                // back onto the StartIo queue and start the next packet.
                //

                CdRompFlushDelayedList(Fdo, &(cdData->Mmc), STATUS_SUCCESS, FALSE);

            }

        }

        //
        // start the next packet so we don't deadlock....
        //

        IoStartNextPacket(Fdo, FALSE);
        return;

    }

    //
    // If the flag is set in the device object
    // force a verify for READ, WRITE and RAW_READ requests
    // Note that ioctls are passed through....
    //

    if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME) &&
        IS_READ_WRITE_REQUEST(currentIrpStack)) {

        TraceLog((CdromDebugTrace,
                    "CdRomStartIo: [%p] Volume needs verified\n", Irp));

        if (!(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {

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

            Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;

            TraceLog((CdromDebugTrace,
                        "CdRomStartIo: [%p] Calling UpdateCapcity - "
                        "ioctl event = %p\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(fdoExtension,
                                         Irp,
                                         nextIrpStack->Parameters.Others.Argument1
                                         );

            TraceLog((CdromDebugTrace,
                        "CdRomStartIo: [%p] UpdateCapacity returned %lx\n",
                        Irp, status));
            return;
        }
    }

    //
    // fail writes if they are not allowed...
    //

    if ((currentIrpStack->MajorFunction == IRP_MJ_WRITE) &&
        !(cdData->Mmc.WriteAllowed)) {

        TraceLog((CdromDebugError,
                    "CdRomStartIo: [%p] Device %p failing write request\n",
                    Irp, Fdo));

        Irp->IoStatus.Information = 0;
        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
        BAIL_OUT(Irp);
        CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
        return;
    }

    if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
        currentIrpStack->MajorFunction == IRP_MJ_WRITE ) {

        ULONG maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;

        //
        // Add partition byte offset to make starting byte relative to
        // beginning of disk.
        //

        currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
            (fdoExtension->CommonExtension.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) {

            //
            // a writable device must be MMC compliant, which supports
            // READ_CD commands.
            //

            ASSERT(currentIrpStack->MajorFunction != IRP_MJ_WRITE);

            ASSERT(!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD));

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

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

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

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

            irpStack = IoGetNextIrpStackLocation(irp2);

⌨️ 快捷键说明

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