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

📄 read.c

📁 怎样在win2000下构造驱动程序znsoft_Serial2000_demo.ZIP
💻 C
📖 第 1 页 / 共 4 页
字号:
/*++

Copyright (c) 1991, 1992, 1993 - 1997 Microsoft Corporation

Module Name:

    read.c

Abstract:

    This module contains the code that is very specific to read
    operations in the serial driver

Author:

    Anthony V. Ercolano 26-Sep-1991

Environment:

    Kernel mode

--*/

#include "precomp.h"


VOID
SerialCancelCurrentRead(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    );

BOOLEAN
SerialGrabReadFromIsr(
    IN PVOID Context
    );

BOOLEAN
SerialUpdateReadByIsr(
    IN PVOID Context
    );

ULONG
SerialGetCharsFromIntBuffer(
    PSERIAL_DEVICE_EXTENSION Extension
    );

BOOLEAN
SerialUpdateInterruptBuffer(
    IN PVOID Context
    );

BOOLEAN
SerialUpdateAndSwitchToUser(
    IN PVOID Context
    );

NTSTATUS
SerialResizeBuffer(
    IN PSERIAL_DEVICE_EXTENSION Extension
    );

ULONG
SerialMoveToNewIntBuffer(
    PSERIAL_DEVICE_EXTENSION Extension,
    PUCHAR NewBuffer
    );

BOOLEAN
SerialUpdateAndSwitchToNew(
    IN PVOID Context
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGESER,SerialRead)
#pragma alloc_text(PAGESER,SerialStartRead)
#pragma alloc_text(PAGESER,SerialCancelCurrentRead)
#pragma alloc_text(PAGESER,SerialGrabReadFromIsr)
#pragma alloc_text(PAGESER,SerialUpdateReadByIsr)
#pragma alloc_text(PAGESER,SerialGetCharsFromIntBuffer)
#pragma alloc_text(PAGESER,SerialUpdateInterruptBuffer)
#pragma alloc_text(PAGESER,SerialUpdateAndSwitchToUser)
#pragma alloc_text(PAGESER,SerialResizeBuffer)
#pragma alloc_text(PAGESER,SerialMoveToNewIntBuffer)
#pragma alloc_text(PAGESER,SerialUpdateAndSwitchToNew)
#endif


NTSTATUS
SerialRead(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the dispatch routine for reading.  It validates the parameters
    for the read request and if all is ok then it places the request
    on the work queue.

Arguments:

    DeviceObject - Pointer to the device object for this device

    Irp - Pointer to the IRP for the current request

Return Value:

    If the io is zero length then it will return STATUS_SUCCESS,
    otherwise this routine will return the status returned by
    the actual start read routine.

--*/

{

    PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
    BOOLEAN acceptingIRPs;
    NTSTATUS status;

    SERIAL_LOCKED_PAGED_CODE();

    SerialDump(SERTRACECALLS, ("SERIAL: Entering SerialRead\n"));

    if ((status = SerialIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
      SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
      SerialDump(SERTRACECALLS, ("SERIAL: Leaving SerialRead (1)\n"));
      return status;
    }

    SerialDump(
        SERIRPPATH,
        ("SERIAL: Dispatch entry for: %x\n",Irp)
        );
    if (SerialCompleteIfError(
            DeviceObject,
            Irp
            ) != STATUS_SUCCESS) {


       SerialDump(SERTRACECALLS, ("SERIAL: Leaving SerialRead (2)\n"));

        return STATUS_CANCELLED;

    }

    Irp->IoStatus.Information = 0L;

    //
    // Quick check for a zero length read.  If it is zero length
    // then we are already done!
    //

    if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length) {

        //
        // Well it looks like we actually have to do some
        // work.  Put the read on the queue so that we can
        // process it when our previous reads are done.
        //


       SerialDump(SERTRACECALLS, ("SERIAL: Leaving SerialRead (3)\n"));
        return SerialStartOrQueue(
                   extension,
                   Irp,
                   &extension->ReadQueue,
                   &extension->CurrentReadIrp,
                   SerialStartRead
                   );

    } else {

        Irp->IoStatus.Status = STATUS_SUCCESS;
        SerialDump(
            SERIRPPATH,
            ("SERIAL: Complete Irp: %x\n",Irp)
            );
        SerialCompleteRequest(extension, Irp, 0);


        SerialDump(SERTRACECALLS, ("SERIAL: Leaving SerialRead (4)\n"));

        return STATUS_SUCCESS;

    }

}

NTSTATUS
SerialStartRead(
    IN PSERIAL_DEVICE_EXTENSION Extension
    )

/*++

Routine Description:

    This routine is used to start off any read.  It initializes
    the Iostatus fields of the irp.  It will set up any timers
    that are used to control the read.  It will attempt to complete
    the read from data already in the interrupt buffer.  If the
    read can be completed quickly it will start off another if
    necessary.

Arguments:

    Extension - Simply a pointer to the serial device extension.

Return Value:

    This routine will return the status of the first read
    irp.  This is useful in that if we have a read that can
    complete right away (AND there had been nothing in the
    queue before it) the read could return SUCCESS and the
    application won't have to do a wait.

--*/

{

    SERIAL_UPDATE_CHAR updateChar;

    PIRP newIrp;
    KIRQL oldIrql;
    KIRQL controlIrql;

    BOOLEAN returnWithWhatsPresent;
    BOOLEAN os2ssreturn;
    BOOLEAN crunchDownToOne;
    BOOLEAN useTotalTimer;
    BOOLEAN useIntervalTimer;

    ULONG multiplierVal;
    ULONG constantVal;

    LARGE_INTEGER totalTime;

    SERIAL_TIMEOUTS timeoutsForIrp;

    BOOLEAN setFirstStatus = FALSE;
    NTSTATUS firstStatus;

    SERIAL_LOCKED_PAGED_CODE();


    SerialDump(SERTRACECALLS, ("SERIAL: SerialStartRead\n"));

    updateChar.Extension = Extension;

    do {

        //
        // Check to see if this is a resize request.  If it is
        // then go to a routine that specializes in that.
        //

        if (IoGetCurrentIrpStackLocation(Extension->CurrentReadIrp)
            ->MajorFunction != IRP_MJ_READ) {

            NTSTATUS localStatus = SerialResizeBuffer(Extension);

            if (!setFirstStatus) {

                firstStatus = localStatus;
                setFirstStatus = TRUE;

            }

        } else {

            Extension->NumberNeededForRead =
                IoGetCurrentIrpStackLocation(Extension->CurrentReadIrp)
                    ->Parameters.Read.Length;

            //
            // Calculate the timeout value needed for the
            // request.  Note that the values stored in the
            // timeout record are in milliseconds.
            //

            useTotalTimer = FALSE;
            returnWithWhatsPresent = FALSE;
            os2ssreturn = FALSE;
            crunchDownToOne = FALSE;
            useIntervalTimer = FALSE;

            //
            //
            // CIMEXCIMEX -- this is a lie
            //
            // Always initialize the timer objects so that the
            // completion code can tell when it attempts to
            // cancel the timers whether the timers had ever
            // been Set.
            //
            // CIMEXCIMEX -- this is the truth
            //
            // What we want to do is just make sure the timers are
            // cancelled to the best of our ability and move on with
            // life.
            //

            SerialCancelTimer(&Extension->ReadRequestTotalTimer, Extension);
            SerialCancelTimer(&Extension->ReadRequestIntervalTimer, Extension);


//            KeInitializeTimer(&Extension->ReadRequestTotalTimer);
//            KeInitializeTimer(&Extension->ReadRequestIntervalTimer);

            //
            // We get the *current* timeout values to use for timing
            // this read.
            //

            KeAcquireSpinLock(
                &Extension->ControlLock,
                &controlIrql
                );

            timeoutsForIrp = Extension->Timeouts;

            KeReleaseSpinLock(
                &Extension->ControlLock,
                controlIrql
                );

            //
            // Calculate the interval timeout for the read.
            //

            if (timeoutsForIrp.ReadIntervalTimeout &&
                (timeoutsForIrp.ReadIntervalTimeout !=
                 MAXULONG)) {

                useIntervalTimer = TRUE;

                Extension->IntervalTime.QuadPart =
                    UInt32x32To64(
                        timeoutsForIrp.ReadIntervalTimeout,
                        10000
                        );


                if (Extension->IntervalTime.QuadPart >=
                    Extension->CutOverAmount.QuadPart) {

                    Extension->IntervalTimeToUse =
                        &Extension->LongIntervalAmount;

                } else {

                    Extension->IntervalTimeToUse =
                        &Extension->ShortIntervalAmount;

                }

            }

            if (timeoutsForIrp.ReadIntervalTimeout == MAXULONG) {

                //
                // We need to do special return quickly stuff here.
                //
                // 1) If both constant and multiplier are
                //    0 then we return immediately with whatever
                //    we've got, even if it was zero.
                //
                // 2) If constant and multiplier are not MAXULONG
                //    then return immediately if any characters
                //    are present, but if nothing is there, then
                //    use the timeouts as specified.
                //
                // 3) If multiplier is MAXULONG then do as in
                //    "2" but return when the first character
                //    arrives.
                //

                if (!timeoutsForIrp.ReadTotalTimeoutConstant &&
                    !timeoutsForIrp.ReadTotalTimeoutMultiplier) {

                    returnWithWhatsPresent = TRUE;

                } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)
                            &&
                           (timeoutsForIrp.ReadTotalTimeoutMultiplier
                            != MAXULONG)) {

                    useTotalTimer = TRUE;
                    os2ssreturn = TRUE;
                    multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;
                    constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;

                } else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)
                            &&
                           (timeoutsForIrp.ReadTotalTimeoutMultiplier
                            == MAXULONG)) {

                    useTotalTimer = TRUE;
                    os2ssreturn = TRUE;
                    crunchDownToOne = TRUE;
                    multiplierVal = 0;
                    constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;

                }

            } else {

                //
                // If both the multiplier and the constant are
                // zero then don't do any total timeout processing.
                //

                if (timeoutsForIrp.ReadTotalTimeoutMultiplier ||
                    timeoutsForIrp.ReadTotalTimeoutConstant) {

                    //
                    // We have some timer values to calculate.
                    //

                    useTotalTimer = TRUE;
                    multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;
                    constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;

                }

            }

            if (useTotalTimer) {

                totalTime.QuadPart = ((LONGLONG)(UInt32x32To64(
                                          Extension->NumberNeededForRead,
                                          multiplierVal
                                          )
                                          + constantVal))
                                      * -10000;

            }


            //
            // We do this copy in the hope of getting most (if not
            // all) of the characters out of the interrupt buffer.
            //
            // Note that we need to protect this operation with a
            // spinlock since we don't want a purge to hose us.
            //

            KeAcquireSpinLock(
                &Extension->ControlLock,
                &controlIrql
                );

            updateChar.CharsCopied = SerialGetCharsFromIntBuffer(Extension);

            //
            // See if we have any cause to return immediately.
            //

            if (returnWithWhatsPresent || (!Extension->NumberNeededForRead) ||
                (os2ssreturn &&
                 Extension->CurrentReadIrp->IoStatus.Information)) {

                //
                // We got all we needed for this read.
                // Update the number of characters in the
                // interrupt read buffer.
                //

                KeSynchronizeExecution(
                    Extension->Interrupt,
                    SerialUpdateInterruptBuffer,
                    &updateChar
                    );

                KeReleaseSpinLock(
                    &Extension->ControlLock,
                    controlIrql
                    );

                Extension->CurrentReadIrp->IoStatus.Status = STATUS_SUCCESS;
                if (!setFirstStatus) {

                    firstStatus = STATUS_SUCCESS;
                    setFirstStatus = TRUE;

⌨️ 快捷键说明

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