⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmc.c

📁 The CD ROM driver is used with Classpnp.sys to provide access to CD ROMs and DVD ROMs. It supports P
💻 C
📖 第 1 页 / 共 4 页
字号:
/*--

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 + -