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

📄 class2.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * PROJECT:         ReactOS Storage Stack
 * LICENSE:         DDK - see license.txt in the root dir
 * FILE:            drivers/storage/class2/class2.c
 * PURPOSE:         SCSI Class driver routines
 * PROGRAMMERS:     Based on a source code sample from Microsoft NT4 DDK
 */

#include <ntddk.h>
#include <ntdddisk.h>
#include <scsi.h>
#include <include/class2.h>
#include <stdio.h>

//#define NDEBUG
#include <debug.h>

#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, ScsiClassGetInquiryData)
#pragma alloc_text(PAGE, ScsiClassInitialize)
#pragma alloc_text(PAGE, ScsiClassGetCapabilities)
#pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
#pragma alloc_text(PAGE, ScsiClassClaimDevice)
#pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
#endif


#define INQUIRY_DATA_SIZE 2048
#define START_UNIT_TIMEOUT  30

NTSTATUS
STDCALL
ScsiClassCreateClose(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

NTSTATUS
STDCALL
ScsiClassReadWrite(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

NTSTATUS
STDCALL
ScsiClassDeviceControlDispatch(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    );

NTSTATUS
STDCALL
ScsiClassDeviceControl(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    );

NTSTATUS
STDCALL
ScsiClassInternalIoControl (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

NTSTATUS
STDCALL
ScsiClassShutdownFlush(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

NTSTATUS
STDCALL
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    );

//
// Class internal routines
//


VOID
STDCALL
RetryRequest(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PSCSI_REQUEST_BLOCK Srb,
    BOOLEAN Associated
    );

VOID
STDCALL
StartUnit(
    IN PDEVICE_OBJECT DeviceObject
    );

NTSTATUS
STDCALL
ClassIoCompletion(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    );

NTSTATUS
STDCALL
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
{
    return STATUS_SUCCESS;
}


ULONG
STDCALL
ScsiClassInitialize(
    IN  PVOID            Argument1,
    IN  PVOID            Argument2,
    IN  PCLASS_INIT_DATA InitializationData
    )

/*++

Routine Description:

    This routine is called by a class driver during its
    DriverEntry routine to initialize the driver.

Arguments:

    Argument1          - Driver Object.
    Argument2          - Registry Path.
    InitializationData - Device-specific driver's initialization data.

Return Value:

    A valid return code for a DriverEntry routine.

--*/

{


    PDRIVER_OBJECT  DriverObject = Argument1;
    ULONG           portNumber = 0;
    PDEVICE_OBJECT  portDeviceObject;
    NTSTATUS        status;
    STRING          deviceNameString;
    UNICODE_STRING  unicodeDeviceName;
    PFILE_OBJECT    fileObject;
    CCHAR           deviceNameBuffer[256];
    BOOLEAN         deviceFound = FALSE;

    DebugPrint((3,"\n\nSCSI Class Driver\n"));

    //
    // Validate the length of this structure. This is effectively a
    // version check.
    //

    if (InitializationData->InitializationDataSize > sizeof(CLASS_INIT_DATA)) {

        DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
        return (ULONG) STATUS_REVISION_MISMATCH;
    }

    //
    // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
    // are not required entry points.
    //

    if ((!InitializationData->ClassFindDevices) ||
        (!InitializationData->ClassDeviceControl) ||
        (!((InitializationData->ClassReadWriteVerification) ||
           (InitializationData->ClassStartIo)))) {

        DebugPrint((0,
            "ScsiClassInitialize: Class device-specific driver missing required entry\n"));

        return (ULONG) STATUS_REVISION_MISMATCH;
    }

    //
    // Update driver object with entry points.
    //

    DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
    DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
    DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
    DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceControlDispatch;
    DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
    DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;

    if (InitializationData->ClassStartIo) {
        DriverObject->DriverStartIo = InitializationData->ClassStartIo;
    }

    //
    // Open port driver controller device objects by name.
    //

    do {

        sprintf(deviceNameBuffer, "\\Device\\ScsiPort%lu", portNumber);

        DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer));

        RtlInitString(&deviceNameString, deviceNameBuffer);

        status = RtlAnsiStringToUnicodeString(&unicodeDeviceName,
                                              &deviceNameString,
                                              TRUE);

        if (!NT_SUCCESS(status)){
            break;
        }

        status = IoGetDeviceObjectPointer(&unicodeDeviceName,
                                           FILE_READ_ATTRIBUTES,
                                           &fileObject,
                                           &portDeviceObject);

        if (NT_SUCCESS(status)) {

            //
            // Call the device-specific driver's FindDevice routine.
            //

            if (InitializationData->ClassFindDevices(DriverObject, Argument2, InitializationData,
                                                     portDeviceObject, portNumber)) {

                deviceFound = TRUE;
            }
        }

        //
        // Check next SCSI adapter.
        //

        portNumber++;

    } while(NT_SUCCESS(status));

    return deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;
}


NTSTATUS
STDCALL
ScsiClassCreateClose(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    SCSI class driver create and close routine.  This is called by the I/O system
    when the device is opened or closed.

Arguments:

    DriverObject - Pointer to driver object created by system.

    Irp - IRP involved.

Return Value:

    Device-specific drivers return value or STATUS_SUCCESS.

--*/

{
    PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;

    //
    // Invoke the device-specific routine, if one exists. Otherwise complete
    // with SUCCESS
    //

    if (deviceExtension->ClassCreateClose) {

        return deviceExtension->ClassCreateClose(DeviceObject, Irp);

    } else {
        Irp->IoStatus.Status = STATUS_SUCCESS;

        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return(STATUS_SUCCESS);
    }
}



NTSTATUS
STDCALL
ScsiClassReadWrite(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the system entry point for read and write requests. The device-specific handler is invoked
    to perform any validation necessary. The number of bytes in the request are
    checked against the maximum byte counts that the adapter supports and requests are broken up into
    smaller sizes if necessary.

Arguments:

    DeviceObject
    Irp - IO request

Return Value:

    NT Status

--*/

{
    PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
    ULONG               transferPages;
    ULONG               transferByteCount = currentIrpStack->Parameters.Read.Length;
    ULONG               maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
    NTSTATUS            status;

    if (DeviceObject->Flags & DO_VERIFY_VOLUME &&
        !(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {

        //
        // if DO_VERIFY_VOLUME bit is set
        // in device object flags, fail request.
        //

        IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);

        Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
        Irp->IoStatus.Information = 0;

        IoCompleteRequest(Irp, 0);
        return STATUS_VERIFY_REQUIRED;
    }

    //
    // Invoke the device specific routine to do whatever it needs to verify
    // this request.
    //

    ASSERT(deviceExtension->ClassReadWriteVerification);

    status = deviceExtension->ClassReadWriteVerification(DeviceObject,Irp);

    if (!NT_SUCCESS(status)) {

        //
        // It is up to the device specific driver to set the Irp status.
        //

        IoCompleteRequest (Irp, IO_NO_INCREMENT);
        return status;
    } else if (status == STATUS_PENDING) {

        IoMarkIrpPending(Irp);
        return STATUS_PENDING;
    }

    //
    // Check for a zero length IO, as several macros will turn this into
    // seemingly a 0xffffffff length request.
    //

    if (transferByteCount == 0) {
        Irp->IoStatus.Status = STATUS_SUCCESS;
        Irp->IoStatus.Information = 0;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return STATUS_SUCCESS;

    }

    if (deviceExtension->ClassStartIo) {

        IoMarkIrpPending(Irp);

        IoStartPacket(DeviceObject,
                      Irp,
                      NULL,
                      NULL);

        return STATUS_PENDING;
    }

    //
    // Mark IRP with status pending.
    //

    IoMarkIrpPending(Irp);

    //
    // Add partition byte offset to make starting byte relative to
    // beginning of disk. In addition, add in skew for DM Driver, if any.
    //

    currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart +
                                                             deviceExtension->DMByteSkew);

    //
    // Calculate number of pages in this transfer.
    //

    transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
                                                   currentIrpStack->Parameters.Read.Length);

    //
    // Check if request length is greater than the maximum number of
    // bytes that the hardware can transfer.
    //

    if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
        transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {

         DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
         DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
                     maximumTransferLength));
         DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
                     currentIrpStack->Parameters.Read.Length));

         transferPages =
            deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;

         if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
             maximumTransferLength = transferPages << PAGE_SHIFT;
         }

        //
        // Check that maximum transfer size is not zero.
        //

        if (maximumTransferLength == 0) {
            maximumTransferLength = PAGE_SIZE;
        }

        //
        // Mark IRP with status pending.
        //

        IoMarkIrpPending(Irp);

        //
        // Request greater than port driver maximum.
        // Break up into smaller routines.
        //

        ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);


        return STATUS_PENDING;
    }

    //
    // Build SRB and CDB for this IRP.
    //

    ScsiClassBuildRequest(DeviceObject, Irp);

    //
    // Return the results of the call to the port driver.
    //

    return IoCallDriver(deviceExtension->PortDeviceObject, Irp);

} // end ScsiClassReadWrite()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -