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

📄 openclos.c

📁 串口Windows驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
                 SERIAL_LSR_THRE)) {

            KeDelayExecutionThread(
                KernelMode,
                FALSE,
                &charTime
                );

        }

        WRITE_TRANSMIT_HOLDING(
            extension->Controller,
            extension->SpecialChars.XonChar
            );

        //
        // Wait a reasonable amount of time for the characters
        // to be 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);
         }
    }


    //
    // The hardware is empty.  Delay 10 character times before
    // shut down all the flow control.
    //

    tenCharDelay.QuadPart = charTime.QuadPart * 10;

    KeDelayExecutionThread(
        KernelMode,
        TRUE,
        &tenCharDelay
        );

    SerialClrDTR(extension);

    //
    // We have to be very careful how we clear the RTS line.
    // Transmit toggling might have been on at some point.
    //
    // We know that there is nothing left that could start
    // out the "polling"  execution path.  We need to
    // check the counter that indicates that the execution
    // path is active.  If it is then we loop delaying one
    // character time.  After each delay we check to see if
    // the counter has gone to zero.  When it has we know that
    // the execution path should be just about finished.  We
    // make sure that we still aren't in the routine that
    // synchronized execution with the ISR by synchronizing
    // ourselve with the ISR.
    //

    if (extension->CountOfTryingToLowerRTS) {

        do {

            KeDelayExecutionThread(
                KernelMode,
                FALSE,
                &charTime
                );

        } while (extension->CountOfTryingToLowerRTS);

        KeSynchronizeExecution(
            extension->Interrupt,
            SerialNullSynch,
            NULL
            );

        //
        // The execution path should no longer exist that
        // is trying to push down the RTS.  Well just
        // make sure it's down by falling through to
        // code that forces it down.
        //

    }

    SerialClrRTS(extension);

    //
    // Clean out the holding reasons (since we are closed).
    //

    extension->RXHolding = 0;
    extension->TXHolding = 0;

    //
    // Mark device as not busy for WMI
    //

    extension->WmiCommData.IsBusy = FALSE;

    //
    // All is done.  The port has been disabled from interrupting
    // so there is no point in keeping the memory around.
    //

    extension->BufferSize = 0;
    if (extension->InterruptReadBuffer != NULL) {
       ExFreePool(extension->InterruptReadBuffer);
    }
    extension->InterruptReadBuffer = NULL;

    //
    // Stop waiting for wakeup
    //

    extension->SendWaitWake = FALSE;

    if (extension->PendingWakeIrp != NULL) {
       IoCancelIrp(extension->PendingWakeIrp);
    }

    //
    // Power down our device stack
    //
    if (!extension->RetainPowerOnClose) {
      (void)SerialGotoPowerState(DeviceObject, extension, PowerDeviceD3);
    }

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

    SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);

    //
    // Unlock the pages.  If this is the last reference to the section
    // then the driver code will be flushed out.
    //

    //
    // First, we have to let the DPC's drain.  No more should be queued
    // since we aren't taking interrupts now....
    //

    pendingDPCs = InterlockedDecrement(&extension->DpcCount);
    LOGENTRY(LOG_CNT, 'DpD7', 0, extension->DpcCount, 0);

    if (pendingDPCs) {
       SerialDbgPrintEx(SERDIAG1,"Draining DPC's: %x\n", Irp);
       KeWaitForSingleObject(&extension->PendingDpcEvent, Executive,
                             KernelMode, FALSE, NULL);
    }


    SerialDbgPrintEx(SERDIAG1, "DPC's drained: %x\n", Irp);



    //
    // Pages must be locked to release the mutex, so don't unlock
    // them until after we release the mutex
    //

    ExReleaseFastMutex(&extension->CloseMutex);

    //
    // Reset for next open
    //

    InterlockedIncrement(&extension->DpcCount);
    LOGENTRY(LOG_CNT, 'DpI6', 0, extension->DpcCount, 0);

    openCount = InterlockedDecrement(&extension->OpenCount);

    //
    // Open count may be non-zero if someone was trying to open
    // at the same time we decremented
    //

    // ASSERT(openCount == 0);

    SerialUnlockPagableImageSection(SerialGlobals.PAGESER_Handle);

    return STATUS_SUCCESS;

}


BOOLEAN
SerialCheckOpen(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine will traverse the circular doubly linked list
    of devices that are using the same interrupt object.  It will look
    for other devices that are open.  If it doesn't find any
    it will indicate that it is ok to open this device.

    If it finds another device open we have two cases:

        1) The device we are trying to open is on a multiport card.

           If the already open device is part of a multiport device
           this code will indicate it is ok to open.  We do this on the
           theory that the multiport devices are daisy chained
           and the cards can correctly arbitrate the interrupt
           line.  Note this assumption could be wrong.  Somebody
           could put two non-daisychained multiports on the
           same interrupt.  However, only a total clod would do
           such a thing, and in my opinion deserves everthing they
           get.

        2) The device we are trying to open is not on a multiport card.

            We indicate that it is not ok to open.

Arguments:

    Context - This is a structure that contains a pointer to the
              extension of the device we are trying to open, and
              a pointer to an NTSTATUS that will indicate whether
              the device was opened or not.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION extensionToOpen =
        ((PSERIAL_CHECK_OPEN)Context)->Extension;
    NTSTATUS *status = ((PSERIAL_CHECK_OPEN)Context)->StatusOfOpen;
    PLIST_ENTRY firstEntry = &extensionToOpen->CommonInterruptObject;
    PLIST_ENTRY currentEntry = firstEntry;
    PSERIAL_DEVICE_EXTENSION currentExtension;

    do {

        currentExtension = CONTAINING_RECORD(
                               currentEntry,
                               SERIAL_DEVICE_EXTENSION,
                               CommonInterruptObject
                               );

        if (currentExtension->DeviceIsOpened) {

            break;

        }

        currentEntry = currentExtension->CommonInterruptObject.Flink;

    } while (currentEntry != firstEntry);

    if (currentEntry == firstEntry) {

        //
        // We searched the whole list and found no other opens
        // mark the status as successful and call the regular
        // opening routine.
        //

        *status = STATUS_SUCCESS;
        SerialMarkOpen(extensionToOpen);

    } else {

        if (!extensionToOpen->PortOnAMultiportCard) {

            *status = STATUS_SHARED_IRQ_BUSY;

        } else {

            if (!currentExtension->PortOnAMultiportCard) {

                *status = STATUS_SHARED_IRQ_BUSY;

            } else {

                *status = STATUS_SUCCESS;
                SerialMarkOpen(extensionToOpen);

            }

        }

    }

    return FALSE;

}

BOOLEAN
SerialMarkOpen(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine merely sets a boolean to true to mark the fact that
    somebody opened the device and its worthwhile to pay attention
    to interrupts.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION extension = Context;

    SerialReset(extension);

    //
    // Prepare for the opening by re-enabling interrupts.
    //
    // We do this my modifying the OUT2 line in the modem control.
    // In PC's this bit is "anded" with the interrupt line.
    //

    WRITE_MODEM_CONTROL(
        extension->Controller,
        (UCHAR)(READ_MODEM_CONTROL(extension->Controller) | SERIAL_MCR_OUT2)
        );

    extension->DeviceIsOpened = TRUE;
    extension->ErrorWord = 0;

    return FALSE;

}


VOID
SerialDisableUART(IN PVOID Context)

/*++

Routine Description:

    This routine disables the UART and puts it in a "safe" state when
    not in use (like a close or powerdown).

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{
   PSERIAL_DEVICE_EXTENSION extension = Context;

   //
   // Prepare for the closing by stopping interrupts.
   //
   // We do this by adjusting the OUT2 line in the modem control.
   // In PC's this bit is "anded" with the interrupt line.
   //

   WRITE_MODEM_CONTROL(extension->Controller,
                       (UCHAR)(READ_MODEM_CONTROL(extension->Controller)
                               & ~SERIAL_MCR_OUT2));

   if (extension->FifoPresent) {
      WRITE_FIFO_CONTROL(extension->Controller, (UCHAR)0);
    }
}


BOOLEAN
SerialMarkClose(
    IN PVOID Context
    )

/*++

Routine Description:

    This routine merely sets a boolean to false to mark the fact that
    somebody closed the device and it's no longer worthwhile to pay attention
    to interrupts.  It also disables the UART.

Arguments:

    Context - Really a pointer to the device extension.

Return Value:

    This routine always returns FALSE.

--*/

{

    PSERIAL_DEVICE_EXTENSION extension = Context;

    SerialDisableUART(Context);

    extension->DeviceIsOpened       = FALSE;
    extension->DeviceState.Reopen   = FALSE;

    return FALSE;

}


NTSTATUS
SerialCleanup(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    This function is used to kill all longstanding IO operations.

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;
    NTSTATUS status;


    PAGED_CODE();

    //
    // We succeed a cleanup on a removing device
    //

    if ((status = SerialIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
       if (status == STATUS_DELETE_PENDING) {
          status = Irp->IoStatus.Status = STATUS_SUCCESS;
       }
       if (status != STATUS_PENDING) {
         SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
       }
       return status;
    }

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

    SerialKillPendingIrps(DeviceObject);

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

    SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);

    return STATUS_SUCCESS;

}

LARGE_INTEGER
SerialGetCharTime(
    IN PSERIAL_DEVICE_EXTENSION Extension
    )

/*++

Routine Description:

    This function will return the number of 100 nanosecond intervals
    there are in one character time (based on the present form
    of flow control.

Arguments:

    Extension - Just what it says.

Return Value:

    100 nanosecond intervals in a character time.

--*/

{

    ULONG dataSize;
    ULONG paritySize;
    ULONG stopSize;
    ULONG charTime;
    ULONG bitTime;
    LARGE_INTEGER tmp;


    if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) {
        dataSize = 5;
    } else if ((Extension->LineControl & SERIAL_DATA_MASK)
                == SERIAL_6_DATA) {
        dataSize = 6;
    } else if ((Extension->LineControl & SERIAL_DATA_MASK)
                == SERIAL_7_DATA) {
        dataSize = 7;
    } else if ((Extension->LineControl & SERIAL_DATA_MASK)
                == SERIAL_8_DATA) {
        dataSize = 8;
    }

    paritySize = 1;
    if ((Extension->LineControl & SERIAL_PARITY_MASK)
            == SERIAL_NONE_PARITY) {

        paritySize = 0;

    }

    if (Extension->LineControl & SERIAL_2_STOP) {

        //
        // Even if it is 1.5, for sanities sake were going
        // to say 2.
        //

        stopSize = 2;

    } else {

        stopSize = 1;

    }

    //
    // First we calculate the number of 100 nanosecond intervals
    // are in a single bit time (Approximately).
    //

    bitTime = (10000000+(Extension->CurrentBaud-1))/Extension->CurrentBaud;
    charTime = bitTime + ((dataSize+paritySize+stopSize)*bitTime);

    tmp.QuadPart = charTime;
    return tmp;

}

⌨️ 快捷键说明

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