📄 mmc.c
字号:
/*--
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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -