📄 initunlo.cpp
字号:
m_pController->ReadByte(RECEIVE_BUFFER_REGISTER);
// There are fifos on this card. Set the value of the
// receive fifo to interrupt when 4 characters are present.
m_pController->WriteByte(FIFO_CONTROL_REGISTER ,
(UCHAR)(SERIAL_FCR_ENABLE | m_RxFifoTrigger |
SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET));
}
// The !m_FifoPresent is included in the test so that
// broken chips like the WinBond will still work after we test
// for the fifo.
if (!ForceFifo || !m_FifoPresent)
{
m_FifoPresent = FALSE;
m_pController->WriteByte(FIFO_CONTROL_REGISTER, 0);
}
if (m_FifoPresent)
{
if (LogFifo)
{
KdSerialDriver::LogError(
15,
STATUS_SUCCESS,
SERIAL_FIFO_PRESENT,
this,
m_OriginalController,
InsertString
);
}
DebugDump(DBG_DIAG1, ("Fifo's detected at port address: %x\n",
m_pController->GetSystemAddress()) );
}
// In case we are dealing with a bitmasked multiportcard,
// that has the mask register enabled, enable all
// interrupts.
if (m_pInterruptStatus)
m_pInterruptStatus->WriteByte(0, 0xff);
}
return returnValue;
}
BOOLEAN KdSerialDevice::Reset()
/*++
Routine Description:
This places the hardware in a standard configuration.
NOTE: This assumes that it is called at interrupt level.
Arguments:
Context - not used.
Return Value:
Always FALSE.
--*/
{
UCHAR regContents;
UCHAR oldModemControl;
ULONG i;
// Adjust the out2 bit.
// This will also prevent any interrupts from occuring.
oldModemControl = m_pController->ReadByte(MODEM_CONTROL_REGISTER);
if (m_Jensen)
m_pController->WriteByte(MODEM_CONTROL_REGISTER, (UCHAR)(oldModemControl | SERIAL_MCR_OUT2));
else
m_pController->WriteByte(MODEM_CONTROL_REGISTER, (UCHAR)(oldModemControl & ~SERIAL_MCR_OUT2));
// Reset the fifo's if there are any.
if (m_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.
m_pController->WriteByte(FIFO_CONTROL_REGISTER, 0);
m_pController->ReadByte(RECEIVE_BUFFER_REGISTER);
m_pController->WriteByte(FIFO_CONTROL_REGISTER,
(UCHAR)(SERIAL_FCR_ENABLE | m_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 = m_pController->ReadByte(LINE_CONTROL_REGISTER);
regContents &= ~(SERIAL_LCR_DLAB | SERIAL_LCR_BREAK);
m_pController->WriteByte(LINE_CONTROL_REGISTER, regContents);
// Read the receive buffer until the line status is
// clear. (Actually give up after a 5 reads.)
for (i = 0; i<5; i++)
{
m_pController->ReadByte(RECEIVE_BUFFER_REGISTER);
if (!(m_pController->ReadByte(LINE_CONTROL_REGISTER) & 1))
break;
}
// 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 (!(m_pController->ReadByte(MODEM_STATUS_REGISTER) & 0x0f))
break;
}
// Now we set the line control, modem control, and the
// baud to what they should be.
SetLineControl();
SetupNewHandFlow(&m_HandFlow);
HandleModemUpdate(FALSE);
SHORT appropriateDivisor;
GetDivisorFromBaud(m_CurrentBaud, &appropriateDivisor);
SetBaud((PVOID)appropriateDivisor);
// 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(m_pController);
// 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 (m_pController->ReadByte(INTERRUPT_IDENT_REGISTER) & 0x01)
break;
}
// Now we know that nothing could be transmitting at this point
// so we set the HoldingEmpty indicator.
m_HoldingEmpty = TRUE;
return FALSE;
}
NTSTATUS KdSerialDevice::GetDivisorFromBaud(LONG DesiredBaud, PSHORT pAppropriateDivisor)
/*++
Routine Description:
This routine will determine a divisor based on an unvalidated
baud rate.
Arguments:
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 function will return STATUS_SUCCESS if the baud is supported.
--*/
{
SHORT AppropriateDivisor;
NTSTATUS status = STATUS_SUCCESS;
SHORT calculatedDivisor;
ULONG denominator;
ULONG remainder;
// Allow up to a 1 percent error
ULONG maxRemain18 = 18432;
ULONG maxRemain30 = 30720;
ULONG maxRemain42 = 42336;
ULONG maxRemain80 = 80000;
ULONG maxRemain;
// Reject any non-positive bauds.
denominator = DesiredBaud*(ULONG)16;
if (DesiredBaud <= 0)
AppropriateDivisor = -1;
else if ((LONG)denominator < DesiredBaud)
{
// If the desired baud was so huge that it cause the denominator
// calculation to wrap, don't support it.
AppropriateDivisor = -1;
}
else
{
switch (m_ClockRate)
{
case 1843200:
maxRemain = maxRemain18;
break;
case 3072000:
maxRemain = maxRemain30;
break;
case 4233600:
maxRemain = maxRemain42;
break;
default:
maxRemain = maxRemain80;
}
calculatedDivisor = (SHORT)(m_ClockRate / denominator);
remainder = m_ClockRate % denominator;
// Round up.
if (((remainder*2) > m_ClockRate) && (DesiredBaud != 110))
calculatedDivisor++;
// Only let the remainder calculations effect us if
// the baud rate is > 9600.
if (DesiredBaud >= 9600)
{
// If the remainder is less than the maximum remainder (wrt
// the m_ClockRate) or the remainder + the maximum remainder is
// greater than or equal to the m_ClockRate then assume that the
// baud is ok.
if ((remainder >= maxRemain) && ((remainder+maxRemain) < m_ClockRate))
calculatedDivisor = -1;
}
// Don't support a baud that causes the denominator to
// be larger than the clock.
if (denominator > m_ClockRate)
calculatedDivisor = -1;
// Ok, Now do some special casing so that things can actually continue
// working on all platforms.
switch (m_ClockRate)
{
case 1843200:
if (DesiredBaud == 56000)
calculatedDivisor = 2;
break;
case 3072000:
if (DesiredBaud == 14400)
calculatedDivisor = 13;
break;
case 4233600:
switch (DesiredBaud)
{
case 9600:
calculatedDivisor = 28;
break;
case 14400:
calculatedDivisor = 18;
break;
case 19200:
calculatedDivisor = 14;
break;
case 38400:
calculatedDivisor = 7;
break;
case 56000:
calculatedDivisor = 5;
break;
}
case 8000000:
if (DesiredBaud == 14400)
calculatedDivisor = 35;
else if (DesiredBaud == 56000)
calculatedDivisor = 9;
break;
}
AppropriateDivisor = calculatedDivisor;
}
if (AppropriateDivisor == -1)
status = STATUS_INVALID_PARAMETER;
if (pAppropriateDivisor)
*pAppropriateDivisor = AppropriateDivisor;
return status;
}
KdSerialDriver::~KdSerialDriver()
{
}
NTSTATUS SerialItemCallBack(QUERY_RESULT* Results, PVOID Context)
/*++
Routine Description:
This routine is called to check if a particular item
is present in the registry.
Arguments:
Context - Pointer to a boolean.
Results - results of the callback. Not Used.
Return Value:
STATUS_SUCCESS
--*/
{
*((BOOLEAN *)Context) = TRUE;
return STATUS_SUCCESS;
}
// This structure is only used to communicate between the
// code that queries what the firmware found and the code
// that is calling the quering of the firmware data.
class SERIAL_FIRMWARE_DATA
{
public:
SERIAL_FIRMWARE_DATA()
: ConfigList(CONFIG_LIST_OFFSET)
{
ControllersFound = 0;
ForceFifoEnableDefault = 0;
RxFIFODefault = 0;
TxFIFODefault = 0;
PermitShareDefault = 0;
PermitSystemWideShare = 0;
LogFifoDefault = 0;
}
ULONG ControllersFound;
ULONG ForceFifoEnableDefault;
ULONG RxFIFODefault;
ULONG TxFIFODefault;
ULONG PermitShareDefault;
ULONG PermitSystemWideShare;
ULONG LogFifoDefault;
KdString Directory;
KdString NtNameSuffix;
KdString DirectorySymbolicName;
KdConfigList ConfigList;
};
typedef SERIAL_FIRMWARE_DATA * PSERIAL_FIRMWARE_DATA;
NTSTATUS SerialConfigCallBack(QUERY_RESULT* Results, PVOID Context)
/*++
Routine Description:
This routine is used to acquire all of the configuration
information for each serial controller found by the firmware
Arguments:
Context - Pointer to the list head o
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -