📄 initunlo.c
字号:
ExtensionCleanup: ;
if (!NT_SUCCESS(status)) {
if (allocedISRSw) {
ExFreePool(pDevExt->CIsrSw);
pDevExt->CIsrSw = NULL;
}
if (pDevExt->UnMapRegisters) {
MmUnmapIoSpace(pDevExt->Controller, pDevExt->SpanOfController);
}
if (pDevExt->UnMapStatus) {
MmUnmapIoSpace(pDevExt->InterruptStatus,
pDevExt->SpanOfInterruptStatus);
}
}
return status;
}
NTSTATUS
SerialInitOneController(IN PDEVICE_OBJECT PDevObj, IN PCONFIG_DATA PConfigData)
/*++
Routine Description:
This routine will call the real port initialization code. It sets
up the ISR and Context correctly for a one port device.
Arguments:
All args are simply passed along.
Return Value:
Status returned from the controller initialization routine.
--*/
{
NTSTATUS status;
PSERIAL_DEVICE_EXTENSION pDevExt;
PAGED_CODE();
status = SerialInitController(PDevObj, PConfigData);
if (NT_SUCCESS(status)) {
pDevExt = PDevObj->DeviceExtension;
//
// We successfully initialized the single controller.
// Stick the isr routine and the parameter for it
// back into the extension.
//
pDevExt->OurIsr = SerialISR;
pDevExt->OurIsrContext = pDevExt;
pDevExt->TopLevelOurIsr = SerialISR;
pDevExt->TopLevelOurIsrContext = pDevExt;
}
return status;
}
BOOLEAN
SerialDoesPortExist(
IN PSERIAL_DEVICE_EXTENSION Extension,
IN PUNICODE_STRING InsertString,
IN ULONG ForceFifo,
IN ULONG LogFifo
)
/*++
Routine Description:
This routine examines several of what might be the serial device
registers. It ensures that the bits that should be zero are zero.
In addition, this routine will determine if the device supports
fifo's. If it does it will enable the fifo's and turn on a boolean
in the extension that indicates the fifo's presence.
NOTE: If there is indeed a serial port at the address specified
it will absolutely have interrupts inhibited upon return
from this routine.
NOTE: Since this routine should be called fairly early in
the device driver initialization, the only element
that needs to be filled in is the base register address.
NOTE: These tests all assume that this code is the only
code that is looking at these ports or this memory.
This is a not to unreasonable assumption even on
multiprocessor systems.
Arguments:
Extension - A pointer to a serial device extension.
InsertString - String to place in an error log entry.
ForceFifo - !0 forces the fifo to be left on if found.
LogFifo - !0 forces a log message if fifo found.
Return Value:
Will return true if the port really exists, otherwise it
will return false.
--*/
{
UCHAR regContents;
BOOLEAN returnValue = TRUE;
UCHAR oldIERContents;
UCHAR oldLCRContents;
USHORT value1;
USHORT value2;
KIRQL oldIrql;
//
// Save of the line control.
//
oldLCRContents = READ_LINE_CONTROL(Extension->Controller);
//
// Make sure that we are *aren't* accessing the divsior latch.
//
WRITE_LINE_CONTROL(
Extension->Controller,
(UCHAR)(oldLCRContents & ~SERIAL_LCR_DLAB)
);
oldIERContents = READ_INTERRUPT_ENABLE(Extension->Controller);
//
// Go up to power level for a very short time to prevent
// any interrupts from this device from coming in.
//
KeRaiseIrql(
POWER_LEVEL,
&oldIrql
);
WRITE_INTERRUPT_ENABLE(
Extension->Controller,
0x0f
);
value1 = READ_INTERRUPT_ENABLE(Extension->Controller);
value1 = value1 << 8;
value1 |= READ_RECEIVE_BUFFER(Extension->Controller);
READ_DIVISOR_LATCH(
Extension->Controller,
&value2
);
WRITE_LINE_CONTROL(
Extension->Controller,
oldLCRContents
);
//
// Put the ier back to where it was before. If we are on a
// level sensitive port this should prevent the interrupts
// from coming in. If we are on a latched, we don't care
// cause the interrupts generated will just get dropped.
//
WRITE_INTERRUPT_ENABLE(
Extension->Controller,
oldIERContents
);
KeLowerIrql(oldIrql);
if (value1 == value2) {
SerialLogError(
Extension->DeviceObject->DriverObject,
Extension->DeviceObject,
Extension->OriginalController,
SerialPhysicalZero,
0,
0,
0,
62,
STATUS_SUCCESS,
SERIAL_DLAB_INVALID,
InsertString->Length+sizeof(WCHAR),
InsertString->Buffer,
0,
NULL
);
returnValue = FALSE;
goto AllDone;
}
AllDone: ;
//
// If we think that there is a serial device then we determine
// if a fifo is present.
//
if (returnValue) {
//
// Well, we think it's a serial device. Absolutely
// positively, prevent interrupts from occuring.
//
// We disable all the interrupt enable bits, and
// push down all the lines in the modem control
// We only needed to push down OUT2 which in
// PC's must also be enabled to get an interrupt.
//
DISABLE_ALL_INTERRUPTS(Extension->Controller);
if (Extension->Jensen) {
WRITE_MODEM_CONTROL(
Extension->Controller,
(UCHAR)SERIAL_MCR_OUT2
);
} else {
WRITE_MODEM_CONTROL(
Extension->Controller,
(UCHAR)0
);
}
//
// See if this is a 16550. We do this by writing to
// what would be the fifo control register with a bit
// pattern that tells the device to enable fifo's.
// We then read the iterrupt Id register to see if the
// bit pattern is present that identifies the 16550.
//
WRITE_FIFO_CONTROL(
Extension->Controller,
SERIAL_FCR_ENABLE
);
regContents = READ_INTERRUPT_ID_REG(Extension->Controller);
if (regContents & SERIAL_IIR_FIFOS_ENABLED) {
//
// Save off that the device supports fifos.
//
Extension->FifoPresent = TRUE;
//
// There is a fine new "super" IO chip out there that
// will get stuck with a line status interrupt if you
// attempt to clear the fifo and enable it at the same
// time if data is present. The best workaround seems
// to be that you should turn off the fifo read a single
// byte, and then re-enable the fifo.
//
WRITE_FIFO_CONTROL(
Extension->Controller,
(UCHAR)0
);
READ_RECEIVE_BUFFER(Extension->Controller);
//
// There are fifos on this card. Set the value of the
// receive fifo to interrupt when 4 characters are present.
//
WRITE_FIFO_CONTROL(Extension->Controller,
(UCHAR)(SERIAL_FCR_ENABLE
| Extension->RxFifoTrigger
| SERIAL_FCR_RCVR_RESET
| SERIAL_FCR_TXMT_RESET));
}
//
// The !Extension->FifoPresent is included in the test so that
// broken chips like the WinBond will still work after we test
// for the fifo.
//
if (!ForceFifo || !Extension->FifoPresent) {
Extension->FifoPresent = FALSE;
WRITE_FIFO_CONTROL(
Extension->Controller,
(UCHAR)0
);
}
if (Extension->FifoPresent) {
if (LogFifo) {
SerialLogError(
Extension->DeviceObject->DriverObject,
Extension->DeviceObject,
Extension->OriginalController,
SerialPhysicalZero,
0,
0,
0,
15,
STATUS_SUCCESS,
SERIAL_FIFO_PRESENT,
InsertString->Length+sizeof(WCHAR),
InsertString->Buffer,
0,
NULL
);
}
SerialDump(
SERDIAG1,
("SERIAL: Fifo's detected at port address: %x\n",
Extension->Controller)
);
}
//
// In case we are dealing with a bitmasked multiportcard,
// that has the mask register enabled, enable the
// interrupts.
//
if (Extension->InterruptStatus) {
if (Extension->Indexed) {
WRITE_PORT_UCHAR(Extension->InterruptStatus, (UCHAR)0xFF);
} else {
//
// Either we are standalone or already mapped
//
if (Extension->OurIsrContext == Extension) {
//
// This is a standalone
//
WRITE_PORT_UCHAR(Extension->InterruptStatus,
(UCHAR)(1 << (Extension->PortIndex - 1)));
} else {
//
// One of many
//
WRITE_PORT_UCHAR(Extension->InterruptStatus,
(UCHAR)((PSERIAL_MULTIPORT_DISPATCH)Extension->
OurIsrContext)->UsablePortMask);
}
}
}
}
return returnValue;
}
BOOLEAN
SerialReset(
IN PVOID Context
)
/*++
Routine Description:
This places the hardware in a standard configuration.
NOTE: This assumes that it is called at interrupt level.
Arguments:
Context - The device extension for serial device
being managed.
Return Value:
Always FALSE.
--*/
{
PSERIAL_DEVICE_EXTENSION extension = Context;
UCHAR regContents;
UCHAR oldModemControl;
ULONG i;
SERIAL_LOCKED_PAGED_CODE();
//
// Adjust the out2 bit.
// This will also prevent any interrupts from occuring.
//
oldModemControl = READ_MODEM_CONTROL(extension->Controller);
if (extension->Jensen) {
WRITE_MODEM_CONTROL(
extension->Controller,
(UCHAR)(oldModemControl | SERIAL_MCR_OUT2)
);
} else {
WRITE_MODEM_CONTROL(
extension->Controller,
(UCHAR)(oldModemControl & ~SERIAL_MCR_OUT2)
);
}
//
// Reset the fifo's if there are any.
//
if (extension->FifoPresent) {
//
// There is a fine new "super" IO chip out there that
// will get stuck with a line status interrupt if you
// attempt to clear the fifo and enable it at the same
// time if data is present. The best workaround seems
// to be that you should turn off the fifo read a single
// byte, and then re-enable the fifo.
//
WRITE_FIFO_CONTROL(
extension->Controller,
(UCHAR)0
);
READ_RECEIVE_BUFFER(extension->Controller);
WRITE_FIFO_CONTROL(
extension->Controller,
(UCHAR)(SERIAL_FCR_ENABLE | extension->RxFifoTrigger |
SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -