879 lines
18 KiB
C
879 lines
18 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
jxport.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the code that provides communication between
|
|||
|
the kernel debugger on a MIPS R3000 or R4000 Jazz system and the host
|
|||
|
system.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "halp.h"
|
|||
|
#include "jazzserp.h"
|
|||
|
|
|||
|
VOID
|
|||
|
HalpGetDivisorFromBaud(
|
|||
|
IN ULONG ClockRate,
|
|||
|
IN LONG DesiredBaud,
|
|||
|
OUT PSHORT AppropriateDivisor
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
#pragma alloc_text(INIT,HalpGetDivisorFromBaud)
|
|||
|
|
|||
|
#define HEADER_FILE
|
|||
|
#include "kxmips.h"
|
|||
|
|
|||
|
#define SP_VIRTUAL_BASE 0xffffa000
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// BUGBUG Temporarily, we use counter to do the timeout
|
|||
|
//
|
|||
|
|
|||
|
#define TIMEOUT_COUNT 1024*512
|
|||
|
|
|||
|
//
|
|||
|
// BUGBUG Temp until we have a configuration manager.
|
|||
|
//
|
|||
|
|
|||
|
PUCHAR KdComPortInUse = NULL;
|
|||
|
BOOLEAN KdUseModemControl = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Define serial port read and write addresses.
|
|||
|
//
|
|||
|
|
|||
|
#define SP_READ ((PSP_READ_REGISTERS)(SP_VIRTUAL_BASE + 0x3F8))
|
|||
|
#define SP_WRITE ((PSP_WRITE_REGISTERS)(SP_VIRTUAL_BASE + 0x3F8))
|
|||
|
|
|||
|
//
|
|||
|
// Define forward referenced prototypes.
|
|||
|
//
|
|||
|
|
|||
|
SP_LINE_STATUS
|
|||
|
KdReadLsr (
|
|||
|
IN BOOLEAN WaitReason
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Define baud rate divisor to be used on the debugger port.
|
|||
|
//
|
|||
|
|
|||
|
SHORT HalpBaudRateDivisor = 6;
|
|||
|
|
|||
|
//
|
|||
|
// Define hardware PTE's that map the serial port used by the debugger.
|
|||
|
//
|
|||
|
|
|||
|
ENTRYLO HalpPte[2];
|
|||
|
|
|||
|
ULONG
|
|||
|
HalpGetByte (
|
|||
|
IN PCHAR Input,
|
|||
|
IN BOOLEAN Wait
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine gets a byte from the serial port used by the kernel
|
|||
|
debugger.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Input - Supplies a pointer to a variable that receives the input
|
|||
|
data byte.
|
|||
|
|
|||
|
Wait - Supplies a boolean value that detemines whether a timeout
|
|||
|
is applied to the input operation.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
CP_GET_SUCCESS is returned if a byte is successfully read from the
|
|||
|
kernel debugger line.
|
|||
|
|
|||
|
CP_GET_ERROR is returned if an error is encountered during reading.
|
|||
|
|
|||
|
CP_GET_NODATA is returned if timeout occurs.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
SP_LINE_STATUS LsrByte;
|
|||
|
UCHAR DataByte;
|
|||
|
ULONG TimeoutCount;
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to read a byte from the debugger port until a byte is
|
|||
|
// available or until a timeout occurs.
|
|||
|
//
|
|||
|
|
|||
|
TimeoutCount = Wait ? TIMEOUT_COUNT : 1;
|
|||
|
do {
|
|||
|
TimeoutCount -= 1;
|
|||
|
|
|||
|
//
|
|||
|
// Wait until data is available in the receive buffer.
|
|||
|
//
|
|||
|
|
|||
|
KeStallExecutionProcessor(1);
|
|||
|
LsrByte = KdReadLsr(TRUE);
|
|||
|
if (LsrByte.DataReady == 0) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read input byte and store in callers buffer.
|
|||
|
//
|
|||
|
|
|||
|
*Input = READ_REGISTER_UCHAR(&SP_READ->ReceiveBuffer);
|
|||
|
|
|||
|
//
|
|||
|
// If using modem controls, then skip any incoming data while
|
|||
|
// ReceiveData not set.
|
|||
|
//
|
|||
|
|
|||
|
if (KdUseModemControl) {
|
|||
|
DataByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus);
|
|||
|
if ( ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect == 0) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return function value as the not of the error indicators.
|
|||
|
//
|
|||
|
|
|||
|
if (LsrByte.ParityError ||
|
|||
|
LsrByte.FramingError ||
|
|||
|
LsrByte.OverrunError ||
|
|||
|
LsrByte.BreakIndicator) {
|
|||
|
return CP_GET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
return CP_GET_SUCCESS;
|
|||
|
} while(TimeoutCount != 0);
|
|||
|
|
|||
|
return CP_GET_NODATA;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
KdPortInitialize (
|
|||
|
PDEBUG_PARAMETERS DebugParameters,
|
|||
|
PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|||
|
BOOLEAN Initialize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine initializes the serial port used by the kernel debugger
|
|||
|
and must be called during system initialization.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DebugParameter - Supplies a pointer to the debug port parameters.
|
|||
|
|
|||
|
LoaderBlock - Supplies a pointer to the loader parameter block.
|
|||
|
|
|||
|
Initialize - Specifies a boolean value that determines whether the
|
|||
|
debug port is initialized or just the debug port parameters
|
|||
|
are captured.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A value of TRUE is returned is the port was successfully initialized.
|
|||
|
Otherwise, a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PCONFIGURATION_COMPONENT_DATA ConfigurationEntry;
|
|||
|
UCHAR DataByte;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
|
|||
|
PCM_SERIAL_DEVICE_DATA DeviceData;
|
|||
|
ULONG KdPortEntry;
|
|||
|
PCM_PARTIAL_RESOURCE_LIST List;
|
|||
|
ULONG MatchKey;
|
|||
|
ULONG BaudRate;
|
|||
|
ULONG BaudClock;
|
|||
|
|
|||
|
//
|
|||
|
// Find the configuration information for the first serial port.
|
|||
|
//
|
|||
|
|
|||
|
if (LoaderBlock != NULL) {
|
|||
|
MatchKey = 0;
|
|||
|
ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
|
|||
|
ControllerClass,
|
|||
|
SerialController,
|
|||
|
&MatchKey);
|
|||
|
|
|||
|
} else {
|
|||
|
ConfigurationEntry = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (DebugParameters->BaudRate != 0) {
|
|||
|
BaudRate = DebugParameters->BaudRate;
|
|||
|
} else {
|
|||
|
BaudRate = 19200;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the serial configuration entry was not found or the frequency
|
|||
|
// specified is not supported, then default the baud clock to 1843200.
|
|||
|
//
|
|||
|
|
|||
|
BaudClock = 1843200;
|
|||
|
|
|||
|
if (ConfigurationEntry != NULL) {
|
|||
|
List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData;
|
|||
|
Descriptor = &List->PartialDescriptors[List->Count];
|
|||
|
DeviceData = (PCM_SERIAL_DEVICE_DATA)Descriptor;
|
|||
|
if ((DeviceData->BaudClock == 1843200) ||
|
|||
|
(DeviceData->BaudClock == 4233600) ||
|
|||
|
(DeviceData->BaudClock == 8000000)) {
|
|||
|
BaudClock = DeviceData->BaudClock;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
HalpGetDivisorFromBaud(
|
|||
|
BaudClock,
|
|||
|
BaudRate,
|
|||
|
&HalpBaudRateDivisor
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// If the debugger is not being enabled, then return.
|
|||
|
//
|
|||
|
|
|||
|
if (Initialize == FALSE) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Map the serial port into the system virtual address space by loading
|
|||
|
// a TB entry.
|
|||
|
//
|
|||
|
|
|||
|
HalpPte[0].PFN = (ULONG)(((EISA_CONTROL_PHYSICAL_BASE_HI << 28) | (EISA_CONTROL_PHYSICAL_BASE_LO >> 4)) >> 8);
|
|||
|
HalpPte[0].G = 1;
|
|||
|
HalpPte[0].V = 1;
|
|||
|
HalpPte[0].D = 1;
|
|||
|
|
|||
|
#if defined(R3000)
|
|||
|
|
|||
|
//
|
|||
|
// Set the TB entry and set the noncached bit in the PTE that will
|
|||
|
// map the serial controller.
|
|||
|
//
|
|||
|
|
|||
|
KdPortEntry = KDPORT_ENTRY;
|
|||
|
HalpPte[0].N = 1;
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
#if defined(R4000)
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a TB entry, set the uncached policy in the PTE that will
|
|||
|
// map the serial controller, and initialize the second PTE.
|
|||
|
//
|
|||
|
|
|||
|
KdPortEntry = HalpAllocateTbEntry();
|
|||
|
HalpPte[0].C = UNCACHED_POLICY;
|
|||
|
|
|||
|
HalpPte[1].PFN = 0;
|
|||
|
HalpPte[1].G = 1;
|
|||
|
HalpPte[1].V = 0;
|
|||
|
HalpPte[1].D = 0;
|
|||
|
HalpPte[1].C = 0;
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
// KdComPortInUse=(PUCHAR)SERIAL0_PHYSICAL_BASE;
|
|||
|
KdComPortInUse=(PUCHAR)0x3f8;
|
|||
|
|
|||
|
//
|
|||
|
// Map the serial controller through a fixed TB entry.
|
|||
|
//
|
|||
|
|
|||
|
KeFillFixedEntryTb((PHARDWARE_PTE)&HalpPte[0],
|
|||
|
(PVOID)SP_VIRTUAL_BASE,
|
|||
|
KdPortEntry);
|
|||
|
|
|||
|
//
|
|||
|
// Clear the divisor latch, clear all interrupt enables, and reset and
|
|||
|
// disable the FIFO's.
|
|||
|
//
|
|||
|
|
|||
|
WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, 0x0);
|
|||
|
WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable, 0x0);
|
|||
|
DataByte = 0;
|
|||
|
((PSP_FIFO_CONTROL)(&DataByte))->ReceiveFifoReset = 1;
|
|||
|
((PSP_FIFO_CONTROL)(&DataByte))->TransmitFifoReset = 1;
|
|||
|
WRITE_REGISTER_UCHAR(&SP_WRITE->FifoControl, DataByte);
|
|||
|
|
|||
|
//
|
|||
|
// Set the divisor latch and set the baud rate to 19200 baud.
|
|||
|
//
|
|||
|
((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1;
|
|||
|
WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte);
|
|||
|
WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer, (UCHAR)(HalpBaudRateDivisor&0xff));
|
|||
|
WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable, (UCHAR)(HalpBaudRateDivisor>>8));
|
|||
|
|
|||
|
//
|
|||
|
// Clear the divisor latch and set the character size to eight bits
|
|||
|
// with one stop bit and no parity checking.
|
|||
|
//
|
|||
|
|
|||
|
DataByte = 0;
|
|||
|
((PSP_LINE_CONTROL)(&DataByte))->CharacterSize = EIGHT_BITS;
|
|||
|
WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte);
|
|||
|
|
|||
|
//
|
|||
|
// Set data terminal ready and request to send.
|
|||
|
//
|
|||
|
|
|||
|
DataByte = 0;
|
|||
|
((PSP_MODEM_CONTROL)(&DataByte))->DataTerminalReady = 1;
|
|||
|
((PSP_MODEM_CONTROL)(&DataByte))->RequestToSend = 1;
|
|||
|
WRITE_REGISTER_UCHAR(&SP_WRITE->ModemControl, DataByte);
|
|||
|
|
|||
|
//
|
|||
|
// Free the TB entry if one was allocated.
|
|||
|
//
|
|||
|
|
|||
|
#if defined(R4000)
|
|||
|
|
|||
|
HalpFreeTbEntry();
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
KdPortGetByte (
|
|||
|
OUT PUCHAR Input
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine gets a byte from the serial port used by the kernel
|
|||
|
debugger.
|
|||
|
|
|||
|
N.B. It is assumed that the IRQL has been raised to the highest
|
|||
|
level, and necessary multiprocessor synchronization has been
|
|||
|
performed before this routine is called.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Input - Supplies a pointer to a variable that receives the input
|
|||
|
data byte.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
CP_GET_SUCCESS is returned if a byte is successfully read from the
|
|||
|
kernel debugger line.
|
|||
|
|
|||
|
CP_GET_ERROR is returned if an error is encountered during reading.
|
|||
|
|
|||
|
CP_GET_NODATA is returned if timeout occurs.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
return HalpGetByte(Input, TRUE);
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
KdPortPollByte (
|
|||
|
OUT PUCHAR Input
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine gets a byte from the serial port used by the kernel
|
|||
|
debugger iff a byte is available.
|
|||
|
|
|||
|
N.B. It is assumed that the IRQL has been raised to the highest
|
|||
|
level, and necessary multiprocessor synchronization has been
|
|||
|
performed before this routine is called.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Input - Supplies a pointer to a variable that receives the input
|
|||
|
data byte.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
CP_GET_SUCCESS is returned if a byte is successfully read from the
|
|||
|
kernel debugger line.
|
|||
|
|
|||
|
CP_GET_ERROR is returned if an error encountered during reading.
|
|||
|
|
|||
|
CP_GET_NODATA is returned if timeout occurs.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
ULONG Status;
|
|||
|
|
|||
|
//
|
|||
|
// Save port status, map the serial controller, get byte from the
|
|||
|
// debugger port is one is avaliable, restore port status, unmap
|
|||
|
// the serial controller, and return the operation status.
|
|||
|
//
|
|||
|
|
|||
|
KdPortSave();
|
|||
|
Status = HalpGetByte(Input, FALSE);
|
|||
|
KdPortRestore();
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KdPortPutByte (
|
|||
|
IN UCHAR Output
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine puts a byte to the serial port used by the kernel debugger.
|
|||
|
|
|||
|
N.B. It is assumed that the IRQL has been raised to the highest level,
|
|||
|
and necessary multiprocessor synchronization has been performed
|
|||
|
before this routine is called.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Output - Supplies the output data byte.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
UCHAR DataByte;
|
|||
|
|
|||
|
if (KdUseModemControl) {
|
|||
|
//
|
|||
|
// Modem control, make sure DSR, CTS and CD are all set before
|
|||
|
// sending any data.
|
|||
|
//
|
|||
|
|
|||
|
for (; ;) {
|
|||
|
DataByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus);
|
|||
|
if ( ((PSP_MODEM_STATUS)&DataByte)->ClearToSend &&
|
|||
|
((PSP_MODEM_STATUS)&DataByte)->DataSetReady &&
|
|||
|
((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect ) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
KdReadLsr(FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Wait for transmit ready.
|
|||
|
//
|
|||
|
|
|||
|
while (KdReadLsr(FALSE).TransmitHoldingEmpty == 0 );
|
|||
|
|
|||
|
//
|
|||
|
// Wait for data set ready.
|
|||
|
//
|
|||
|
|
|||
|
// do {
|
|||
|
// LsrByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus);
|
|||
|
// } while (((PSP_MODEM_STATUS)(&LsrByte))->DataSetReady == 0);
|
|||
|
|
|||
|
//
|
|||
|
// Transmit data.
|
|||
|
//
|
|||
|
|
|||
|
WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer, Output);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KdPortRestore (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine restores the state of the serial port after the kernel
|
|||
|
debugger has been active.
|
|||
|
|
|||
|
N.B. This routine performs no function on the Jazz system.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Free the TB entry if one was allocated.
|
|||
|
//
|
|||
|
|
|||
|
#if defined(R4000)
|
|||
|
|
|||
|
HalpFreeTbEntry();
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KdPortSave (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine saves the state of the serial port and initializes the port
|
|||
|
for use by the kernel debugger.
|
|||
|
|
|||
|
N.B. This routine performs no function on the Jazz system.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
ULONG KdPortEntry;
|
|||
|
|
|||
|
#if defined(R3000)
|
|||
|
|
|||
|
//
|
|||
|
// Set the TB entry that will be used to map the serial controller.
|
|||
|
//
|
|||
|
|
|||
|
KdPortEntry = KDPORT_ENTRY;
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
#if defined(R4000)
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the TB entry that will be used to map the serial controller.
|
|||
|
//
|
|||
|
|
|||
|
KdPortEntry = HalpAllocateTbEntry();
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Map the serial controller through a allocated TB entry.
|
|||
|
//
|
|||
|
|
|||
|
KeFillFixedEntryTb((PHARDWARE_PTE)&HalpPte[0],
|
|||
|
(PVOID)SP_VIRTUAL_BASE,
|
|||
|
KdPortEntry);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
SP_LINE_STATUS
|
|||
|
KdReadLsr (
|
|||
|
IN BOOLEAN WaitReason
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns current line status.
|
|||
|
|
|||
|
If status which is being waited for is ready, then the function
|
|||
|
checks the current modem status and causes a possible display update
|
|||
|
of the current statuses.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
WaitReason - Suuplies a boolean value that determines whether the line
|
|||
|
status is required for a receive or transmit.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The current line status is returned as the function value.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
static UCHAR RingFlag = 0;
|
|||
|
UCHAR DataLsr, DataMsr;
|
|||
|
|
|||
|
//
|
|||
|
// Get the line status for a recevie or a transmit.
|
|||
|
//
|
|||
|
|
|||
|
DataLsr = READ_REGISTER_UCHAR(&SP_READ->LineStatus);
|
|||
|
if (WaitReason) {
|
|||
|
|
|||
|
//
|
|||
|
// Get line status for receive data.
|
|||
|
//
|
|||
|
|
|||
|
if (((PSP_LINE_STATUS)&DataLsr)->DataReady) {
|
|||
|
return *((PSP_LINE_STATUS)&DataLsr);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Get line status for transmit empty.
|
|||
|
//
|
|||
|
|
|||
|
if (((PSP_LINE_STATUS)&DataLsr)->TransmitEmpty) {
|
|||
|
return *((PSP_LINE_STATUS)&DataLsr);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
DataMsr = READ_REGISTER_UCHAR(&SP_READ->ModemStatus);
|
|||
|
RingFlag |= ((PSP_MODEM_STATUS)&DataMsr)->RingIndicator ? 1 : 2;
|
|||
|
if (RingFlag == 3) {
|
|||
|
|
|||
|
//
|
|||
|
// The ring indicate line has toggled, use modem control from
|
|||
|
// now on.
|
|||
|
//
|
|||
|
|
|||
|
KdUseModemControl = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return *((PSP_LINE_STATUS) &DataLsr);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HalpGetDivisorFromBaud(
|
|||
|
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
|
|||
|
SHORT pointed to by this parameter will be set to the appropriate
|
|||
|
value. If the requested baud rate is unsupportable on the machine
|
|||
|
return a divisor appropriate for 19200.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
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 {
|
|||
|
|
|||
|
if (ClockRate == 1843200) {
|
|||
|
maxRemain = maxRemain18;
|
|||
|
} else if (ClockRate == 3072000) {
|
|||
|
maxRemain = maxRemain30;
|
|||
|
} else if (ClockRate == 4233600) {
|
|||
|
maxRemain = maxRemain42;
|
|||
|
} else {
|
|||
|
maxRemain = maxRemain80;
|
|||
|
}
|
|||
|
|
|||
|
calculatedDivisor = (SHORT)(ClockRate / denominator);
|
|||
|
remainder = ClockRate % denominator;
|
|||
|
|
|||
|
//
|
|||
|
// Round up.
|
|||
|
//
|
|||
|
|
|||
|
if (((remainder*2) > 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 ClockRate) or the remainder + the maximum remainder is
|
|||
|
// greater than or equal to the ClockRate then assume that the
|
|||
|
// baud is ok.
|
|||
|
//
|
|||
|
|
|||
|
if ((remainder >= maxRemain) && ((remainder+maxRemain) < ClockRate)) {
|
|||
|
calculatedDivisor = -1;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Don't support a baud that causes the denominator to
|
|||
|
// be larger than the clock.
|
|||
|
//
|
|||
|
|
|||
|
if (denominator > ClockRate) {
|
|||
|
|
|||
|
calculatedDivisor = -1;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Ok, Now do some special casing so that things can actually continue
|
|||
|
// working on all platforms.
|
|||
|
//
|
|||
|
|
|||
|
if (ClockRate == 1843200) {
|
|||
|
|
|||
|
if (DesiredBaud == 56000) {
|
|||
|
calculatedDivisor = 2;
|
|||
|
}
|
|||
|
|
|||
|
} else if (ClockRate == 3072000) {
|
|||
|
|
|||
|
if (DesiredBaud == 14400) {
|
|||
|
calculatedDivisor = 13;
|
|||
|
}
|
|||
|
|
|||
|
} else if (ClockRate == 4233600) {
|
|||
|
|
|||
|
if (DesiredBaud == 9600) {
|
|||
|
calculatedDivisor = 28;
|
|||
|
} else if (DesiredBaud == 14400) {
|
|||
|
calculatedDivisor = 18;
|
|||
|
} else if (DesiredBaud == 19200) {
|
|||
|
calculatedDivisor = 14;
|
|||
|
} else if (DesiredBaud == 38400) {
|
|||
|
calculatedDivisor = 7;
|
|||
|
} else if (DesiredBaud == 56000) {
|
|||
|
calculatedDivisor = 5;
|
|||
|
}
|
|||
|
|
|||
|
} else if (ClockRate == 8000000) {
|
|||
|
|
|||
|
if (DesiredBaud == 14400) {
|
|||
|
calculatedDivisor = 35;
|
|||
|
} else if (DesiredBaud == 56000) {
|
|||
|
calculatedDivisor = 9;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
*AppropriateDivisor = calculatedDivisor;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (*AppropriateDivisor == -1) {
|
|||
|
|
|||
|
HalpGetDivisorFromBaud(
|
|||
|
ClockRate,
|
|||
|
19200,
|
|||
|
AppropriateDivisor
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|