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

📄 mmc.c

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

    nextStack = IoGetNextIrpStackLocation(irp);
    nextStack->MajorFunction = IRP_MJ_SCSI;
    nextStack->Parameters.Scsi.Srb = srb;
    irp->MdlAddress = mmcData->CapabilitiesMdl;
    irp->AssociatedIrp.SystemBuffer = mmcData->CapabilitiesBuffer;
    IoSetCompletionRoutine(irp, CdRomUpdateMmcDriveCapabilitiesCompletion, Fdo,
                           TRUE, TRUE, TRUE);

    return;

}

VOID
CdRomUpdateMmcDriveCapabilities(
    IN PDEVICE_OBJECT Fdo,
    IN PVOID Context
    )
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
    PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
    PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
    PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
    PIO_STACK_LOCATION thisStack = IoGetCurrentIrpStackLocation(mmcData->CapabilitiesIrp);
    PSCSI_REQUEST_BLOCK srb = &(mmcData->CapabilitiesSrb);
    NTSTATUS status;


    ASSERT(Context == NULL);

    //
    // NOTE: a remove lock is unneccessary, since the delayed irp
    // will have said lock held for itself, preventing a remove.
    //
    CdRomPrepareUpdateCapabilitiesIrp(Fdo);
    
    ASSERT(thisStack->Parameters.Others.Argument1 == Fdo);
    ASSERT(thisStack->Parameters.Others.Argument2 == mmcData->CapabilitiesBuffer);
    ASSERT(thisStack->Parameters.Others.Argument3 == &(mmcData->CapabilitiesSrb));
    
    mmcData->WriteAllowed = FALSE; // default to read-only

    //
    // set max retries, and also allow volume verify override based on
    // original (delayed) irp
    //
    
    thisStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;

    //
    // send to self... note that SL_OVERRIDE_VERIFY_VOLUME is not required,
    // as this is IRP_MJ_INTERNAL_DEVICE_CONTROL 
    //

    IoCallDriver(commonExtension->LowerDeviceObject, mmcData->CapabilitiesIrp);

    KeWaitForSingleObject(&mmcData->CapabilitiesEvent,
                          Executive, KernelMode, FALSE, NULL);
    
    status = mmcData->CapabilitiesIrp->IoStatus.Status;
    
    if (!NT_SUCCESS(status)) {

        goto FinishDriveUpdate;
    
    }

    //
    // we've updated the feature set, so update whether or not reads and writes
    // are allowed or not.
    //

    KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
               "CdRomUpdateMmc => Succeeded "
               "--------------------"
               "--------------------\n"));

    /*++
    
    NOTE: It is important to only use srb->DataTransferLength worth
          of data at this point, since the bufferSize is what is
          *available* to use, not what was *actually* used.
    
    --*/

#if DBG
    CdRompPrintAllFeaturePages(mmcData->CapabilitiesBuffer,
                               srb->DataTransferLength);
#endif // DBG

    //
    // update whether or not writes are allowed.  this is currently defined
    // as requiring TargetDefectManagement and RandomWritable features
    //
    {
        PFEATURE_HEADER defectHeader;
        PFEATURE_HEADER writableHeader;

        defectHeader   = CdRomFindFeaturePage(mmcData->CapabilitiesBuffer,
                                              srb->DataTransferLength,
                                              FeatureDefectManagement);
        writableHeader = CdRomFindFeaturePage(mmcData->CapabilitiesBuffer,
                                              srb->DataTransferLength,
                                              FeatureRandomWritable);

        if ((defectHeader != NULL)  && (writableHeader != NULL) &&
            (defectHeader->Current) && (writableHeader->Current)) {

            //
            // this should be the *ONLY* place writes are set to allowed 
            //

            KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                       "CdRomUpdateMmc => Writes *allowed*\n"));
            mmcData->WriteAllowed = TRUE;

        } else {

            if (defectHeader == NULL) {
                KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                           "CdRomUpdateMmc => No writes - %s = %s\n",
                           "defect management", "DNE"));
            } else {
                KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                           "CdRomUpdateMmc => No writes - %s = %s\n",
                           "defect management", "Not Current"));
            }
            if (writableHeader == NULL) {
                KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                           "CdRomUpdateMmc => No writes - %s = %s\n",
                           "sector writable", "DNE"));
            } else {
                KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                           "CdRomUpdateMmc => No writes - %s = %s\n",
                           "sector writable", "Not Current"));
            }
        } // end of feature checking
    } // end of check for writability

    status = STATUS_SUCCESS;

FinishDriveUpdate:

    CdRompFlushDelayedList(Fdo, mmcData, status, TRUE);

    return;
}


VOID
CdRompFlushDelayedList(
    IN PDEVICE_OBJECT Fdo,
    IN PCDROM_MMC_EXTENSION MmcData,
    IN NTSTATUS Status,
    IN BOOLEAN CalledFromWorkItem
    )
{
    LIST_ENTRY irpList;
    PLIST_ENTRY listEntry;
    KIRQL oldIrql;
    
    // NOTE - REF #0002
    //
    // need to set the new state first to prevent deadlocks.
    // this is only done from the workitem, to prevent any
    // edge cases where we'd "lose" the UpdateRequired
    //
    // then, must ignore the state, since it's not guaranteed to
    // be the same any longer.  the only thing left is to handle
    // all the delayed irps by flushing the queue and sending them
    // back onto the StartIo queue for the device.
    //

    if (CalledFromWorkItem) {
        
        LONG oldState;
        LONG newState;

        if (NT_SUCCESS(Status)) {
            newState = CdromMmcUpdateComplete;
        } else {
            newState = CdromMmcUpdateRequired;
        }

        oldState = InterlockedCompareExchange(&MmcData->UpdateState,
                                              newState,
                                              CdromMmcUpdateStarted);
        ASSERT(oldState == CdromMmcUpdateStarted);

    } else {

        //
        // just flushing the queue if not called from the workitem,
        // and we don't want to ever fail the queue in those cases.
        //

        ASSERT(NT_SUCCESS(Status));

    }

    /*
     *  Get all the delayed IRPs into a private list first to avoid an infinite loop 
     *  where irps are added to the DelayedIrpsList while we are siphoning them off.
     */
    InitializeListHead(&irpList);
    KeAcquireSpinLock(&MmcData->DelayedIrpsLock, &oldIrql);
    while (!IsListEmpty(&MmcData->DelayedIrpsList)){
        listEntry = RemoveHeadList(&MmcData->DelayedIrpsList);
        InsertTailList(&irpList, listEntry);
        ASSERT(MmcData->NumDelayedIrps > 0);
        MmcData->NumDelayedIrps--;
    }
    ASSERT(MmcData->NumDelayedIrps == 0);
    KeReleaseSpinLock(&MmcData->DelayedIrpsLock, oldIrql);

    // if this assert fires, it means that we have started
    // a workitem when the previous workitem took the delayed
    // irp.  if this happens, then the logic in HACKHACK #0002
    // is either flawed or the rules set within are not being
    // followed.  this would require investigation.
    ASSERT(!IsListEmpty(&irpList));

    //
    // now either succeed or fail all the delayed irps, according
    // to the update status.
    //

    while (!IsListEmpty(&irpList)){
        PIRP irp;
        
        listEntry = RemoveHeadList(&irpList);
        irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
        
        irp->Tail.Overlay.DriverContext[0] = 0;
        irp->Tail.Overlay.DriverContext[1] = 0;
        irp->Tail.Overlay.DriverContext[2] = 0;
        irp->Tail.Overlay.DriverContext[3] = 0;

        if (NT_SUCCESS(Status)) {
            
            KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                       "CdRomUpdateMmc => Re-sending delayed irp %p\n",
                       irp));
            IoStartPacket(Fdo, irp, NULL, NULL);

        } else {
            
            KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                       "CdRomUpdateMmc => Failing delayed irp %p with "
                       " status %x\n", irp, Status));
            irp->IoStatus.Information = 0;
            irp->IoStatus.Status = Status;
            ClassReleaseRemoveLock(Fdo, irp);
            IoCompleteRequest(irp, IO_CD_ROM_INCREMENT);

        }

    } // while (list)

    return;

}

VOID
CdRomDeAllocateMmcResources(
    IN PDEVICE_OBJECT Fdo
    )
{
    PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
    PCDROM_DATA cddata = commonExtension->DriverData;
    PCDROM_MMC_EXTENSION mmcData = &cddata->Mmc;
    NTSTATUS status;

    if (mmcData->CapabilitiesWorkItem) {
        IoFreeWorkItem(mmcData->CapabilitiesWorkItem);
        mmcData->CapabilitiesWorkItem = NULL;
    }
    if (mmcData->CapabilitiesIrp) {
        IoFreeIrp(mmcData->CapabilitiesIrp);
        mmcData->CapabilitiesIrp = NULL;
    }
    if (mmcData->CapabilitiesMdl) {
        IoFreeMdl(mmcData->CapabilitiesMdl);
        mmcData->CapabilitiesMdl = NULL;
    }
    if (mmcData->CapabilitiesBuffer) {
        ExFreePool(mmcData->CapabilitiesBuffer);
        mmcData->CapabilitiesBuffer = NULL;
    }
    mmcData->CapabilitiesBuffer = 0;
    mmcData->IsMmc = FALSE;
    mmcData->WriteAllowed = FALSE;
    
    return;
}

NTSTATUS
CdRomAllocateMmcResources(
    IN PDEVICE_OBJECT Fdo
    )
{
    PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
    PCDROM_DATA cddata = commonExtension->DriverData;
    PCDROM_MMC_EXTENSION mmcData = &cddata->Mmc;
    PIO_STACK_LOCATION irpStack;
    NTSTATUS status;

    ASSERT(mmcData->CapabilitiesWorkItem == NULL);
    ASSERT(mmcData->CapabilitiesIrp == NULL);
    ASSERT(mmcData->CapabilitiesMdl == NULL);
    ASSERT(mmcData->CapabilitiesBuffer == NULL);
    ASSERT(mmcData->CapabilitiesBufferSize == 0);

    status = CdRomGetConfiguration(Fdo,
                                   &mmcData->CapabilitiesBuffer,
                                   &mmcData->CapabilitiesBufferSize,
                                   FeatureProfileList,
                                   SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
    if (!NT_SUCCESS(status)) {
        ASSERT(mmcData->CapabilitiesBuffer     == NULL);
        ASSERT(mmcData->CapabilitiesBufferSize == 0);
        return status;
    }
    ASSERT(mmcData->CapabilitiesBuffer     != NULL);
    ASSERT(mmcData->CapabilitiesBufferSize != 0);
    
    mmcData->CapabilitiesMdl = IoAllocateMdl(mmcData->CapabilitiesBuffer,
                                             mmcData->CapabilitiesBufferSize,
                                             FALSE, FALSE, NULL);
    if (mmcData->CapabilitiesMdl == NULL) {
        ExFreePool(mmcData->CapabilitiesBuffer);
        mmcData->CapabilitiesBufferSize = 0;
        return STATUS_INSUFFICIENT_RESOURCES;
    }

        
    mmcData->CapabilitiesIrp = IoAllocateIrp(Fdo->StackSize + 2, FALSE);
    if (mmcData->CapabilitiesIrp == NULL) {
        IoFreeMdl(mmcData->CapabilitiesMdl);
        ExFreePool(mmcData->CapabilitiesBuffer);
        mmcData->CapabilitiesBufferSize = 0;
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    mmcData->CapabilitiesWorkItem = IoAllocateWorkItem(Fdo);
    if (mmcData->CapabilitiesWorkItem == NULL) {
        IoFreeIrp(mmcData->CapabilitiesIrp);
        IoFreeMdl(mmcData->CapabilitiesMdl);
        ExFreePool(mmcData->CapabilitiesBuffer);
        mmcData->CapabilitiesBufferSize = 0;
        return STATUS_INSUFFICIENT_RESOURCES;
    }
            
    //
    // everything has been allocated, so now prepare it all....
    //

    MmBuildMdlForNonPagedPool(mmcData->CapabilitiesMdl);
    InitializeListHead(&mmcData->DelayedIrpsList);
    KeInitializeSpinLock(&mmcData->DelayedIrpsLock);
    mmcData->NumDelayedIrps = 0;
    
    //
    // use the extra stack for internal bookkeeping
    //
    IoSetNextIrpStackLocation(mmcData->CapabilitiesIrp);
    irpStack = IoGetCurrentIrpStackLocation(mmcData->CapabilitiesIrp);
    irpStack->Parameters.Others.Argument1 = Fdo;
    irpStack->Parameters.Others.Argument2 = mmcData->CapabilitiesBuffer;
    irpStack->Parameters.Others.Argument3 = &(mmcData->CapabilitiesSrb);
    // arg 4 is the retry count

    //
    // set the completion event to FALSE for now
    //

    KeInitializeEvent(&mmcData->CapabilitiesEvent,
                      SynchronizationEvent, FALSE);
    return STATUS_SUCCESS;

}

⌨️ 快捷键说明

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