You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1540 lines
49 KiB
1540 lines
49 KiB
/*--
|
|
|
|
Copyright (C) Microsoft Corporation, 2000
|
|
|
|
Module Name:
|
|
|
|
mmc.c
|
|
|
|
Abstract:
|
|
|
|
This file is used to extend cdrom.sys to detect and use mmc-compatible
|
|
drives' capabilities more wisely.
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
SCSI Tape, CDRom and Disk class drivers share common routines
|
|
that can be found in the CLASS directory (..\ntos\dd\class).
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ntddk.h"
|
|
#include "classpnp.h"
|
|
#include "cdrom.h"
|
|
#include "mmc.tmh"
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CdRomGetConfiguration(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
OUT PGET_CONFIGURATION_HEADER *Buffer,
|
|
OUT PULONG BytesReturned,
|
|
IN FEATURE_NUMBER StartingFeature,
|
|
IN ULONG RequestedType
|
|
);
|
|
VOID
|
|
CdRompPrintAllFeaturePages(
|
|
IN PGET_CONFIGURATION_HEADER Buffer,
|
|
IN ULONG Usable
|
|
);
|
|
NTSTATUS
|
|
CdRomUpdateMmcDriveCapabilitiesCompletion(
|
|
IN PDEVICE_OBJECT Unused,
|
|
IN PIRP Irp,
|
|
IN PDEVICE_OBJECT Fdo
|
|
);
|
|
VOID
|
|
CdRomPrepareUpdateCapabilitiesIrp(
|
|
PDEVICE_OBJECT Fdo
|
|
);
|
|
|
|
/*++
|
|
|
|
NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
|
|
if memory is non-paged
|
|
PRESUMES ALL DATA IS ACCESSIBLE based on FeatureBuffer
|
|
|
|
--*/
|
|
VOID
|
|
CdRomFindProfileInProfiles(
|
|
IN PFEATURE_DATA_PROFILE_LIST ProfileHeader,
|
|
IN FEATURE_PROFILE_TYPE ProfileToFind,
|
|
OUT PBOOLEAN Found
|
|
)
|
|
{
|
|
PFEATURE_DATA_PROFILE_LIST_EX profile;
|
|
ULONG numberOfProfiles;
|
|
ULONG i;
|
|
|
|
|
|
*Found = FALSE;
|
|
|
|
if (ProfileHeader->Header.AdditionalLength % 4 != 0) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"Profile total length %x is not integral multiple of 4\n",
|
|
ProfileHeader->Header.AdditionalLength));
|
|
ASSERT(FALSE);
|
|
return;
|
|
}
|
|
|
|
numberOfProfiles = ProfileHeader->Header.AdditionalLength / 4;
|
|
profile = ProfileHeader->Profiles; // zero-sized array
|
|
|
|
for (i = 0; i < numberOfProfiles; i++) {
|
|
|
|
FEATURE_PROFILE_TYPE currentProfile;
|
|
|
|
currentProfile =
|
|
(profile->ProfileNumber[0] << 8) |
|
|
(profile->ProfileNumber[1] & 0xff);
|
|
|
|
if (currentProfile == ProfileToFind) {
|
|
|
|
*Found = TRUE;
|
|
|
|
}
|
|
|
|
profile++;
|
|
}
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
|
|
if memory is non-paged
|
|
|
|
--*/
|
|
PVOID
|
|
CdRomFindFeaturePage(
|
|
IN PGET_CONFIGURATION_HEADER FeatureBuffer,
|
|
IN ULONG Length,
|
|
IN FEATURE_NUMBER Feature
|
|
)
|
|
{
|
|
PUCHAR buffer;
|
|
PUCHAR limit;
|
|
|
|
if (Length < sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// set limit to point to first illegal address
|
|
//
|
|
|
|
limit = (PUCHAR)FeatureBuffer;
|
|
limit += Length;
|
|
|
|
//
|
|
// set buffer to point to first page
|
|
//
|
|
|
|
buffer = FeatureBuffer->Data;
|
|
|
|
//
|
|
// loop through each page until we find the requested one, or
|
|
// until it's not safe to access the entire feature header
|
|
// (if equal, have exactly enough for the feature header)
|
|
//
|
|
while (buffer + sizeof(FEATURE_HEADER) <= limit) {
|
|
|
|
PFEATURE_HEADER header = (PFEATURE_HEADER)buffer;
|
|
FEATURE_NUMBER thisFeature;
|
|
|
|
thisFeature =
|
|
(header->FeatureCode[0] << 8) |
|
|
(header->FeatureCode[1]);
|
|
|
|
if (thisFeature == Feature) {
|
|
|
|
PUCHAR temp;
|
|
|
|
//
|
|
// if don't have enough memory to safely access all the feature
|
|
// information, return NULL
|
|
//
|
|
temp = buffer;
|
|
temp += sizeof(FEATURE_HEADER);
|
|
temp += header->AdditionalLength;
|
|
|
|
if (temp > limit) {
|
|
|
|
//
|
|
// this means the transfer was cut-off, an insufficiently
|
|
// small buffer was given, or other arbitrary error. since
|
|
// it's not safe to view the amount of data (even though
|
|
// the header is safe) in this feature, pretend it wasn't
|
|
// transferred at all...
|
|
//
|
|
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"Feature %x exists, but not safe to access all its "
|
|
"data. returning NULL\n", Feature));
|
|
return NULL;
|
|
} else {
|
|
return buffer;
|
|
}
|
|
}
|
|
|
|
if (header->AdditionalLength % 4) {
|
|
ASSERT(!"Feature page AdditionalLength field must be integral multiple of 4!\n");
|
|
return NULL;
|
|
}
|
|
|
|
buffer += sizeof(FEATURE_HEADER);
|
|
buffer += header->AdditionalLength;
|
|
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*++
|
|
|
|
Private so we can later expose to someone wanting to use a preallocated buffer
|
|
|
|
--*/
|
|
NTSTATUS
|
|
CdRompGetConfiguration(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PGET_CONFIGURATION_HEADER Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG ValidBytes,
|
|
IN FEATURE_NUMBER StartingFeature,
|
|
IN ULONG RequestedType
|
|
)
|
|
{
|
|
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
|
|
PCDROM_DATA cdData;
|
|
SCSI_REQUEST_BLOCK srb = {0};
|
|
PCDB cdb;
|
|
ULONG_PTR returned;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
ASSERT(Buffer);
|
|
ASSERT(ValidBytes);
|
|
|
|
*ValidBytes = 0;
|
|
returned = 0;
|
|
|
|
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
|
|
RtlZeroMemory(Buffer, BufferSize);
|
|
|
|
fdoExtension = Fdo->DeviceExtension;
|
|
cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData);
|
|
|
|
if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT)) {
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
srb.TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT;
|
|
srb.CdbLength = 10;
|
|
|
|
cdb = (PCDB)srb.Cdb;
|
|
cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
|
|
cdb->GET_CONFIGURATION.RequestType = (UCHAR)RequestedType;
|
|
cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(StartingFeature >> 8);
|
|
cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(StartingFeature & 0xff);
|
|
cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(BufferSize >> 8);
|
|
cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(BufferSize & 0xff);
|
|
|
|
status = ClassSendSrbSynchronous(Fdo, &srb, Buffer,
|
|
BufferSize, FALSE);
|
|
returned = srb.DataTransferLength;
|
|
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: Status was %x\n", status));
|
|
|
|
if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
|
|
|
|
//
|
|
// if returned more than can be stored in a ULONG, return false
|
|
//
|
|
|
|
if (returned > (ULONG)(-1)) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
ASSERT(returned <= BufferSize);
|
|
*ValidBytes = (ULONG)returned;
|
|
return STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: failed %x\n", status));
|
|
return status;
|
|
|
|
}
|
|
ASSERT(FALSE);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/*++
|
|
|
|
Allocates buffer with configuration info, returns STATUS_SUCCESS
|
|
or an error if one occurred
|
|
|
|
NOTE: does not handle case where more than 65000 bytes are returned,
|
|
which requires multiple calls with different starting feature
|
|
numbers.
|
|
|
|
--*/
|
|
NTSTATUS
|
|
CdRomGetConfiguration(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
OUT PGET_CONFIGURATION_HEADER *Buffer,
|
|
OUT PULONG BytesReturned,
|
|
IN FEATURE_NUMBER StartingFeature,
|
|
IN ULONG RequestedType
|
|
)
|
|
{
|
|
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
|
|
GET_CONFIGURATION_HEADER header = {0}; // eight bytes, not a lot
|
|
PGET_CONFIGURATION_HEADER buffer;
|
|
ULONG returned;
|
|
ULONG size;
|
|
ULONG i;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
fdoExtension = Fdo->DeviceExtension;
|
|
*Buffer = NULL;
|
|
*BytesReturned = 0;
|
|
|
|
buffer = NULL;
|
|
returned = 0;
|
|
|
|
//
|
|
// send the first request down to just get the header
|
|
//
|
|
|
|
status = CdRompGetConfiguration(Fdo, &header, sizeof(header),
|
|
&returned, StartingFeature, RequestedType);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// now try again, using information returned to allocate
|
|
// just enough memory
|
|
//
|
|
|
|
size = header.DataLength[0] << 24 |
|
|
header.DataLength[1] << 16 |
|
|
header.DataLength[2] << 8 |
|
|
header.DataLength[3] << 0 ;
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
//
|
|
// the datalength field is the size *following*
|
|
// itself, so adjust accordingly
|
|
//
|
|
|
|
size += 4*sizeof(UCHAR);
|
|
|
|
//
|
|
// make sure the size is reasonable
|
|
//
|
|
|
|
if (size <= sizeof(FEATURE_HEADER)) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: drive reports only %x bytes?\n",
|
|
size));
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// allocate the memory
|
|
//
|
|
|
|
buffer = (PGET_CONFIGURATION_HEADER)
|
|
ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
|
|
size,
|
|
CDROM_TAG_FEATURE);
|
|
|
|
if (buffer == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// send the first request down to just get the header
|
|
//
|
|
|
|
status = CdRompGetConfiguration(Fdo, buffer, size, &returned,
|
|
StartingFeature, RequestedType);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ExFreePool(buffer);
|
|
return status;
|
|
}
|
|
|
|
if (returned > size) {
|
|
ExFreePool(buffer);
|
|
return STATUS_INTERNAL_ERROR;
|
|
}
|
|
|
|
returned = buffer->DataLength[0] << 24 |
|
|
buffer->DataLength[1] << 16 |
|
|
buffer->DataLength[2] << 8 |
|
|
buffer->DataLength[3] << 0 ;
|
|
returned += 4*sizeof(UCHAR);
|
|
|
|
if (returned <= size) {
|
|
*Buffer = buffer;
|
|
*BytesReturned = size; // amount of 'safe' memory
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// else retry using the new size....
|
|
//
|
|
|
|
size = returned;
|
|
ExFreePool(buffer);
|
|
buffer = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// it failed after a number of attempts, so just fail.
|
|
//
|
|
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdRomGetConfiguration: Failed %d attempts to get all feature "
|
|
"information\n", i));
|
|
return STATUS_IO_DEVICE_ERROR;
|
|
}
|
|
|
|
VOID
|
|
CdRomIsDeviceMmcDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
OUT PBOOLEAN IsMmc
|
|
)
|
|
{
|
|
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
|
|
PCDROM_DATA cdData = commonExtension->DriverData;
|
|
GET_CONFIGURATION_HEADER localHeader = {0};
|
|
NTSTATUS status;
|
|
ULONG usable;
|
|
ULONG size;
|
|
ULONG previouslyFailed;
|
|
|
|
PAGED_CODE();
|
|
ASSERT( commonExtension->IsFdo );
|
|
|
|
*IsMmc = FALSE;
|
|
|
|
//
|
|
// read the registry in case the drive failed previously,
|
|
// and a timeout is occurring.
|
|
//
|
|
|
|
previouslyFailed = FALSE;
|
|
ClassGetDeviceParameter(fdoExtension,
|
|
CDROM_SUBKEY_NAME,
|
|
CDROM_NON_MMC_DRIVE_NAME,
|
|
&previouslyFailed
|
|
);
|
|
|
|
if (previouslyFailed) {
|
|
SET_FLAG(cdData->HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT);
|
|
}
|
|
|
|
//
|
|
// check for the following profiles:
|
|
//
|
|
// ProfileList
|
|
//
|
|
|
|
status = CdRompGetConfiguration(Fdo,
|
|
&localHeader,
|
|
sizeof(localHeader),
|
|
&usable,
|
|
FeatureProfileList,
|
|
SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
|
|
|
|
if (status == STATUS_INVALID_DEVICE_REQUEST ||
|
|
status == STATUS_NO_MEDIA_IN_DEVICE ||
|
|
status == STATUS_IO_DEVICE_ERROR ||
|
|
status == STATUS_IO_TIMEOUT) {
|
|
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"GetConfiguration Failed (%x), device %p not mmc-compliant\n",
|
|
status, Fdo
|
|
));
|
|
previouslyFailed = TRUE;
|
|
ClassSetDeviceParameter(fdoExtension,
|
|
CDROM_SUBKEY_NAME,
|
|
CDROM_NON_MMC_DRIVE_NAME,
|
|
previouslyFailed
|
|
);
|
|
return;
|
|
|
|
} else if (!NT_SUCCESS(status)) {
|
|
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
|
|
"GetConfiguration Failed, status %x -- defaulting to -ROM\n",
|
|
status));
|
|
return;
|
|
|
|
} else if (usable < sizeof(GET_CONFIGURATION_HEADER)) {
|
|
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"GetConfiguration Failed, returned only %x bytes!\n", usable));
|
|
previouslyFailed = TRUE;
|
|
ClassSetDeviceParameter(fdoExtension,
|
|
CDROM_SUBKEY_NAME,
|
|
CDROM_NON_MMC_DRIVE_NAME,
|
|
previouslyFailed
|
|
);
|
|
return;
|
|
|
|
}
|
|
|
|
size = (localHeader.DataLength[0] << 24) |
|
|
(localHeader.DataLength[1] << 16) |
|
|
(localHeader.DataLength[2] << 8) |
|
|
(localHeader.DataLength[3] << 0);
|
|
|
|
if (size <= 4) {
|
|
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"GetConfiguration Failed, claims MMC support but doesn't "
|
|
"correctly return config length! (%x)\n",
|
|
size
|
|
));
|
|
previouslyFailed = TRUE;
|
|
ClassSetDeviceParameter(fdoExtension,
|
|
CDROM_SUBKEY_NAME,
|
|
CDROM_NON_MMC_DRIVE_NAME,
|
|
previouslyFailed
|
|
);
|
|
return;
|
|
|
|
} else if ((size % 4) != 0) {
|
|
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"GetConfiguration Failed, returned odd number of bytes %x!\n",
|
|
size
|
|
));
|
|
previouslyFailed = TRUE;
|
|
ClassSetDeviceParameter(fdoExtension,
|
|
CDROM_SUBKEY_NAME,
|
|
CDROM_NON_MMC_DRIVE_NAME,
|
|
previouslyFailed
|
|
);
|
|
return;
|
|
|
|
}
|
|
|
|
size += 4; // sizeof the datalength fields
|
|
|
|
#if DBG
|
|
{
|
|
PGET_CONFIGURATION_HEADER dbgBuffer;
|
|
NTSTATUS dbgStatus;
|
|
|
|
dbgBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
|
|
(SIZE_T)size,
|
|
CDROM_TAG_FEATURE);
|
|
if (dbgBuffer != NULL) {
|
|
RtlZeroMemory(dbgBuffer, size);
|
|
|
|
dbgStatus = CdRompGetConfiguration(Fdo, dbgBuffer, size,
|
|
&size, FeatureProfileList,
|
|
SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
|
|
|
|
if (NT_SUCCESS(dbgStatus)) {
|
|
CdRompPrintAllFeaturePages(dbgBuffer, usable);
|
|
}
|
|
ExFreePool(dbgBuffer);
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
*IsMmc = TRUE;
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
CdRompPrintAllFeaturePages(
|
|
IN PGET_CONFIGURATION_HEADER Buffer,
|
|
IN ULONG Usable
|
|
)
|
|
{
|
|
PFEATURE_HEADER header;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// items expected to ALWAYS be current if they exist
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureProfileList);
|
|
if (header != NULL) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: CurrentProfile %x "
|
|
"with %x bytes of data at %p\n",
|
|
Buffer->CurrentProfile[0] << 8 |
|
|
Buffer->CurrentProfile[1],
|
|
Usable, Buffer));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureCore);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"CORE Features"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureMorphing);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Morphing"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureRemovableMedium);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Removable Medium"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeaturePowerManagement);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Power Management"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureEmbeddedChanger);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Embedded Changer"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureMicrocodeUpgrade);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Microcode Update"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureTimeout);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Timeouts"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureLogicalUnitSerialNumber);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"LUN Serial Number"
|
|
));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// items expected not to always be current
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureWriteProtect);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Software Write Protect"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureRandomReadable);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Random Reads"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureMultiRead);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Multi-Read"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdRead);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"reading from CD-ROM/R/RW"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdRead);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"DVD Structure Reads"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureRandomWritable);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Random Writes"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureIncrementalStreamingWritable);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Incremental Streaming Writing"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureSectorErasable);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Sector Erasable Media"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureFormattable);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Formatting"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureDefectManagement);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"defect management"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureWriteOnce);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Write Once Media"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureRestrictedOverwrite);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Restricted Overwrites"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdrwCAVWrite);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"CD-RW CAV recording"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureMrw);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Mount Rainier media"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdPlusRW);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"DVD+RW media"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureRigidRestrictedOverwrite);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Rigid Restricted Overwrite"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdTrackAtOnce);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"CD Recording (Track At Once)"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdMastering);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"CD Recording (Mastering)"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdRecordableWrite);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"DVD Recording (Mastering)"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureDDCDRead);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"DD CD Reading"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureDDCDRWrite);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"DD CD-R Writing"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureDDCDRWWrite);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"DD CD-RW Writing"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureSMART);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"S.M.A.R.T."
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureCDAudioAnalogPlay);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Analogue CD Audio Operations"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdCSS);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"DVD CSS"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureRealTimeStreaming);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"Real-time Streaming Reads"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureDiscControlBlocks);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"DVD Disc Control Blocks"
|
|
));
|
|
}
|
|
|
|
header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdCPRM);
|
|
if (header) {
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"CdromGetConfiguration: %s %s\n",
|
|
(header->Current ?
|
|
"Currently supports" : "Is able to support"),
|
|
"DVD CPRM"
|
|
));
|
|
}
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
CdRomUpdateMmcDriveCapabilitiesCompletion(
|
|
IN PDEVICE_OBJECT Unused,
|
|
IN PIRP Irp,
|
|
IN PDEVICE_OBJECT Fdo
|
|
)
|
|
{
|
|
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
|
|
PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
|
|
PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
|
|
PSCSI_REQUEST_BLOCK srb = &(mmcData->CapabilitiesSrb);
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
PIRP delayedIrp;
|
|
|
|
// completion routine should retry as neccessary.
|
|
// when success, clear the flag to allow startio to proceed.
|
|
// else fail original request when retries are exhausted.
|
|
|
|
ASSERT(mmcData->CapabilitiesIrp == Irp);
|
|
|
|
// for now, if succeeded, just print the new pages.
|
|
|
|
if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// ISSUE-2000/4/20-henrygab - should we try to reallocate if size
|
|
// available became larger than what we
|
|
// originally allocated? otherwise, it
|
|
// is possible (not probable) that we
|
|
// would miss the feature. can check
|
|
// that by looking at the header size
|
|
// and comparing it to requested data
|
|
// size.
|
|
//
|
|
|
|
BOOLEAN retry;
|
|
ULONG retryInterval;
|
|
|
|
//
|
|
// Release the queue if it is frozen.
|
|
//
|
|
|
|
if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
|
|
ClassReleaseQueue(Fdo);
|
|
}
|
|
|
|
retry = ClassInterpretSenseInfo(
|
|
Fdo,
|
|
srb,
|
|
irpStack->MajorFunction,
|
|
0,
|
|
MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
|
|
&status,
|
|
&retryInterval);
|
|
|
|
//
|
|
// DATA_OVERRUN is not an error in this case....
|
|
//
|
|
|
|
if (status == STATUS_DATA_OVERRUN) {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// override verify_volume based on original irp's settings
|
|
//
|
|
|
|
if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
|
|
status == STATUS_VERIFY_REQUIRED) {
|
|
status = STATUS_IO_DEVICE_ERROR;
|
|
retry = TRUE;
|
|
}
|
|
|
|
if (retry && ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4)--) {
|
|
|
|
LARGE_INTEGER delay;
|
|
delay.QuadPart = retryInterval;
|
|
delay.QuadPart *= (LONGLONG)1000 * 1000 * 10;
|
|
|
|
//
|
|
// retry the request
|
|
//
|
|
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
|
|
"Not using ClassRetryRequest Yet\n"));
|
|
KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
|
|
"Retry update capabilities %p\n", Irp));
|
|
CdRomPrepareUpdateCapabilitiesIrp(Fdo);
|
|
|
|
CdRomRetryRequest(fdoExtension, Irp, retryInterval, TRUE);
|
|
|
|
//
|
|
// ClassRetryRequest(Fdo, Irp, delay);
|
|
//
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
KeSetEvent(&mmcData->CapabilitiesEvent, IO_CD_ROM_INCREMENT, FALSE);
|
|
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
VOID
|
|
CdRomPrepareUpdateCapabilitiesIrp(
|
|
PDEVICE_OBJECT Fdo
|
|
)
|
|
{
|
|
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 nextStack;
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
PCDB cdb;
|
|
ULONG bufferSize;
|
|
PIRP irp;
|
|
|
|
ASSERT(mmcData->UpdateState);
|
|
ASSERT(mmcData->NumDelayedIrps != 0);
|
|
ASSERT(mmcData->CapabilitiesIrp != NULL);
|
|
ASSERT(mmcData->CapabilitiesMdl != NULL);
|
|
ASSERT(mmcData->CapabilitiesBuffer);
|
|
ASSERT(mmcData->CapabilitiesBufferSize != 0);
|
|
ASSERT(fdoExtension->SenseData);
|
|
|
|
//
|
|
// do *NOT* call IoReuseIrp(), since it would zero out our
|
|
// current irp stack location, which we really don't want
|
|
// to happen. it would also set the current irp stack location
|
|
// to one greater than currently exists (to give max irp usage),
|
|
// but we don't want that either, since we use the top irp stack.
|
|
//
|
|
// IoReuseIrp(mmcData->CapabilitiesIrp, STATUS_UNSUCCESSFUL);
|
|
//
|
|
|
|
irp = mmcData->CapabilitiesIrp;
|
|
srb = &(mmcData->CapabilitiesSrb);
|
|
cdb = (PCDB)(srb->Cdb);
|
|
bufferSize = mmcData->CapabilitiesBufferSize;
|
|
|
|
//
|
|
// zero stuff out
|
|
//
|
|
|
|
RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
|
|
RtlZeroMemory(fdoExtension->SenseData, sizeof(SENSE_DATA));
|
|
RtlZeroMemory(mmcData->CapabilitiesBuffer, bufferSize);
|
|
|
|
//
|
|
// setup the srb
|
|
//
|
|
|
|
srb->TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT;
|
|
srb->Length = SCSI_REQUEST_BLOCK_SIZE;
|
|
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
|
|
srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
|
|
srb->SenseInfoBuffer = fdoExtension->SenseData;
|
|
srb->DataBuffer = mmcData->CapabilitiesBuffer;
|
|
srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
|
|
srb->DataTransferLength = mmcData->CapabilitiesBufferSize;
|
|
srb->ScsiStatus = 0;
|
|
srb->SrbStatus = 0;
|
|
srb->NextSrb = NULL;
|
|
srb->OriginalRequest = irp;
|
|
srb->SrbFlags = fdoExtension->SrbFlags;
|
|
srb->CdbLength = 10;
|
|
SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
|
|
SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
|
|
|
|
//
|
|
// setup the cdb
|
|
//
|
|
|
|
cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
|
|
cdb->GET_CONFIGURATION.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT;
|
|
cdb->GET_CONFIGURATION.StartingFeature[0] = 0;
|
|
cdb->GET_CONFIGURATION.StartingFeature[1] = 0;
|
|
cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(bufferSize >> 8);
|
|
cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(bufferSize & 0xff);
|
|
|
|
//
|
|
// setup the irp
|
|
//
|
|
|
|
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;
|
|
|
|
}
|