376 lines
8.4 KiB
C++
376 lines
8.4 KiB
C++
|
//++
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation
|
||
|
//
|
||
|
// Module Name:
|
||
|
//
|
||
|
// blcom.cpp
|
||
|
//
|
||
|
// Abstract:
|
||
|
//
|
||
|
// This module implements COM port support for the boot loader.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
#include "bl.h"
|
||
|
|
||
|
#define COM1_ADDRESS 0x3F8
|
||
|
#define COM2_ADDRESS 0x2F8
|
||
|
#define COM3_ADDRESS 0x3E8
|
||
|
#define COM4_ADDRESS 0x2E8
|
||
|
|
||
|
const UINT16 BlComBasePort[COM_MAX_PORT + 1] = {
|
||
|
0,
|
||
|
COM1_ADDRESS,
|
||
|
COM2_ADDRESS,
|
||
|
COM3_ADDRESS,
|
||
|
COM4_ADDRESS
|
||
|
};
|
||
|
|
||
|
#define COM_DATA_REGISTER 0x0000
|
||
|
#define COM_INTERRUPT_ENABLE_REGISTER 0x0001
|
||
|
#define COM_INTERRUPT_IDENTIFICATION_REGISTER 0x0002
|
||
|
#define COM_FIFO_CONTROL_REGISTER 0x0002
|
||
|
#define COM_LINE_CONTROL_REGISTER 0x0003
|
||
|
#define COM_MODEM_CONTROL_REGISTER 0x0004
|
||
|
#define COM_LINE_STATUS_REGISTER 0x0005
|
||
|
#define COM_MODEM_STATUS_REGISTER 0x0006
|
||
|
#define COM_SCRATCH_REGISTER 0x0007
|
||
|
|
||
|
#define COM_DIVISOR_LATCH_REGISTER_LOW 0x0000
|
||
|
#define COM_DIVISOR_LATCH_REGISTER_HIGH 0x0001
|
||
|
|
||
|
#define COM_CLOCK_RATE 0x1C200
|
||
|
|
||
|
#define COM_LINE_CONTROL_8BITS_1STOP 0x03
|
||
|
#define COM_LINE_CONTROL_DIVISOR_ACCESS 0x80
|
||
|
|
||
|
#define COM_MODEM_CONTROL_DATA_TERMINAL_READY 0x01
|
||
|
#define COM_MODEM_CONTROL_REQUEST_TO_SEND 0x02
|
||
|
|
||
|
#define COM_LINE_STATUS_DATA_READY 0x01
|
||
|
#define COM_LINE_STATUS_OVERRUN_ERROR 0x02
|
||
|
#define COM_LINE_STATUS_PARITY_ERROR 0x04
|
||
|
#define COM_LINE_STATUS_FRAMING_ERROR 0x08
|
||
|
#define COM_LINE_STATUS_SEND_BUFFER_EMPTY 0x20
|
||
|
|
||
|
BOOLEAN
|
||
|
BlComInitialize(
|
||
|
UINT8 PortNumber,
|
||
|
UINT32 BaudRate
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function initializes the specified COM port.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// PortNumber - Supplies the number of the port to initialize.
|
||
|
//
|
||
|
// BaudRate - Supplies the baud rate.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// TRUE, if initialization was successful.
|
||
|
// FALSE, otherwise.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
UINT16 Base;
|
||
|
UINT16 Divisor;
|
||
|
UINT8 Index;
|
||
|
UINT8 Status;
|
||
|
|
||
|
BLASSERT((PortNumber >= 1) && (PortNumber <= COM_MAX_PORT));
|
||
|
|
||
|
BLASSERT(BaudRate != 0);
|
||
|
|
||
|
BLASSERT(BaudRate <= COM_CLOCK_RATE);
|
||
|
|
||
|
BLASSERT((COM_CLOCK_RATE % BaudRate) == 0);
|
||
|
|
||
|
BLASSERT((COM_CLOCK_RATE / BaudRate) <= 0x10000);
|
||
|
|
||
|
Base = BlComBasePort[PortNumber];
|
||
|
|
||
|
BlRtlWritePort8(Base + COM_LINE_CONTROL_REGISTER, 0);
|
||
|
BlRtlWritePort8(Base + COM_INTERRUPT_ENABLE_REGISTER, 0);
|
||
|
BlRtlWritePort8(Base + COM_MODEM_CONTROL_REGISTER, COM_MODEM_CONTROL_DATA_TERMINAL_READY | COM_MODEM_CONTROL_REQUEST_TO_SEND);
|
||
|
|
||
|
Divisor = (UINT16) (COM_CLOCK_RATE / BaudRate);
|
||
|
|
||
|
BlRtlWritePort8(Base + COM_LINE_CONTROL_REGISTER, COM_LINE_CONTROL_DIVISOR_ACCESS);
|
||
|
BlRtlWritePort8(Base + COM_DIVISOR_LATCH_REGISTER_LOW, (UINT8) (Divisor & 0xFF));
|
||
|
BlRtlWritePort8(Base + COM_DIVISOR_LATCH_REGISTER_HIGH, (UINT8) (Divisor >> 8));
|
||
|
|
||
|
BlRtlWritePort8(Base + COM_LINE_CONTROL_REGISTER, COM_LINE_CONTROL_8BITS_1STOP);
|
||
|
|
||
|
Index = 0;
|
||
|
|
||
|
do {
|
||
|
|
||
|
BlRtlWritePort8(Base + COM_SCRATCH_REGISTER, Index);
|
||
|
|
||
|
if (BlRtlReadPort8(Base + COM_SCRATCH_REGISTER) != Index) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
Index += 1;
|
||
|
|
||
|
} while (Index != 0);
|
||
|
|
||
|
Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER);
|
||
|
|
||
|
if (Status == 0xFF) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
#if COM_VERBOSE
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Overrun error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Parity error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Framing error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
BlComSendByte(
|
||
|
UINT8 PortNumber,
|
||
|
UINT8 Byte
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function sends a byte to the specified COM port.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// PortNumber - Supplies the number of the port to send to.
|
||
|
//
|
||
|
// Byte - Supplies the byte to send.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// TRUE, if data was sent.
|
||
|
// FALSE, otherwise.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
UINT16 Base;
|
||
|
UINT8 Status;
|
||
|
|
||
|
BLASSERT((PortNumber >= 1) && (PortNumber <= COM_MAX_PORT));
|
||
|
|
||
|
Base = BlComBasePort[PortNumber];
|
||
|
|
||
|
do {
|
||
|
|
||
|
Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER);
|
||
|
|
||
|
#if COM_VERBOSE
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Overrun error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Parity error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Framing error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
} while ((Status & COM_LINE_STATUS_SEND_BUFFER_EMPTY) == 0);
|
||
|
|
||
|
BlRtlWritePort8(Base + COM_DATA_REGISTER, Byte);
|
||
|
|
||
|
Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER);
|
||
|
|
||
|
#if COM_VERBOSE
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Overrun error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Parity error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Framing error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
BlComDataAvailable(
|
||
|
UINT8 PortNumber
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function checks if data is available at the specified COM port.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// PortNumber - Supplies the number of the port to check.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// TRUE, if data is available.
|
||
|
// FALSE, otherwise.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
UINT16 Base;
|
||
|
UINT8 Status;
|
||
|
|
||
|
BLASSERT((PortNumber >= 1) && (PortNumber <= COM_MAX_PORT));
|
||
|
|
||
|
Base = BlComBasePort[PortNumber];
|
||
|
|
||
|
Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER);
|
||
|
|
||
|
#if COM_VERBOSE
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Overrun error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Parity error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Framing error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return ((Status & COM_LINE_STATUS_DATA_READY) != 0);
|
||
|
}
|
||
|
|
||
|
UINT8
|
||
|
BlComReceiveByte(
|
||
|
UINT8 PortNumber
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function receives a byte from the specified COM port.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// PortNumber - Supplies the number of the port to receive from.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// Byte received from the specified COM port.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
UINT16 Base;
|
||
|
UINT8 Byte;
|
||
|
UINT8 Status;
|
||
|
|
||
|
BLASSERT((PortNumber >= 1) && (PortNumber <= COM_MAX_PORT));
|
||
|
|
||
|
Base = BlComBasePort[PortNumber];
|
||
|
|
||
|
BlRtlReadPort8(Base + COM_MODEM_STATUS_REGISTER);
|
||
|
|
||
|
do {
|
||
|
|
||
|
Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER);
|
||
|
|
||
|
#if COM_VERBOSE
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Overrun error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Parity error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Framing error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
} while ((Status & COM_LINE_STATUS_DATA_READY) == 0);
|
||
|
|
||
|
Byte = BlRtlReadPort8(Base + COM_DATA_REGISTER);
|
||
|
|
||
|
Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER);
|
||
|
|
||
|
#if COM_VERBOSE
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Overrun error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Parity error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) {
|
||
|
|
||
|
BlVideoPrintf("COM%u: Framing error!\n", PortNumber);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return Byte;
|
||
|
}
|