📄 cdrom.c
字号:
//
TraceLog((CdromDebugWarning,
"CdRomDetermineRawReadCapabilities: Devices for newer "
"busses must support READ_CD command for FDO %p, Bus %x\n",
Fdo, fdoExtension->DeviceDescriptor->BusType));
SET_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT);
SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
}
//
// now clear all our READ_CD flags if the drive should have supported
// it, but we are not sure it actually does. we still won't query
// the drive more than one time if it supports the command.
//
if (TEST_FLAG(cddata->HackFlags, CDROM_HACK_FORCE_READ_CD_DETECTION)) {
TraceLog((CdromDebugWarning,
"Forcing detection of READ_CD for FDO %p because "
"testing showed some firmware did not properly support it\n",
Fdo));
CLEAR_FLAG(cddata->XAFlags, XA_USE_READ_CD);
}
//
// read our READ_CD support in the registry if it was seeded.
//
{
ULONG readCdSupported = 0;
ClassGetDeviceParameter(fdoExtension,
CDROM_SUBKEY_NAME,
CDROM_READ_CD_NAME,
&readCdSupported
);
if (readCdSupported != 0) {
TraceLog((CdromDebugWarning,
"Defaulting to READ_CD because previously detected "
"that the device supports it for Fdo %p.\n",
Fdo
));
SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
}
}
//
// backwards-compatible attempt to determine if the drive
// supports any method of reading digital audio from the disc.
//
// NOTE: Deprecate this; remove this check in longhorn and
// always use READ_CD.
if (!TEST_FLAG(cddata->XAFlags, XA_USE_READ_CD)) {
SCSI_REQUEST_BLOCK srb = {0};
PCDB cdb;
ULONG length;
PUCHAR buffer = NULL;
ULONG count;
//
// ISSUE-2000/07/05-henrygab - use the mode page to determine
// READ_CD support, then fall back on the below
// method, which may not always detect this ability
// on older (pre-1999) drives.
//
//
// Build the MODE SENSE CDB. The data returned will be kept in the
// device extension and used to set block size.
//
length = max(sizeof(ERROR_RECOVERY_DATA),sizeof(ERROR_RECOVERY_DATA10));
buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
length,
CDROM_TAG_MODE_DATA);
if (!buffer) {
TraceLog((CdromDebugWarning,
"CdRomDetermineRawReadCapabilities: cannot allocate "
"buffer, so leaving for FDO %p\n", Fdo));
status = STATUS_INSUFFICIENT_RESOURCES;
goto CdRomInitDeviceExit;
}
for (count = 0; count < 2; count++) {
if (count == 0) {
length = sizeof(ERROR_RECOVERY_DATA);
} else {
length = sizeof(ERROR_RECOVERY_DATA10);
}
RtlZeroMemory(buffer, length);
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
cdb = (PCDB)srb.Cdb;
srb.TimeOutValue = fdoExtension->TimeOutValue;
if (count == 0) {
srb.CdbLength = 6;
cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
cdb->MODE_SENSE.PageCode = 0x1;
// note: not setting DBD in order to get the block descriptor!
cdb->MODE_SENSE.AllocationLength = (UCHAR)length;
} else {
srb.CdbLength = 10;
cdb->MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
cdb->MODE_SENSE10.PageCode = 0x1;
// note: not setting DBD in order to get the block descriptor!
cdb->MODE_SENSE10.AllocationLength[0] = (UCHAR)(length >> 8);
cdb->MODE_SENSE10.AllocationLength[1] = (UCHAR)(length & 0xFF);
}
status = ClassSendSrbSynchronous(Fdo,
&srb,
buffer,
length,
FALSE);
if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {
//
// STATUS_DATA_OVERRUN means it's a newer drive with more info
// to tell us, so it's probably able to support READ_CD
//
RtlZeroMemory(cdb, CDB12GENERIC_LENGTH);
srb.CdbLength = 12;
cdb->READ_CD.OperationCode = SCSIOP_READ_CD;
status = ClassSendSrbSynchronous(Fdo,
&srb,
NULL,
0,
FALSE);
if (NT_SUCCESS(status) ||
(status == STATUS_NO_MEDIA_IN_DEVICE) ||
(status == STATUS_NONEXISTENT_SECTOR) ||
(status == STATUS_UNRECOGNIZED_MEDIA)
) {
//
// READ_CD works
//
TraceLog((CdromDebugWarning,
"CdRomDetermineRawReadCapabilities: Using "
"READ_CD for FDO %p due to status %x\n",
Fdo,
status));
SET_FLAG(cddata->XAFlags, XA_USE_READ_CD);
//
// ignore errors in saving this info
//
ClassSetDeviceParameter(fdoExtension,
CDROM_SUBKEY_NAME,
CDROM_READ_CD_NAME,
1
);
break; // out of the for loop
}
TraceLog((CdromDebugWarning,
"CdRomDetermineRawReadCapabilities: Using "
"%s-byte mode switching for FDO %p due to status "
"%x returned for READ_CD\n",
((count == 0) ? "6" : "10"), Fdo, status));
if (count == 0) {
SET_FLAG(cddata->XAFlags, XA_USE_6_BYTE);
RtlCopyMemory(&cddata->Header,
buffer,
sizeof(ERROR_RECOVERY_DATA));
cddata->Header.ModeDataLength = 0;
} else {
SET_FLAG(cddata->XAFlags, XA_USE_10_BYTE);
RtlCopyMemory(&cddata->Header10,
buffer,
sizeof(ERROR_RECOVERY_DATA10));
cddata->Header10.ModeDataLength[0] = 0;
cddata->Header10.ModeDataLength[1] = 0;
}
break; // out of for loop
}
TraceLog((CdromDebugWarning,
"FDO %p failed %x byte mode sense, status %x\n",
Fdo,
((count == 0) ? 6 : 10),
status
));
//
// mode sense failed
//
} // end of for loop to try 6 and 10-byte mode sense
if (count == 2) {
//
// nothing worked. we probably cannot support digital
// audio extraction from this drive
//
TraceLog((CdromDebugWarning,
"CdRomDetermineRawReadCapabilities: FDO %p "
"cannot support READ_CD\n", Fdo));
CLEAR_FLAG(cddata->XAFlags, XA_PLEXTOR_CDDA);
CLEAR_FLAG(cddata->XAFlags, XA_NEC_CDDA);
SET_FLAG(cddata->XAFlags, XA_NOT_SUPPORTED);
} // end of count == 2
//
// free our resources
//
ExFreePool(buffer);
//
// set a successful status
// (in case someone later checks this)
//
status = STATUS_SUCCESS;
}
//
// Register interfaces for this device.
//
{
UNICODE_STRING interfaceName = {0};
RtlInitUnicodeString(&interfaceName, NULL);
status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
(LPGUID) &CdRomClassGuid,
NULL,
&interfaceName);
if(NT_SUCCESS(status)) {
cddata->CdromInterfaceString = interfaceName;
status = IoSetDeviceInterfaceState(
&interfaceName,
TRUE);
if(!NT_SUCCESS(status)) {
TraceLog((CdromDebugWarning,
"CdromInitDevice: Unable to register cdrom "
"DCA for fdo %p [%lx]\n",
Fdo, status));
}
}
}
return(STATUS_SUCCESS);
CdRomInitDeviceExit:
CdRomDeAllocateMmcResources(Fdo);
RtlZeroMemory(&(cddata->Mmc), sizeof(CDROM_MMC_EXTENSION));
return status;
}
NTSTATUS
CdRomStartDevice(
IN PDEVICE_OBJECT Fdo
)
/*++
Routine Description:
This routine starts the timer for the cdrom
Arguments:
Fdo - a pointer to the functional device object for this device
Return Value:
status
--*/
{
PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
PCDROM_DATA cddata = (PCDROM_DATA)(commonExtension->DriverData);
PDVD_COPY_PROTECT_KEY copyProtectKey;
PDVD_RPC_KEY rpcKey;
IO_STATUS_BLOCK ioStatus = {0};
ULONG bufferLen;
//
// if we have a DVD-ROM
// if we have a rpc0 device
// fake a rpc2 device
// if device does not have a dvd region set
// select a dvd region for the user
//
cddata->DvdRpc0Device = FALSE;
//
// since StartIo() will call IoStartNextPacket() on error, allowing
// StartIo() to be non-recursive prevents stack overflow bugchecks in
// severe error cases (such as fault-injection in the verifier).
//
// the only difference is that the thread context may be different
// in StartIo() than in the caller of IoStartNextPacket().
//
IoSetStartIoAttributes(Fdo, TRUE, TRUE);
//
// check to see if we have a DVD device
//
if (CdRomGetDeviceType(Fdo) != FILE_DEVICE_DVD) {
return STATUS_SUCCESS;
}
//
// we got a DVD drive.
// now, figure out if we have a RPC0 device
//
bufferLen = DVD_RPC_KEY_LENGTH;
copyProtectKey =
(PDVD_COPY_PROTECT_KEY)ExAllocatePoolWithTag(PagedPool,
bufferLen,
DVD_TAG_RPC2_CHECK);
if (copyProtectKey == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// get the device region
//
RtlZeroMemory (copyProtectKey, bufferLen);
copyProtectKey->KeyLength = DVD_RPC_KEY_LENGTH;
copyProtectKey->KeyType = DvdGetRpcKey;
//
// Build a request for READ_KEY
//
ClassSendDeviceIoControlSynchronous(
IOCTL_DVD_READ_KEY,
Fdo,
copyProtectKey,
DVD_RPC_KEY_LENGTH,
DVD_RPC_KEY_LENGTH,
FALSE,
&ioStatus
);
if (!NT_SUCCESS(ioStatus.Status)) {
//
// we have a rpc0 device
//
// NOTE: THIS MODIFIES THE BEHAVIOR OF THE IOCTL
//
cddata->DvdRpc0Device = TRUE;
TraceLog((CdromDebugWarning,
"CdromStartDevice (%p): RPC Phase 1 drive detected\n",
Fdo));
//
// note: we could force this chosen now, but it's better to reduce
// the number of code paths that could be taken. always delay to
// increase the percentage code coverage.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -