
//

//

//

//

//

//
//--

#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
    )


//

//

//

//

//

//

//


//
//--

{
    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
    )


//

//

//

//

//

//

//


//
//--

{
    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
    )


//

//

//

//

//

//


//
//--

{
    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
    )


//

//

//

//

//

//

//
//--

{
    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;
}
