diff --git a/input/aip/aip.h b/input/aip/aip.h
index 95ea010..ed4cc77 100644
--- a/input/aip/aip.h
+++ b/input/aip/aip.h
@@ -34,5 +34,6 @@ void PS2MouseInterruptHandler(TrapFrame *);
int InitializeMouse();
int FinalizeMouse();
int DetectPS2Mouse();
+int DetectUART();
#endif // !__FENNIX_DRIVER_AIP_H__
diff --git a/input/aip/main.c b/input/aip/main.c
index 606927c..aa53058 100644
--- a/input/aip/main.c
+++ b/input/aip/main.c
@@ -194,10 +194,11 @@ int DriverProbe()
int kbd = DetectPS2Keyboard();
int mouse = DetectPS2Mouse();
+ int uart = DetectUART();
UnregisterAllInterruptHandlers(__intStub);
- if (kbd != 0 && mouse != 0)
+ if (kbd != 0 && mouse != 0 && uart != 0)
return -ENODEV;
if (kbd == 0)
@@ -219,11 +220,11 @@ int DriverProbe()
}
KernelPrint("PS/2 Port 1: %s (0x%X 0x%X)",
- GetPS2DeviceName(Device1ID[0], Device1ID[1]),
- Device1ID[0], Device1ID[1]);
+ GetPS2DeviceName(Device1ID[0], Device1ID[1]),
+ Device1ID[0], Device1ID[1]);
KernelPrint("PS/2 Port 2: %s (0x%X 0x%X)",
- GetPS2DeviceName(Device2ID[0], Device2ID[1]),
- Device2ID[0], Device2ID[1]);
+ GetPS2DeviceName(Device2ID[0], Device2ID[1]),
+ Device2ID[0], Device2ID[1]);
return 0;
}
diff --git a/input/aip/uart.c b/input/aip/uart.c
new file mode 100644
index 0000000..832ef8f
--- /dev/null
+++ b/input/aip/uart.c
@@ -0,0 +1,646 @@
+/*
+ This file is part of Fennix Drivers.
+
+ Fennix Drivers is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of
+ the License, or (at your option) any later version.
+
+ Fennix Drivers is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Fennix Drivers. If not, see .
+*/
+
+#include "aip.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#define SERIAL_ENABLE_DLAB 0x80
+#define SERIAL_BUFFER_EMPTY 0x20
+
+enum Ports
+{
+ COM1 = 0x3F8,
+ COM2 = 0x2F8,
+ COM3 = 0x3E8,
+ COM4 = 0x2E8,
+ COM5 = 0x5F8,
+ COM6 = 0x4F8,
+ COM7 = 0x5E8,
+ COM8 = 0x4E8,
+
+ LPT1 = 0x378,
+ LPT2 = 0x278,
+ LPT3 = 0x3BC
+};
+
+enum SerialSpeed
+{
+ RATE_50_HI = 0x09,
+ RATE_50_LO = 0x00,
+
+ RATE_300_HI = 0x01,
+ RATE_300_LO = 0x80,
+
+ RATE_600_HI = 0x00,
+ RATE_600_LO = 0xC0,
+
+ RATE_2400_HI = 0x00,
+ RATE_2400_LO = 0x30,
+
+ RATE_4800_HI = 0x00,
+ RATE_4800_LO = 0x18,
+
+ RATE_9600_HI = 0x00,
+ RATE_9600_LO = 0x0C,
+
+ RATE_19200_HI = 0x00,
+ RATE_19200_LO = 0x06,
+
+ RATE_38400_HI = 0x00,
+ RATE_38400_LO = 0x03,
+
+ RATE_57600_HI = 0x00,
+ RATE_57600_LO = 0x02,
+
+ RATE_115200_HI = 0x00,
+ RATE_115200_LO = 0x01
+};
+
+/*
+. Table of Registers .
+/---------------------------------------------------------------------\
+| Base Address | DLAB | R/W | Abr | Register Name |
+|---------------------------------------------------------------------|
+| +0 | =0 | W | - | Transmitter Holding Buffer |
+| | =0 | R | - | Receiver Buffer |
+| | =1 | R/W | - | Divisor Latch Low Byte |
+| +1 | =0 | R/W | IER | Interrupt Enable Register |
+| | =1 | R/W | - | Divisor Latch High Byte |
+| +2 | - | R | IIR | Interrupt Identification Register |
+| | - | W | FCR | FIFO Control Register |
+| +3 | - | R/W | LCR | Line Control Register |
+| +4 | - | R/W | MCR | Modem Control Register |
+| +5 | - | R | LSR | Line Status Register |
+| +6 | - | R | MSR | Modem Status Register |
+| +7 | - | R/W | - | Scratch Register |
+\---------------------------------------------------------------------/
+
+ Source:
+ Interfacing the Serial / RS232 Port V5.0
+ Table 5 : Table of Registers
+*/
+
+/** Interrupt Enable Register */
+typedef union
+{
+ struct
+ {
+ /* Enable Received Data Available Interrupt */
+ uint8_t InterruptOnReceive : 1;
+
+ /* Enable Transmitter Holding Register Empty Interrupt */
+ uint8_t InterruptOnTransmitter : 1;
+
+ /* Enable Receiver Line Status Interrupt */
+ uint8_t LineStatusInterrupt : 1;
+
+ /* Enable Modem Status Interrupt */
+ uint8_t ModemStatusInterrupt : 1;
+
+ /* Enables Sleep Mode (16750) */
+ uint8_t SleepMode : 1;
+
+ /* Enables Low Power Mode (16750) */
+ uint8_t LowPowerMode : 1;
+
+ /* Reserved */
+ uint8_t __reserved : 2;
+ };
+ uint8_t raw;
+} IER;
+
+/** Interrupt Identification Register */
+typedef union
+{
+ struct
+ {
+ /* Interrupt pending */
+ uint8_t InterruptPending : 1;
+
+ /**
+ * Interrupt Status
+ *
+ * 00b = Modem Status Interrupt
+ * 01b = Transmitter Holding Register Empty Interrupt
+ * 10b = Received Data Available Interrupt
+ * 11b = Receiver Line Status Interrupt
+ */
+ uint8_t InterruptStatus : 2;
+
+ /**
+ * 16550 Time-out Interrupt Pending
+ *
+ * @note Reserved on 8250, 16450
+ */
+ uint8_t TimeOutIP : 1;
+
+ /** Reserved */
+ uint8_t __reserved : 1;
+
+ /** 64 Byte Fifo Enabled (16750 only) */
+ uint8_t FIFO64 : 1;
+
+ /**
+ * Enable FIFO
+ *
+ * 00b = No FIFO
+ * 01b = FIFO Enabled but Unusable
+ * 11b = FIFO Enabled
+ */
+ uint8_t FIFO : 2;
+ };
+ uint8_t raw;
+} IIR;
+
+/** First In / First Out Control Register */
+typedef union
+{
+ struct
+ {
+ /** Enable FIFO's */
+ uint8_t FIFO : 1;
+
+ /** Clear Receive FIFO */
+ uint8_t ClearRX : 1;
+
+ /** Clear Transmit FIFO */
+ uint8_t ClearTX : 1;
+
+ /** DMA Mode Select.
+ *
+ * Change status of RXRDY & TXRDY pins from mode 1 to mode 2.
+ */
+ uint8_t DMAMode : 1;
+
+ /** Reserved */
+ uint8_t __reserved : 1;
+
+ /** Enable 64 Byte FIFO (16750 only) */
+ uint8_t FIFO64 : 1;
+
+ /** Interrupt Trigger Level
+ *
+ * 00b = 1 Byte
+ * 01b = 4 Bytes
+ * 10b = 8 Bytes
+ * 11b = 14 Bytes
+ */
+ uint8_t TriggerLevel : 2;
+ };
+ uint8_t raw;
+} FCR;
+
+/** Line Control Register */
+typedef union
+{
+ struct
+ {
+ /** Word Length
+ *
+ * 00b = 5 bits
+ * 01b = 6 bits
+ * 10b = 7 bits
+ * 11b = 8 bits
+ */
+ uint8_t WordLength : 2;
+
+ /** Length of Stop Bit
+ *
+ * 0b = One Stop Bit
+ * 1b = 2 Stop bits for words of length 6,7 or 8 bits or 1.5 Stop Bits for Word lengths of 5 bits.
+ */
+ uint8_t StopBit : 1;
+
+ /** Parity Select
+ *
+ * 0b = No Parity
+ * 001b = Odd Parity
+ * 011b = Even Parity
+ * 101b = High Parity (Sticky)
+ * 111b = Low Parity (Sticky)
+ */
+ uint8_t Parity : 3;
+
+ /** Set Break Enable */
+ uint8_t SetBreak : 1;
+
+ /**
+ * Divisor Latch Access
+ *
+ * 0b = Access to Receiver buffer, Transmitter buffer & Interrupt Enable Register
+ * 1b = Divisor Latch Access Bit
+ */
+ uint8_t DLAB : 1;
+ };
+ uint8_t raw;
+} LCR;
+
+/** Modem Control Register */
+typedef union
+{
+ struct
+ {
+ /** Force Data Terminal Ready */
+ uint8_t DataTerminalReady : 1;
+
+ /** Force Request to Send */
+ uint8_t RequestToSend : 1;
+
+ /** Auxiliary Output 1 */
+ uint8_t Out1 : 1;
+
+ /** Auxiliary Output 2 */
+ uint8_t Out2 : 1;
+
+ /** Loopback Mode */
+ uint8_t Loopback : 1;
+
+ /** Autoflow Control Enabled (16750 only) */
+ uint8_t Autoflow : 1;
+
+ /** Reserved */
+ uint8_t __reserved : 2;
+ };
+ uint8_t raw;
+} MCR;
+
+/** Line Status Register */
+typedef union
+{
+ struct
+ {
+ /** Data Ready */
+ uint8_t DataReady : 1;
+
+ /** Overrun Error */
+ uint8_t OverrunError : 1;
+
+ /** Parity Error */
+ uint8_t ParityError : 1;
+
+ /** Framing Error */
+ uint8_t FramingError : 1;
+
+ /** Break Interrupt */
+ uint8_t BreakInterrupt : 1;
+
+ /** Empty Transmitter Holding Register */
+ uint8_t EmptyTransmitterHolding : 1;
+
+ /** Empty Data Holding Registers */
+ uint8_t EmptyDataHolding : 1;
+
+ /** Error in Received FIFO */
+ uint8_t ErrorReceivedFIFO : 1;
+ };
+ uint8_t raw;
+} LSR;
+
+/** Modem Status Register */
+typedef union
+{
+ struct
+ {
+ /** Delta Clear to Send */
+ uint8_t DeltaClearToSend : 1;
+
+ /** Delta Data Set Ready */
+ uint8_t DeltaDataSetReady : 1;
+
+ /** Trailing Edge Ring Indicator */
+ uint8_t TrailingEdgeRingIndicator : 1;
+
+ /** Delta Data Carrier Detect */
+ uint8_t DeltaDataCarrierDetect : 1;
+
+ /** Clear To Send */
+ uint8_t ClearToSend : 1;
+
+ /** Data Set Ready */
+ uint8_t DataSetReady : 1;
+
+ /** Ring Indicator */
+ uint8_t RingIndicator : 1;
+
+ /** Carrier Detect */
+ uint8_t CarrierDetect : 1;
+ };
+ uint8_t raw;
+} MSR;
+
+union UARTs
+{
+ struct
+ {
+ uint8_t com1 : 1;
+ uint8_t com2 : 1;
+ uint8_t com3 : 1;
+ uint8_t com4 : 1;
+ uint8_t com5 : 1;
+ uint8_t com6 : 1;
+ uint8_t com7 : 1;
+ uint8_t com8 : 1;
+
+ uint8_t lpt1 : 1;
+ uint8_t lpt2 : 1;
+ uint8_t lpt3 : 1;
+
+ uint8_t __reserved : 5;
+ };
+ uint16_t raw;
+} uart;
+
+bool IsDataReady(uint16_t Port)
+{
+ LSR lsr;
+ lsr.raw = inb(Port + 5);
+ return lsr.DataReady;
+}
+
+bool IsTransmitEmpty(uint16_t Port)
+{
+ LSR lsr;
+ lsr.raw = inb(Port + 5);
+ return lsr.EmptyTransmitterHolding;
+}
+
+char ReadSerial(uint16_t Port)
+{
+ while (!IsDataReady(Port))
+ Yield();
+ return inb(Port);
+}
+
+void WriteSerial(uint16_t Port, char Character)
+{
+ while (!IsTransmitEmpty(Port))
+ Yield();
+ outb(Port, Character);
+}
+
+void ReportSerialReceived(uint8_t Data)
+{
+ DebugLog("%c", Data);
+}
+
+void UartCOM24(TrapFrame *)
+{
+ LSR lsr2, lsr4;
+ do
+ {
+ lsr2.raw = inb(COM2 + 5);
+ if (lsr2.DataReady)
+ ReportSerialReceived(inb(COM2));
+ lsr4.raw = inb(COM4 + 5);
+ if (lsr4.DataReady)
+ ReportSerialReceived(inb(COM4));
+ } while (lsr2.DataReady || lsr4.DataReady);
+}
+
+void UartCOM13(TrapFrame *)
+{
+ LSR lsr1, lsr3;
+ do
+ {
+ lsr1.raw = inb(COM1 + 5);
+ if (lsr1.DataReady)
+ ReportSerialReceived(inb(COM1));
+ lsr3.raw = inb(COM3 + 5);
+ if (lsr3.DataReady)
+ ReportSerialReceived(inb(COM3));
+ } while (lsr1.DataReady || lsr3.DataReady);
+}
+
+bool InitializePort(uint16_t Port)
+{
+ ECS;
+ LCR lcr = {0};
+ IER ier = {0};
+ FCR fcr = {0};
+ MCR mcr = {0};
+
+ outb(Port + 3, lcr.raw);
+ outb(Port + 1, ier.raw);
+
+ lcr.DLAB = 1;
+ outb(Port + 3, lcr.raw);
+
+ outb(Port + 0, RATE_115200_LO);
+ outb(Port + 1, RATE_115200_HI);
+
+ lcr.DLAB = 0;
+ lcr.WordLength = 0b11;
+ outb(Port + 3, lcr.raw);
+
+ fcr.FIFO = 1;
+ fcr.ClearRX = 1;
+ fcr.ClearTX = 1;
+ fcr.TriggerLevel = 0b11;
+ outb(Port + 2, fcr.raw);
+
+ mcr.DataTerminalReady = 1;
+ mcr.RequestToSend = 1;
+ mcr.Out2 = 1;
+ mcr.Loopback = 1;
+ outb(Port + 4, mcr.raw);
+
+ /* Test the serial port */
+ outb(Port + 0, 0x48);
+ uint8_t result = inb(Port + 0);
+ if (result != 0x48)
+ {
+ /* FIXME: DETECT BAUD RATE
+ Do multiple test to check if the output is garbage.
+ If so, reduce the baud rate until it works. */
+
+ LCS;
+ KernelPrint("Port %#X test failed!", Port);
+ return false;
+ }
+
+ /* Set normal operation mode */
+ mcr.DataTerminalReady = 1;
+ mcr.RequestToSend = 1;
+ mcr.Out1 = 1;
+ mcr.Out2 = 1;
+ mcr.Loopback = 0;
+ outb(Port + 4, mcr.raw);
+
+ /* Enable interrupts on receive */
+ ier.InterruptOnReceive = 1;
+ outb(Port + 1, ier.raw);
+ RegisterInterruptHandler(3, UartCOM24);
+ RegisterInterruptHandler(4, UartCOM13);
+
+ LCS;
+ KernelPrint("Port %#X initialized", Port);
+ return true;
+}
+
+int DetectUART()
+{
+ uart.com1 = inb(COM1) != 0xFF ? true : false;
+ uart.com2 = inb(COM2) != 0xFF ? true : false;
+ uart.com3 = inb(COM3) != 0xFF ? true : false;
+ uart.com4 = inb(COM4) != 0xFF ? true : false;
+ uart.com5 = inb(COM5) != 0xFF ? true : false;
+ uart.com6 = inb(COM6) != 0xFF ? true : false;
+ uart.com7 = inb(COM7) != 0xFF ? true : false;
+ uart.com8 = inb(COM8) != 0xFF ? true : false;
+
+ uart.lpt1 = inb(LPT1) != 0xFF ? true : false;
+ uart.lpt2 = inb(LPT2) != 0xFF ? true : false;
+ uart.lpt3 = inb(LPT3) != 0xFF ? true : false;
+
+ if (uart.com1 == true)
+ if (InitializePort(COM1) == false)
+ uart.com1 = false;
+
+ if (uart.com2 == true)
+ if (InitializePort(COM2) == false)
+ uart.com1 = false;
+
+ if (uart.com3 == true)
+ if (InitializePort(COM3) == false)
+ uart.com1 = false;
+
+ if (uart.com4 == true)
+ if (InitializePort(COM4) == false)
+ uart.com1 = false;
+
+ if (uart.com5 == true)
+ if (InitializePort(COM5) == false)
+ uart.com1 = false;
+
+ if (uart.com6 == true)
+ if (InitializePort(COM6) == false)
+ uart.com1 = false;
+
+ if (uart.com7 == true)
+ if (InitializePort(COM7) == false)
+ uart.com1 = false;
+
+ if (uart.com8 == true)
+ if (InitializePort(COM8) == false)
+ uart.com1 = false;
+
+ if (uart.lpt1 == true)
+ KernelPrint("LPT1 is present");
+
+ if (uart.lpt2 == true)
+ KernelPrint("LPT2 is present");
+
+ if (uart.lpt3 == true)
+ KernelPrint("LPT3 is present");
+ return 0;
+}
+
+// static int once = 0;
+// static uint8_t com4 = 0xFF;
+// if (!once++)
+// com4 = inb(0x2E8);
+// if (com4 == 0xFF)
+// CPU::Halt(true);
+// char UserInputBuffer[256]{'\0'};
+// int BackSpaceLimit = 0;
+// while (true)
+// {
+// while ((inb(0x2E8 + 5) & 1) == 0)
+// CPU::Pause();
+// char key = inb(0x2E8);
+// // debug("key: %d", key);
+// if (key == '\x7f') /* Backspace (DEL) */
+// {
+// if (BackSpaceLimit <= 0)
+// continue;
+// char keyBuf[5] = {'\b', '\x1b', '[', 'K', '\0'};
+// ExPrint(keyBuf);
+// backspace(UserInputBuffer);
+// BackSpaceLimit--;
+// continue;
+// }
+// else if (key == '\x0d') /* Enter (CR) */
+// {
+// UserInput(UserInputBuffer);
+// BackSpaceLimit = 0;
+// UserInputBuffer[0] = '\0';
+// continue;
+// }
+// else if (key == '\x1b') /* Escape */
+// {
+// char tmp[16]{'\0'};
+// append(tmp, key);
+// while ((inb(0x2E8 + 5) & 1) == 0)
+// CPU::Pause();
+// char key = inb(0x2E8);
+// append(tmp, key);
+// if (key == '[')
+// {
+// // 27 91
+// // < 68
+// // > 67
+// // down 66
+// // up 65
+// while ((inb(0x2E8 + 5) & 1) == 0)
+// CPU::Pause();
+// key = inb(0x2E8);
+// append(tmp, key);
+// switch (key)
+// {
+// case 'A':
+// key = KEY_D_UP;
+// break;
+// case 'B':
+// key = KEY_D_DOWN;
+// break;
+// case 'C':
+// key = KEY_D_RIGHT;
+// break;
+// case 'D':
+// key = KEY_D_LEFT;
+// break;
+// default:
+// {
+// for (size_t i = 0; i < strlen(tmp); i++)
+// {
+// if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit)
+// continue;
+// append(UserInputBuffer, tmp[i]);
+// BackSpaceLimit++;
+// char keyBuf[2] = {(char)tmp[i], '\0'};
+// ExPrint(keyBuf);
+// }
+// continue;
+// }
+// }
+// ArrowInput(key);
+// continue;
+// }
+// }
+
+// if ((int)sizeof(UserInputBuffer) <= BackSpaceLimit)
+// continue;
+// append(UserInputBuffer, key);
+// BackSpaceLimit++;
+// char keyBuf[2] = {(char)key, '\0'};
+// ExPrint(keyBuf);
+// }