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

📄 initunlo.c

📁 串口Windows驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
      = (PSERIAL_DEVICE_EXTENSION)PDevExt->OurIsrContext;
   PSERIAL_DEVICE_EXTENSION pNewExt
      = (PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension;
   NTSTATUS status;
   PSERIAL_MULTIPORT_DISPATCH pDispatch;

   PAGED_CODE();


   SerialDbgPrintEx(DPFLTR_TRACE_LEVEL, ">SerialInitMultiPort(%X, %X, %X)\n",
                    PDevExt, PConfigData, PDevObj);

   //
   // Allow him to share our CISRsw and interrupt object
   //

   pNewExt->CIsrSw = PDevExt->CIsrSw;
   pNewExt->Interrupt = PDevExt->Interrupt;

   //
   // First, see if we can initialize the one we have found
   //

   status = SerialInitOneController(PDevObj, PConfigData);

   if (!NT_SUCCESS(status)) {
      SerialDbgPrintEx(DPFLTR_TRACE_LEVEL, "<SerialInitMultiPort (1) %X\n",
                       status);
      return status;
   }

   //
   // OK.  He's good to go.  Find the root controller.  He may
   // currently be a single, so we have to change him to multi.
   //

   if (PDevExt->PortOnAMultiportCard != TRUE) {

      pDispatch = PDevExt->NewExtension
         = ExAllocatePool(NonPagedPool, sizeof(SERIAL_MULTIPORT_DISPATCH));

      if (pDispatch == NULL) {
         // FAIL and CLEANUP
         status = STATUS_INSUFFICIENT_RESOURCES;

         SerialDbgPrintEx(DPFLTR_TRACE_LEVEL, "<SerialInitMultiPort (2) %X\n",
                          status);
         return status;
      }

      RtlZeroMemory(pDispatch, sizeof(*pDispatch));
      KeSynchronizeExecution(PDevExt->Interrupt, SerialSingleToMulti, PDevExt);
   }

   //
   // Update some important fields
   //

   ((PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension)->PortOnAMultiportCard
      = TRUE;
   ((PSERIAL_DEVICE_EXTENSION)PDevObj->DeviceExtension)->OurIsr = NULL;


   PDevExt->NewPortIndex = PConfigData->PortIndex;
   PDevExt->NewMaskInverted = PConfigData->MaskInverted;
   PDevExt->NewExtension = PDevObj->DeviceExtension;

   //
   // Now, we can add the new guy.  He will be hooked in
   // immediately, so we need to be able to handle interrupts.
   //

   KeSynchronizeExecution(PDevExt->Interrupt, SerialAddToMulti, PDevExt);

   SerialDbgPrintEx(DPFLTR_TRACE_LEVEL, "<SerialInitMultiPort (3) %X\n",
                    STATUS_SUCCESS);

   return STATUS_SUCCESS;
}



NTSTATUS
SerialInitController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfigData)

/*++

Routine Description:

    Really too many things to mention here.  In general initializes
    kernel synchronization structures, allocates the typeahead buffer,
    sets up defaults, etc.

Arguments:

    PDevObj       - Device object for the device to be started

    PConfigData   - Pointer to a record for a single port.

Return Value:

    STATUS_SUCCCESS if everything went ok.  A !NT_SUCCESS status
    otherwise.

--*/

{

   PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;

   //
   // This will hold the string that we need to use to describe
   // the name of the device to the IO system.
   //

   UNICODE_STRING uniNameString;

   //
   // Holds the NT Status that is returned from each call to the
   // kernel and executive.
   //

   NTSTATUS status = STATUS_SUCCESS;

   //
   // Indicates that a conflict was detected for resources
   // used by this device.
   //

   BOOLEAN conflictDetected = FALSE;

   //
   // Indicates if we allocated an ISR switch
   //

   BOOLEAN allocedISRSw = FALSE;
   KIRQL   oldIrql;

   PAGED_CODE();


   SerialDbgPrintEx(SERDIAG1, "Initializing for configuration record of %wZ\n",
                    &pDevExt->DeviceName);

   //
   // This compare is done using **untranslated** values since that is what
   // the kernel shoves in regardless of the architecture.
   //

   if ((*KdComPortInUse) == (ULongToPtr(PConfigData->Controller.LowPart))) {
      SerialDbgPrintEx(DPFLTR_ERROR_LEVEL, "Kernel debugger is using port at "
                       "address %X\n", *KdComPortInUse);
      SerialDbgPrintEx(DPFLTR_ERROR_LEVEL, "Serial driver will not load port"
                       "\n");

      SerialLogError(
                    PDevObj->DriverObject,
                    NULL,
                    PConfigData->TrController,
                    SerialPhysicalZero,
                    0,
                    0,
                    0,
                    3,
                    STATUS_SUCCESS,
                    SERIAL_KERNEL_DEBUGGER_ACTIVE,
                    pDevExt->DeviceName.Length+sizeof(WCHAR),
                    pDevExt->DeviceName.Buffer,
                    0,
                    NULL
                    );

      return STATUS_INSUFFICIENT_RESOURCES;
   }


   if (pDevExt->CIsrSw == NULL) {
      if ((pDevExt->CIsrSw
           = ExAllocatePool(NonPagedPool, sizeof(SERIAL_CISR_SW))) == NULL) {
         return STATUS_INSUFFICIENT_RESOURCES;
      }

      InitializeListHead(&pDevExt->CIsrSw->SharerList);

      allocedISRSw = TRUE;
   }


   //
   // Initialize the timers used to timeout operations.
   //

   KeInitializeTimer(&pDevExt->ReadRequestTotalTimer);
   KeInitializeTimer(&pDevExt->ReadRequestIntervalTimer);
   KeInitializeTimer(&pDevExt->WriteRequestTotalTimer);
   KeInitializeTimer(&pDevExt->ImmediateTotalTimer);
   KeInitializeTimer(&pDevExt->XoffCountTimer);
   KeInitializeTimer(&pDevExt->LowerRTSTimer);


   //
   // Intialialize the dpcs that will be used to complete
   // or timeout various IO operations.
   //

   KeInitializeDpc(&pDevExt->CompleteWriteDpc, SerialCompleteWrite, pDevExt);
   KeInitializeDpc(&pDevExt->CompleteReadDpc, SerialCompleteRead, pDevExt);
   KeInitializeDpc(&pDevExt->TotalReadTimeoutDpc, SerialReadTimeout, pDevExt);
   KeInitializeDpc(&pDevExt->IntervalReadTimeoutDpc, SerialIntervalReadTimeout,
                   pDevExt);
   KeInitializeDpc(&pDevExt->TotalWriteTimeoutDpc, SerialWriteTimeout, pDevExt);
   KeInitializeDpc(&pDevExt->CommErrorDpc, SerialCommError, pDevExt);
   KeInitializeDpc(&pDevExt->CompleteImmediateDpc, SerialCompleteImmediate,
                   pDevExt);
   KeInitializeDpc(&pDevExt->TotalImmediateTimeoutDpc, SerialTimeoutImmediate,
                   pDevExt);
   KeInitializeDpc(&pDevExt->CommWaitDpc, SerialCompleteWait, pDevExt);
   KeInitializeDpc(&pDevExt->XoffCountTimeoutDpc, SerialTimeoutXoff, pDevExt);
   KeInitializeDpc(&pDevExt->XoffCountCompleteDpc, SerialCompleteXoff, pDevExt);
   KeInitializeDpc(&pDevExt->StartTimerLowerRTSDpc, SerialStartTimerLowerRTS,
                   pDevExt);
   KeInitializeDpc(&pDevExt->PerhapsLowerRTSDpc, SerialInvokePerhapsLowerRTS,
                   pDevExt);
   KeInitializeDpc(&pDevExt->IsrUnlockPagesDpc, SerialUnlockPages, pDevExt);

#if 0 // DBG
   //
   // Init debug stuff
   //

   pDevExt->DpcQueued[0].Dpc = &pDevExt->CompleteWriteDpc;
   pDevExt->DpcQueued[1].Dpc = &pDevExt->CompleteReadDpc;
   pDevExt->DpcQueued[2].Dpc = &pDevExt->TotalReadTimeoutDpc;
   pDevExt->DpcQueued[3].Dpc = &pDevExt->IntervalReadTimeoutDpc;
   pDevExt->DpcQueued[4].Dpc = &pDevExt->TotalWriteTimeoutDpc;
   pDevExt->DpcQueued[5].Dpc = &pDevExt->CommErrorDpc;
   pDevExt->DpcQueued[6].Dpc = &pDevExt->CompleteImmediateDpc;
   pDevExt->DpcQueued[7].Dpc = &pDevExt->TotalImmediateTimeoutDpc;
   pDevExt->DpcQueued[8].Dpc = &pDevExt->CommWaitDpc;
   pDevExt->DpcQueued[9].Dpc = &pDevExt->XoffCountTimeoutDpc;
   pDevExt->DpcQueued[10].Dpc = &pDevExt->XoffCountCompleteDpc;
   pDevExt->DpcQueued[11].Dpc = &pDevExt->StartTimerLowerRTSDpc;
   pDevExt->DpcQueued[12].Dpc = &pDevExt->PerhapsLowerRTSDpc;
   pDevExt->DpcQueued[13].Dpc = &pDevExt->IsrUnlockPagesDpc;

#endif

   //
   // Save the value of clock input to the part.  We use this to calculate
   // the divisor latch value.  The value is in Hertz.
   //

   pDevExt->ClockRate = PConfigData->ClockRate;


   //
   // Save if we have to enable TI's auto flow control
   //


   pDevExt->TL16C550CAFC = PConfigData->TL16C550CAFC;


   //
   // Map the memory for the control registers for the serial device
   // into virtual memory.
   //
   pDevExt->Controller =
      SerialGetMappedAddress(PConfigData->InterfaceType,
                             PConfigData->BusNumber,
                             PConfigData->TrController,
                             PConfigData->SpanOfController,
                             (BOOLEAN)PConfigData->AddressSpace,
                             &pDevExt->UnMapRegisters);

   if (!pDevExt->Controller) {

      SerialLogError(
                    PDevObj->DriverObject,
                    pDevExt->DeviceObject,
                    PConfigData->TrController,
                    SerialPhysicalZero,
                    0,
                    0,
                    0,
                    7,
                    STATUS_SUCCESS,
                    SERIAL_REGISTERS_NOT_MAPPED,
                    pDevExt->DeviceName.Length+sizeof(WCHAR),
                    pDevExt->DeviceName.Buffer,
                    0,
                    NULL
                    );

      SerialDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map memory for device "
                       "registers for %wZ\n", &pDevExt->DeviceName);

      pDevExt->UnMapRegisters = FALSE;
      status = STATUS_NONE_MAPPED;
      goto ExtensionCleanup;

   }

   pDevExt->AddressSpace          = PConfigData->AddressSpace;
   pDevExt->OriginalController    = PConfigData->Controller;
   pDevExt->SpanOfController      = PConfigData->SpanOfController;


   //
   // if we have an interrupt status then map it.
   //

   pDevExt->InterruptStatus =
      (PUCHAR)PConfigData->TrInterruptStatus.QuadPart;

   if (pDevExt->InterruptStatus) {

      pDevExt->InterruptStatus
         = SerialGetMappedAddress(PConfigData->InterfaceType,
                                  PConfigData->BusNumber,
                                  PConfigData->TrInterruptStatus,
                                  PConfigData->SpanOfInterruptStatus,
                                  (BOOLEAN)PConfigData->AddressSpace,
                                  &pDevExt->UnMapStatus);


      if (!pDevExt->InterruptStatus) {

         SerialLogError(
                       PDevObj->DriverObject,
                       PDevObj,
                       PConfigData->TrController,
                       SerialPhysicalZero,
                       0,
                       0,
                       0,
                       8,
                       STATUS_SUCCESS,
                       SERIAL_REGISTERS_NOT_MAPPED,
                       pDevExt->DeviceName.Length+sizeof(WCHAR),
                       pDevExt->DeviceName.Buffer,
                       0,
                       NULL
                       );

         SerialDbgPrintEx(DPFLTR_WARNING_LEVEL, "Could not map memory for "
                          "interrupt status for %wZ\n", &pDevExt->DeviceName);

         //
         // Manually unmap the other register here if necessary
         //

         if (pDevExt->UnMapRegisters) {
            MmUnmapIoSpace((PVOID)PConfigData->TrController.QuadPart,
                           PConfigData->SpanOfController);
         }

         pDevExt->UnMapRegisters = FALSE;
         pDevExt->UnMapStatus = FALSE;
         status = STATUS_NONE_MAPPED;
         goto ExtensionCleanup;

      }

      pDevExt->OriginalInterruptStatus = PConfigData->InterruptStatus;
      pDevExt->SpanOfInterruptStatus = PConfigData->SpanOfInterruptStatus;


   }


   //
   // Shareable interrupt?
   //

   if ((BOOLEAN)PConfigData->PermitSystemWideShare) {
      pDevExt->InterruptShareable = TRUE;
   }

   //
   // Save off the interface type and the bus number.
   //

   pDevExt->InterfaceType = PConfigData->InterfaceType;
   pDevExt->BusNumber     = PConfigData->BusNumber;

   pDevExt->PortIndex = PConfigData->PortIndex;
   pDevExt->Indexed = (BOOLEAN)PConfigData->Indexed;
   pDevExt->MaskInverted = PConfigData->MaskInverted;

   //
   // Get the translated interrupt vector, level, and affinity
   //

   pDevExt->OriginalIrql      = PConfigData->OriginalIrql;
   pDevExt->OriginalVector    = PConfigData->OriginalVector;


   //
   // PnP uses the passed translated values rather than calling
   // HalGetInterruptVector()
   //

   pDevExt->Vector = PConfigData->TrVector;
   pDevExt->Irql = (UCHAR)PConfigData->TrIrql;

   //
   // Set up the Isr.
   //

   pDevExt->OurIsr        = SerialISR;
   pDevExt->OurIsrContext = pDevExt;


   //
   // If the user said to permit sharing within the device, propagate this
   // through.
   //

   pDevExt->PermitShare = PConfigData->PermitShare;


   //
   // Before we test whether the port exists (which will enable the FIFO)
   // convert the rx trigger value to what should be used in the register.
   //
   // If a bogus value was given - crank them down to 1.
   //
   // If this is a "souped up" UART with like a 64 byte FIFO, they
   // should use the appropriate "spoofing" value to get the desired
   // results.  I.e., if on their chip 0xC0 in the FCR is for 64 bytes,
   // they should specify 14 in the registry.
   //


   switch (PConfigData->RxFIFO) {

   case 1:

      pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
      break;

   case 4:

      pDevExt->RxFifoTrigger = SERIAL_4_BYTE_HIGH_WATER;
      break;

   case 8:

      pDevExt->RxFifoTrigger = SERIAL_8_BYTE_HIGH_WATER;
      break;

   case 14:

      pDevExt->RxFifoTrigger = SERIAL_14_BYTE_HIGH_WATER;
      break;

   default:

      pDevExt->RxFifoTrigger = SERIAL_1_BYTE_HIGH_WATER;
      break;

   }


   if (PConfigData->TxFIFO < 1) {

      pDevExt->TxFifoAmount = 1;

   } else {

      pDevExt->TxFifoAmount = PConfigData->TxFIFO;

   }


   if (!SerialDoesPortExist(
                           pDevExt,
                           &pDevExt->DeviceName,
                           PConfigData->ForceFifoEnable,
                           PConfigData->LogFifo

⌨️ 快捷键说明

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