📄 cdrom.c
字号:
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->Function = SRB_FUNCTION_EXECUTE_SCSI;
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 = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
transferByteCount,
CDROM_TAG_RAW);
if (!dataBuffer) {
ExFreePool(senseBuffer);
ExFreePool(srb);
IoFreeIrp(irp2);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
BAIL_OUT(Irp);
CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
return;
}
/*
* Zero out input buffer in case the device returns fewer bytes than advertized,
* which would cause us to return uninitialized kernel memory.
*/
RtlZeroMemory(dataBuffer, transferByteCount);
irp2->MdlAddress = IoAllocateMdl(dataBuffer,
transferByteCount,
FALSE,
FALSE,
(PIRP) NULL);
if (!irp2->MdlAddress) {
ExFreePool(senseBuffer);
ExFreePool(srb);
ExFreePool(dataBuffer);
IoFreeIrp(irp2);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
BAIL_OUT(Irp);
CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
return;
}
//
// Prepare the MDL
//
MmBuildMdlForNonPagedPool(irp2->MdlAddress);
srb->DataBuffer = dataBuffer;
//
// Set the new block size in the descriptor.
//
if (use6Byte) {
cdData->BlockDescriptor.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
cdData->BlockDescriptor.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
cdData->BlockDescriptor.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
} else {
cdData->BlockDescriptor10.BlockLength[0] = (UCHAR)(COOKED_SECTOR_SIZE >> 16) & 0xFF;
cdData->BlockDescriptor10.BlockLength[1] = (UCHAR)(COOKED_SECTOR_SIZE >> 8) & 0xFF;
cdData->BlockDescriptor10.BlockLength[2] = (UCHAR)(COOKED_SECTOR_SIZE & 0xFF);
}
//
// Move error page into dataBuffer.
//
RtlCopyMemory(srb->DataBuffer, &cdData->Header, transferByteCount);
//
// Build and send a mode select to switch into raw mode.
//
srb->SrbFlags = fdoExtension->SrbFlags;
SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_OUT);
srb->DataTransferLength = transferByteCount;
srb->TimeOutValue = fdoExtension->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(fdoExtension->CommonExtension.LowerDeviceObject, irp2);
return;
}
//
// 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 =
fdoExtension->AdapterDescriptor->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;
}
ClassSplitRequest(Fdo, Irp, maximumTransferLength);
return;
} else if (currentIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
//
// Allocate an irp, srb and associated structures.
//
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;
}
RtlZeroMemory(senseBuffer, SENSE_BUFFER_SIZE);
//
// 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;
}
//
// keep track of the new irp as Argument3
//
nextIrpStack->Parameters.Others.Argument3 = irp2;
//
// 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;
IoSetCompletionRoutine(irp2,
CdRomDeviceControlCompletion,
srb,
TRUE,
TRUE,
TRUE);
//
// Setup those fields that are generic to all requests.
//
srb->Length = SCSI_REQUEST_BLOCK_SIZE;
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
srb->SrbStatus = srb->ScsiStatus = 0;
srb->NextSrb = 0;
srb->OriginalRequest = irp2;
srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
srb->SenseInfoBuffer = senseBuffer;
if ((currentIrpStack->Parameters.DeviceIoControl.IoControlCode & 3) == METHOD_BUFFERED){
/*
* The kernel allocated the output buffer for us and did not initialize it.
* We may not return the entire read length, so zero out the return buffer in order to avoid
* returning part of an uninitialized kernel buffer.
*/
if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength > currentIrpStack->Parameters.DeviceIoControl.InputBufferLength){
RtlZeroMemory((PUCHAR)Irp->AssociatedIrp.SystemBuffer+currentIrpStack->Parameters.DeviceIoControl.InputBufferLength,
currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength-currentIrpStack->Parameters.DeviceIoControl.InputBufferLength);
}
}
switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_CDROM_RAW_READ: {
//
// Determine whether the drive is currently in raw or cooked mode,
// and which command to use to read the data.
//
RAW_READ_INFO rawReadInfo;
PVOID outputVirtAddr = NULL;
/*
* Since this ioctl is METHOD_OUT_DIRECT, we need to copy away the input buffer before interpreting it.
* This prevents a malicious app from messing with the input buffer while we are interpreting it.
*/
rawReadInfo = *(PRAW_READ_INFO)currentIrpStack->Parameters.DeviceIoControl.Type3InputBuffer;
if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength){
/*
* Make sure that any user buffer that we pass down to the hardware is properly aligned
*/
ASSERT(Irp->MdlAddress);
outputVirtAddr = MmGetMdlVirtualAddress(Irp->MdlAddress);
if ((ULONG_PTR)outputVirtAddr & fdoExtension->AdapterDescriptor->AlignmentMask){
ASSERT(!((ULONG_PTR)outputVirtAddr & fdoExtension->AdapterDescriptor->AlignmentMask));
ExFreePool(senseBuffer);
ExFreePool(srb);
IoFreeIrp(irp2);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
BAIL_OUT(Irp);
CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
return;
}
}
if (!TEST_FLAG(cdData->XAFlags, XA_USE_READ_CD)) {
ULONG maximumTransferLength;
if (cdData->RawAccess) {
ULONG rawTransferPages;
ULONG startingSector;
UCHAR min, sec, frame;
//
// Free the recently allocated irp, as we don't need it.
//
IoFreeIrp(irp2);
cdb = (PCDB)srb->Cdb;
RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
//
// Calculate starting offset.
//
startingSector = (ULONG)(rawReadInfo.DiskOffset.QuadPart >> fdoExtension->SectorShift);
transferByteCount = rawReadInfo.SectorCount * RAW_SECTOR_SIZE;
maximumTransferLength = fdoExtension->AdapterDescriptor->MaximumTransferLength;
rawTransferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(outputVirtAddr, transferByteCount);
//
// Determine if request is within limits imposed by miniport.
//
if (transferByteCount > maximumTransferLength ||
rawTransferPages > fdoExtension->AdapterDescriptor->MaximumPhysicalPages) {
//
// The claim is that this won't happen, and is backed up by
// ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
// we get only 4 sector requests.
//
ExFreePool(senseBuffer);
ExFreePool(srb);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
BAIL_OUT(Irp);
CdRomCompleteIrpAndStartNextPacketSafely(Fdo, Irp);
return;
}
srb->OriginalRequest = Irp;
srb->SrbFlags = fdoExtension->SrbFlags;
SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
srb->DataTransferLength = transferByteCount;
srb->TimeOutValue = fdoExtension->TimeOutValue;
srb->CdbLength = 10;
srb->DataBuffer = outputVirtAddr;
if (rawReadInfo.TrackMode == CDDA) {
if (TEST_FLAG(cdData->XAFlags, XA_PLEXTOR_CDDA)) {
srb->CdbLength = 12;
cdb->PLXTR_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
cdb->PLXTR_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
cdb->PLXTR_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
cdb->PLXTR_READ_CDDA.LogicalBlockByte0 = (UCHAR) ((startingSector >> 24) & 0xFF);
cdb->PLXTR_READ_CDDA.TransferBlockByte3 = (UCHAR) (rawReadInfo.SectorCount & 0xFF);
cdb->PLXTR_READ_CDDA.TransferBlockByte2 = (UCHAR) (rawReadInfo.SectorCount >> 8);
cdb->PLXTR_READ_CDDA.TransferBlockByte1 = 0;
cdb->PLXTR_READ_CDDA.TransferBlockByte0 = 0;
cdb->PLXTR_READ_CDDA.SubCode = 0;
cdb->PLXTR_READ_CDDA.OperationCode = 0xD8;
} else if (TEST_FLAG(cdData->XAFlags, XA_NEC_CDDA)) {
cdb->NEC_READ_CDDA.LogicalBlockByte3 = (UCHAR) (startingSector & 0xFF);
cdb->NEC_READ_CDDA.LogicalBlockByte2 = (UCHAR) ((startingSector >> 8) & 0xFF);
cdb->NEC_READ_CDDA.LogicalBlockByte1 = (UCHAR) ((startingSector >> 16) & 0xFF);
cdb->NEC_READ_CDDA.LogicalBlo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -