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