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