📄 initunlo.c
字号:
= (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 + -