📄 mmc.c
字号:
//
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 + -