📄 initunlo.c
字号:
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);
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
);
}
SerialDbgPrintEx(SERDIAG1, "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);
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)
);
}
//
// Make sure that the line control set up correct.
//
// 1) Make sure that the Divisor latch select is set
// up to select the transmit and receive register.
//
// 2) Make sure that we aren't in a break state.
//
regContents = READ_LINE_CONTROL(extension->Controller);
regContents &= ~(SERIAL_LCR_DLAB | SERIAL_LCR_BREAK);
WRITE_LINE_CONTROL(
extension->Controller,
regContents
);
//
// Read the receive buffer until the line status is
// clear. (Actually give up after a 5 reads.)
//
for (i = 0;
i < 5;
i++
) {
if (IsNotNEC_98) {
READ_RECEIVE_BUFFER(extension->Controller);
if (!(READ_LINE_STATUS(extension->Controller) & 1)) {
break;
}
} else {
//
// I get incorrect data when read enpty buffer.
// But do not read no data! for PC98!
//
if (!(READ_LINE_STATUS(extension->Controller) & 1)) {
break;
}
READ_RECEIVE_BUFFER(extension->Controller);
}
}
//
// Read the modem status until the low 4 bits are
// clear. (Actually give up after a 5 reads.)
//
for (i = 0;
i < 1000;
i++
) {
if (!(READ_MODEM_STATUS(extension->Controller) & 0x0f)) {
break;
}
}
//
// Now we set the line control, modem control, and the
// baud to what they should be.
//
//
// See if we have to enable special Auto Flow Control
//
if (extension->TL16C550CAFC) {
oldModemControl = READ_MODEM_CONTROL(extension->Controller);
WRITE_MODEM_CONTROL(extension->Controller,
(UCHAR)(oldModemControl | SERIAL_MCR_TL16C550CAFE));
}
SerialSetLineControl(extension);
SerialSetupNewHandFlow(
extension,
&extension->HandFlow
);
SerialHandleModemUpdate(
extension,
FALSE
);
{
SHORT appropriateDivisor;
SERIAL_IOCTL_SYNC s;
SerialGetDivisorFromBaud(
extension->ClockRate,
extension->CurrentBaud,
&appropriateDivisor
);
s.Extension = extension;
s.Data = (PVOID)appropriateDivisor;
SerialSetBaud(&s);
}
//
// Enable which interrupts we want to receive.
//
// NOTE NOTE: This does not actually let interrupts
// occur. We must still raise the OUT2 bit in the
// modem control register. We will do that on open.
//
ENABLE_ALL_INTERRUPTS(extension->Controller);
//
// Read the interrupt id register until the low bit is
// set. (Actually give up after a 5 reads.)
//
for (i = 0;
i < 5;
i++
) {
if (READ_INTERRUPT_ID_REG(extension->Controller) & 0x01) {
break;
}
}
//
// Now we know that nothing could be transmitting at this point
// so we set the HoldingEmpty indicator.
//
extension->HoldingEmpty = TRUE;
return FALSE;
}
NTSTATUS
SerialGetDivisorFromBaud(
IN ULONG ClockRate,
IN LONG DesiredBaud,
OUT PSHORT AppropriateDivisor
)
/*++
Routine Description:
This routine will determine a divisor based on an unvalidated
baud rate.
Arguments:
ClockRate - The clock input to the controller.
DesiredBaud - The baud rate for whose divisor we seek.
AppropriateDivisor - Given that the DesiredBaud is valid, the
LONG pointed to by this parameter will be set to the appropriate
value. NOTE: The long is undefined if the DesiredBaud is not
supported.
Return Value:
This fun
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -