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

📄 openclos.c

📁 串口Windows驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/*++

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

Module Name:

    openclos.c

Abstract:

    This module contains the code that is very specific to
    opening, closing, and cleaning up in the serial driver.

Author:

    Anthony V. Ercolano 26-Sep-1991

Environment:

    Kernel mode

--*/

#include "precomp.h"


BOOLEAN
SerialMarkOpen(
    IN PVOID Context
    );

BOOLEAN
SerialCheckOpen(
    IN PVOID Context
    );

BOOLEAN
SerialNullSynch(
    IN PVOID Context
    );

NTSTATUS
SerialCreateOpen(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );


#ifdef ALLOC_PRAGMA

//
// Paged for open and PnP transactions
//

#pragma alloc_text(PAGESER,SerialGetCharTime)
#pragma alloc_text(PAGESER,SerialCleanup)
#pragma alloc_text(PAGESER,SerialClose)
#pragma alloc_text(PAGESER, SerialCheckOpen)
#pragma alloc_text(PAGESER, SerialMarkOpen)

//
// Always paged
//

#pragma alloc_text(PAGESRP0,SerialCreateOpen)
#pragma alloc_text(PAGESRP0, SerialDrainUART)
#endif // ALLOC_PRAGMA

typedef struct _SERIAL_CHECK_OPEN {
    PSERIAL_DEVICE_EXTENSION Extension;
    NTSTATUS *StatusOfOpen;
    } SERIAL_CHECK_OPEN,*PSERIAL_CHECK_OPEN;

//
// Just a bogus little routine to make sure that we
// can synch with the ISR.
//

BOOLEAN
SerialNullSynch(
    IN PVOID Context
    ) {

    UNREFERENCED_PARAMETER(Context);
    return FALSE;
}

NTSTATUS
SerialCreateOpen(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    We connect up to the interrupt for the create/open and initialize
    the structures needed to maintain an open for a device.

Arguments:

    DeviceObject - Pointer to the device object for this device

    Irp - Pointer to the IRP for the current request

Return Value:

    The function value is the final status of the call

--*/

{

    PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
    SERIAL_CHECK_OPEN checkOpen;
    NTSTATUS localStatus;
    KIRQL oldIrql;

    PAGED_CODE();

    if (extension->PNPState != SERIAL_PNP_STARTED) {
       Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
       IoCompleteRequest(Irp, IO_NO_INCREMENT);
       return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // Lock out changes to PnP state until we have our open state decided
    //

    ExAcquireFastMutex(&extension->OpenMutex);

    if ((localStatus = SerialIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
       ExReleaseFastMutex(&extension->OpenMutex);
       if(localStatus != STATUS_PENDING) {
         SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
       }
       return localStatus;
    }

    if (InterlockedIncrement(&extension->OpenCount) != 1) {
       ExReleaseFastMutex(&extension->OpenMutex);
       InterlockedDecrement(&extension->OpenCount);
       Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
       SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
       return STATUS_ACCESS_DENIED;
    }

    SerialDbgPrintEx(SERIRPPATH, "Dispatch entry for: %x\n", Irp);

    SerialDbgPrintEx(SERDIAG3, "In SerialCreateOpen\n");

    //
    // Before we do anything, let's make sure they aren't trying
    // to create a directory. what's a driver to do!?
    //

    if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options &
        FILE_DIRECTORY_FILE) {
        ExReleaseFastMutex(&extension->OpenMutex);

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

        InterlockedDecrement(&extension->OpenCount);
        SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);

        return STATUS_NOT_A_DIRECTORY;

    }

    //
    // Create a buffer for the RX data when no reads are outstanding.
    //

    extension->InterruptReadBuffer = NULL;
    extension->BufferSize = 0;

    switch (MmQuerySystemSize()) {

        case MmLargeSystem: {

            extension->BufferSize = 4096;
            extension->InterruptReadBuffer = ExAllocatePool(
                                                 NonPagedPool,
                                                 extension->BufferSize
                                                 );

            if (extension->InterruptReadBuffer) {

                break;

            }

        }

        case MmMediumSystem: {

            extension->BufferSize = 1024;
            extension->InterruptReadBuffer = ExAllocatePool(
                                                 NonPagedPool,
                                                 extension->BufferSize
                                                 );

            if (extension->InterruptReadBuffer) {

                break;

            }

        }

        case MmSmallSystem: {

            extension->BufferSize = 128;
            extension->InterruptReadBuffer = ExAllocatePool(
                                                 NonPagedPool,
                                                 extension->BufferSize
                                                 );

        }

    }

    if (!extension->InterruptReadBuffer) {
       ExReleaseFastMutex(&extension->OpenMutex);

        extension->BufferSize = 0;
        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
        Irp->IoStatus.Information = 0;

        InterlockedDecrement(&extension->OpenCount);
        SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);

        return STATUS_INSUFFICIENT_RESOURCES;

    }

    //
    // Ok, it looks like we really are going to open.  Lock down the
    // driver.
    //

    SerialLockPagableSectionByHandle(SerialGlobals.PAGESER_Handle);

    //
    // Power up the stack
    //

    (void)SerialGotoPowerState(DeviceObject, extension, PowerDeviceD0);

    //
    // Not currently waiting for wake up
    //

    extension->SendWaitWake = FALSE;

    //
    // On a new open we "flush" the read queue by initializing the
    // count of characters.
    //

    extension->CharsInInterruptBuffer = 0;
    extension->LastCharSlot = extension->InterruptReadBuffer +
                              (extension->BufferSize - 1);

    extension->ReadBufferBase = extension->InterruptReadBuffer;
    extension->CurrentCharSlot = extension->InterruptReadBuffer;
    extension->FirstReadableChar = extension->InterruptReadBuffer;

    extension->TotalCharsQueued = 0;

    //
    // We set up the default xon/xoff limits.
    //

    extension->HandFlow.XoffLimit = extension->BufferSize >> 3;
    extension->HandFlow.XonLimit = extension->BufferSize >> 1;

    extension->WmiCommData.XoffXmitThreshold = extension->HandFlow.XoffLimit;
    extension->WmiCommData.XonXmitThreshold = extension->HandFlow.XonLimit;

    extension->BufferSizePt8 = ((3*(extension->BufferSize>>2))+
                                   (extension->BufferSize>>4));

    //
    // Mark the device as busy for WMI
    //

    extension->WmiCommData.IsBusy = TRUE;

    extension->IrpMaskLocation = NULL;
    extension->HistoryMask = 0;
    extension->IsrWaitMask = 0;

    extension->SendXonChar = FALSE;
    extension->SendXoffChar = FALSE;

#if !DBG
    //
    // Clear out the statistics.
    //

    KeSynchronizeExecution(
        extension->Interrupt,
        SerialClearStats,
        extension
        );
#endif

    //
    // The escape char replacement must be reset upon every open.
    //

    extension->EscapeChar = 0;

    if (!extension->PermitShare) {

        if (!extension->InterruptShareable) {

            checkOpen.Extension = extension;
            checkOpen.StatusOfOpen = &Irp->IoStatus.Status;

            KeSynchronizeExecution(
                extension->Interrupt,
                SerialCheckOpen,
                &checkOpen
                );

        } else {

            KeSynchronizeExecution(
                extension->Interrupt,
                SerialMarkOpen,
                extension
                );

            Irp->IoStatus.Status = STATUS_SUCCESS;

        }

    } else {

        //
        // Synchronize with the ISR and let it know that the device
        // has been successfully opened.
        //

        KeSynchronizeExecution(
            extension->Interrupt,
            SerialMarkOpen,
            extension
            );

        Irp->IoStatus.Status = STATUS_SUCCESS;

    }

    //
    // We have been marked open, so now the PnP state can change
    //

    ExReleaseFastMutex(&extension->OpenMutex);

    localStatus = Irp->IoStatus.Status;
    Irp->IoStatus.Information=0L;

    if (!NT_SUCCESS(localStatus)) {
       if (extension->InterruptReadBuffer != NULL) {
          ExFreePool(extension->InterruptReadBuffer);
          extension->InterruptReadBuffer = NULL;
       }

       InterlockedDecrement(&extension->OpenCount);
    }

    SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);

    return localStatus;

}

VOID
SerialDrainUART(IN PSERIAL_DEVICE_EXTENSION PDevExt,
                IN PLARGE_INTEGER PDrainTime)
{
   PAGED_CODE();

   //
   // Wait until all characters have been emptied out of the hardware.
   //

   while ((READ_LINE_STATUS(PDevExt->Controller) &
           (SERIAL_LSR_THRE | SERIAL_LSR_TEMT))
           != (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {

        KeDelayExecutionThread(KernelMode, FALSE, PDrainTime);
    }
}


NTSTATUS
SerialClose(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    We simply disconnect the interrupt for now.

Arguments:

    DeviceObject - Pointer to the device object for this device

    Irp - Pointer to the IRP for the current request

Return Value:

    The function value is the final status of the call

--*/

{

    //
    // This "timer value" is used to wait 10 character times
    // after the hardware is empty before we actually "run down"
    // all of the flow control/break junk.
    //
    LARGE_INTEGER tenCharDelay;

    //
    // Holds a character time.
    //
    LARGE_INTEGER charTime;

    //
    // Just what it says.  This is the serial specific device
    // extension of the device object create for the serial driver.
    //
    PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;

    NTSTATUS status;

    //
    // Number of opens still active
    //

    LONG openCount;

    //
    // Number of DPC's still pending
    //

    ULONG pendingDPCs;

    ULONG flushCount;

    KIRQL oldIrql;

    //
    // Grab a mutex
    //

    ExAcquireFastMutex(&extension->CloseMutex);


    //
    // We succeed a close on a removing device
    //

    if ((status = SerialIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
       SerialDbgPrintEx(DPFLTR_INFO_LEVEL, "Close prologue failed for: %x\n",
                        Irp);
       if (status == STATUS_DELETE_PENDING) {
             extension->BufferSize = 0;
             ExFreePool(extension->InterruptReadBuffer);
             extension->InterruptReadBuffer = NULL;
             status = Irp->IoStatus.Status = STATUS_SUCCESS;
       }

       if (status != STATUS_PENDING) {
             SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
             openCount = InterlockedDecrement(&extension->OpenCount);
             ASSERT(openCount == 0);
       }

       ExReleaseFastMutex(&extension->CloseMutex);
       return status;
    }

    ASSERT(extension->OpenCount >= 1);

    if (extension->OpenCount < 1) {
       SerialDbgPrintEx(DPFLTR_ERROR_LEVEL, "Close open count bad for: 0x%x\n",
                        Irp);
       SerialDbgPrintEx(DPFLTR_ERROR_LEVEL, "Count: %x  Addr: 0x%x\n",
                        extension->OpenCount, &extension->OpenCount);
       ExReleaseFastMutex(&extension->CloseMutex);
       Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
       SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
       return STATUS_INVALID_DEVICE_REQUEST;
    }

    SerialDbgPrintEx(SERIRPPATH, "Dispatch entry for: %x\n", Irp);
    SerialDbgPrintEx(SERDIAG3, "In SerialClose\n");

    charTime.QuadPart = -SerialGetCharTime(extension).QuadPart;

    //
    // Do this now so that if the isr gets called it won't do anything
    // to cause more chars to get sent.  We want to run down the hardware.
    //

    SetDeviceIsOpened(extension, FALSE, FALSE);

    //
    // Synchronize with the isr to turn off break if it
    // is already on.
    //

    KeSynchronizeExecution(
        extension->Interrupt,
        SerialTurnOffBreak,
        extension
        );

    //
    // Wait a reasonable amount of time (20 * fifodepth) until all characters
    // have been emptied out of the hardware.
    //

    for (flushCount = (20 * 16); flushCount != 0; flushCount--) {
       if ((READ_LINE_STATUS(extension->Controller) &
            (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) !=
           (SERIAL_LSR_THRE | SERIAL_LSR_TEMT)) {

          KeDelayExecutionThread(KernelMode, FALSE, &charTime);
      } else {
         break;
      }
    }

    if (flushCount == 0) {
       SerialMarkHardwareBroken(extension);
    }

    //
    // Synchronize with the ISR to let it know that interrupts are
    // no longer important.
    //

    KeSynchronizeExecution(
        extension->Interrupt,
        SerialMarkClose,
        extension
        );


    //
    // If the driver has automatically transmitted an Xoff in
    // the context of automatic receive flow control then we
    // should transmit an Xon.
    //

    if (extension->RXHolding & SERIAL_RX_XOFF) {

        //
        // Loop until the holding register is empty.
        //

        while (!(READ_LINE_STATUS(extension->Controller) &

⌨️ 快捷键说明

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