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

📄 initunlo.c

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

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

Module Name:

    initunlo.c

Abstract:

    This module contains the code that is very specific to initialization
    and unload operations in the serial driver

Author:

    Anthony V. Ercolano 26-Sep-1991

Environment:

    Kernel mode

--*/

#include "precomp.h"

//
// All our global variables except DebugLevel stashed in one
// little package
//
SERIAL_GLOBALS SerialGlobals;

static const PHYSICAL_ADDRESS SerialPhysicalZero = {0};

//
// We use this to query into the registry as to whether we
// should break at driver entry.
//

SERIAL_FIRMWARE_DATA    driverDefaults;

//
// This is exported from the kernel.  It is used to point
// to the address that the kernel debugger is using.
//
extern PUCHAR *KdComPortInUse;

//
// INIT - only needed during init and then can be disposed
// PAGESRP0 - always paged / never locked
// PAGESER - must be locked when a device is open, else paged
//
//
// INIT is used for DriverEntry() specific code
//
// PAGESRP0 is used for code that is not often called and has nothing
// to do with I/O performance.  An example, IRP_MJ_PNP/IRP_MN_START_DEVICE
// support functions
//
// PAGESER is used for code that needs to be locked after an open for both
// performance and IRQL reasons.
//

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)

#pragma alloc_text(PAGESRP0, SerialInitMultiPort)
#pragma alloc_text(PAGESRP0, SerialInitOneController)
#pragma alloc_text(PAGESRP0, SerialInitController)
#pragma alloc_text(PAGESRP0, SerialGetMappedAddress)
#pragma alloc_text(PAGESRP0, SerialRemoveDevObj)
#pragma alloc_text(PAGESRP0, SerialUnload)
#pragma alloc_text(PAGESRP0, SerialMemCompare)


//
// PAGESER handled is keyed off of SerialReset, so SerialReset
// must remain in PAGESER for things to work properly
//

#pragma alloc_text(PAGESER, SerialGetDivisorFromBaud)
#pragma alloc_text(PAGESER, SerialReset)
#endif


NTSTATUS
DriverEntry(
           IN PDRIVER_OBJECT DriverObject,
           IN PUNICODE_STRING RegistryPath
           )

/*++

Routine Description:

    The entry point that the system point calls to initialize
    any driver.

    This routine will gather the configuration information,
    report resource usage, attempt to initialize all serial
    devices, connect to interrupts for ports.  If the above
    goes reasonably well it will fill in the dispatch points,
    reset the serial devices and then return to the system.

Arguments:

    DriverObject - Just what it says,  really of little use
    to the driver itself, it is something that the IO system
    cares more about.

    PathToRegistry - points to the entry for this driver
    in the current control set of the registry.

Return Value:

    Always STATUS_SUCCESS

--*/

{
   //
   // Lock the paged code in their frames
   //

   PVOID lockPtr = MmLockPagableCodeSection(SerialReset);

   PAGED_CODE();


   ASSERT(SerialGlobals.PAGESER_Handle == NULL);
#if DBG
   SerialGlobals.PAGESER_Count = 0;
   SerialLogInit();
#endif
   SerialGlobals.PAGESER_Handle = lockPtr;

   SerialGlobals.RegistryPath.MaximumLength = RegistryPath->MaximumLength;
   SerialGlobals.RegistryPath.Length = RegistryPath->Length;
   SerialGlobals.RegistryPath.Buffer
      = ExAllocatePool(PagedPool, SerialGlobals.RegistryPath.MaximumLength);

   if (SerialGlobals.RegistryPath.Buffer == NULL) {
      MmUnlockPagableImageSection(lockPtr);
      return STATUS_INSUFFICIENT_RESOURCES;
   }

   RtlZeroMemory(SerialGlobals.RegistryPath.Buffer,
                 SerialGlobals.RegistryPath.MaximumLength);
   RtlMoveMemory(SerialGlobals.RegistryPath.Buffer,
                 RegistryPath->Buffer, RegistryPath->Length);

   KeInitializeSpinLock(&SerialGlobals.GlobalsSpinLock);

   //
   // Initialize all our globals
   //

   InitializeListHead(&SerialGlobals.AllDevObjs);

   //
   // Call to find out default values to use for all the devices that the
   // driver controls, including whether or not to break on entry.
   //

   SerialGetConfigDefaults(&driverDefaults, RegistryPath);

   //
   // Break on entry if requested via registry
   //

   if (driverDefaults.ShouldBreakOnEntry) {
      DbgBreakPoint();
   }


   //
   // Just dump out how big the extension is.
   //

   SerialDbgPrintEx(DPFLTR_INFO_LEVEL, "The number of bytes in the extension "
                    "is: %d\n", sizeof(SERIAL_DEVICE_EXTENSION));


   //
   // Initialize the Driver Object with driver's entry points
   //

   DriverObject->DriverUnload                          = SerialUnload;
   DriverObject->DriverExtension->AddDevice            = SerialAddDevice;

   DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]   = SerialFlush;
   DriverObject->MajorFunction[IRP_MJ_WRITE]           = SerialWrite;
   DriverObject->MajorFunction[IRP_MJ_READ]            = SerialRead;
   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = SerialIoControl;
   DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]
      = SerialInternalIoControl;
   DriverObject->MajorFunction[IRP_MJ_CREATE]          = SerialCreateOpen;
   DriverObject->MajorFunction[IRP_MJ_CLOSE]           = SerialClose;
   DriverObject->MajorFunction[IRP_MJ_CLEANUP]         = SerialCleanup;
   DriverObject->MajorFunction[IRP_MJ_PNP]             = SerialPnpDispatch;
   DriverObject->MajorFunction[IRP_MJ_POWER]           = SerialPowerDispatch;

   DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]
      = SerialQueryInformationFile;
   DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]
      = SerialSetInformationFile;

   DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]
      = SerialSystemControlDispatch;


#if !defined(NO_LEGACY_DRIVERS)

#define SerialDoLegacyConversion() (~0)

   //
   // Enumerate and Initialize legacy devices if necessary.  This should go away
   // and be done by setup.
   //

   if (SerialDoLegacyConversion()) {
#if DBG
      InterlockedIncrement(&SerialGlobals.PAGESER_Count);
#endif
      (void)SerialEnumerateLegacy(DriverObject, RegistryPath, &driverDefaults);
#if DBG
      InterlockedDecrement(&SerialGlobals.PAGESER_Count);
#endif
   }
#endif // NO_LEGACY_DRIVERS

   //
   // Unlock pageable text
   //
   MmUnlockPagableImageSection(lockPtr);

   return STATUS_SUCCESS;
}




BOOLEAN
SerialCleanLists(IN PVOID Context)
/*++

Routine Description:

    Removes a device object from any of the serial linked lists it may
    appear on.

Arguments:

    Context - Actually a PSERIAL_DEVICE_EXTENSION (for the devobj being
              removed).

Return Value:

    Always TRUE

--*/
{
   PSERIAL_DEVICE_EXTENSION pDevExt = (PSERIAL_DEVICE_EXTENSION)Context;
   KIRQL oldIrql;

    //
    // If we are a multiport device, remove our entry
    //

    if (pDevExt->PortOnAMultiportCard) {
       PSERIAL_MULTIPORT_DISPATCH pDispatch
          = (PSERIAL_MULTIPORT_DISPATCH)pDevExt->OurIsrContext;

       SerialDbgPrintEx(SERPNPPOWER, "SERIAL: CLEAN: removing multiport isr "
                        "ext\n");

       pDispatch->Extensions[pDevExt->PortIndex - 1] = NULL;

       if (pDevExt->Indexed == FALSE) {
          pDispatch->UsablePortMask &= ~(1 << (pDevExt->PortIndex - 1));
          pDispatch->MaskInverted &= ~(pDevExt->NewMaskInverted);
       }
    }

   if (!IsListEmpty(&pDevExt->TopLevelSharers)) {

      SerialDbgPrintEx(SERPNPPOWER, "SERIAL: CLEAN: removing multiport isr ext"
                       "\n");
      SerialDbgPrintEx(SERPNPPOWER, "SERIAL: CLEAN: Device is a sharer\n");

      //
      // If we have siblings, the first becomes the sharer
      //

      if (!IsListEmpty(&pDevExt->MultiportSiblings)) {
         PSERIAL_DEVICE_EXTENSION pNewRoot;

         SerialDbgPrintEx(SERPNPPOWER, "CLEAN: Transferring to siblings\n");

         pNewRoot = CONTAINING_RECORD(pDevExt->MultiportSiblings.Flink,
                                      SERIAL_DEVICE_EXTENSION,
                                      MultiportSiblings);

         //
         // He should not be on there already
         //

         ASSERT(IsListEmpty(&pNewRoot->TopLevelSharers));
         InsertTailList(&pDevExt->TopLevelSharers, &pNewRoot->TopLevelSharers);

      }

      //
      // Remove ourselves
      //

      RemoveEntryList(&pDevExt->TopLevelSharers);
      InitializeListHead(&pDevExt->TopLevelSharers);

      //
      // Now check the master list to see if anyone is left...
      //

      if (!IsListEmpty(&pDevExt->CIsrSw->SharerList)) {
         //
         // Others are chained on this interrupt, so we don't want to
         // disconnect it.
         //

         pDevExt->Interrupt = NULL;
      }
   }

   //
   // If this is part of a multiport board and we still have
   // siblings, remove us from that list
   //

   if (!IsListEmpty(&pDevExt->MultiportSiblings)) {
      SerialDbgPrintEx(SERPNPPOWER, "CLEAN: Has multiport siblings\n");
      RemoveEntryList(&pDevExt->MultiportSiblings);
      InitializeListHead(&pDevExt->MultiportSiblings);
   }


   if (!IsListEmpty(&pDevExt->CommonInterruptObject)) {

      SerialDbgPrintEx(SERPNPPOWER, "CLEAN: Common intobj member\n");

      RemoveEntryList(&pDevExt->CommonInterruptObject);
      InitializeListHead(&pDevExt->CommonInterruptObject);

      //
      // Others are sharing this interrupt object so we detach ourselves
      // from it this way instead of disconnecting.
      //

      pDevExt->Interrupt = NULL;
   }

   return TRUE;
}



VOID
SerialReleaseResources(IN PSERIAL_DEVICE_EXTENSION PDevExt)
/*++

Routine Description:

    Releases resources (not pool) stored in the device extension.

Arguments:

    PDevExt - Pointer to the device extension to release resources from.

Return Value:

    VOID

--*/
{
   KIRQL oldIrql;

   SerialDbgPrintEx(DPFLTR_TRACE_LEVEL, ">SerialReleaseResources(%X)\n",
                    PDevExt);

   //
   // Remove us from any lists we may be on
   //

   if (PDevExt->Interrupt != NULL) {
      KeSynchronizeExecution(PDevExt->Interrupt, SerialCleanLists, PDevExt);

      //
      // AllDevObjs should never be empty since we have a sentinal
      //

      KeAcquireSpinLock(&SerialGlobals.GlobalsSpinLock, &oldIrql);

      ASSERT(!IsListEmpty(&PDevExt->AllDevObjs));

      RemoveEntryList(&PDevExt->AllDevObjs);

      KeReleaseSpinLock(&SerialGlobals.GlobalsSpinLock, oldIrql);

      InitializeListHead(&PDevExt->AllDevObjs);
   }

   //
   // SerialCleanLists can remove our interrupt from us...
   //

   if (PDevExt->Interrupt != NULL) {
      //
      // Stop servicing interrupts if we are the owner
      //

      SerialDbgPrintEx(SERPNPPOWER, "Release - disconnecting interrupt %X\n",
                       PDevExt->Interrupt);

      IoDisconnectInterrupt(PDevExt->Interrupt);
      PDevExt->Interrupt = NULL;

      if (PDevExt->CIsrSw != NULL) {
         ExFreePool(PDevExt->CIsrSw);
         PDevExt->CIsrSw = NULL;
      }
   }

   if (PDevExt->PortOnAMultiportCard) {
       ULONG i;

       //
       // If we are the last device, free this memory
       //

       for (i = 0; i < SERIAL_MAX_PORTS_INDEXED; i++) {
          if (((PSERIAL_MULTIPORT_DISPATCH)PDevExt->OurIsrContext)
              ->Extensions[i] != NULL) {
             break;
          }
       }

       if (i == SERIAL_MAX_PORTS_INDEXED) {
          SerialDbgPrintEx(SERPNPPOWER, "Release - freeing multi context\n");
          ExFreePool(PDevExt->OurIsrContext);
       }
    }


   //
   // Stop handling timers
   //

   SerialCancelTimer(&PDevExt->ReadRequestTotalTimer, PDevExt);
   SerialCancelTimer(&PDevExt->ReadRequestIntervalTimer, PDevExt);
   SerialCancelTimer(&PDevExt->WriteRequestTotalTimer, PDevExt);
   SerialCancelTimer(&PDevExt->ImmediateTotalTimer, PDevExt);
   SerialCancelTimer(&PDevExt->XoffCountTimer, PDevExt);
   SerialCancelTimer(&PDevExt->LowerRTSTimer, PDevExt);

   //
   // Stop servicing DPC's
   //

   SerialRemoveQueueDpc(&PDevExt->CompleteWriteDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->CompleteReadDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->TotalReadTimeoutDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->IntervalReadTimeoutDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->TotalWriteTimeoutDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->CommErrorDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->CompleteImmediateDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->TotalImmediateTimeoutDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->CommWaitDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->XoffCountTimeoutDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->XoffCountCompleteDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->StartTimerLowerRTSDpc, PDevExt);
   SerialRemoveQueueDpc(&PDevExt->PerhapsLowerRTSDpc, PDevExt);


⌨️ 快捷键说明

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