Pretty Much Finish Basic Serial Driver

This commit is contained in:
Tyler McGurrin 2025-05-31 11:59:11 -04:00
parent b4388c9808
commit 16ab26257e
5 changed files with 313 additions and 5 deletions

View File

@ -38,7 +38,12 @@ case $yn in
echo -------------
echo STARTING QEMU
echo -------------
qemu-system-i386 -audiodev pa,id=speaker -machine pcspk-audiodev=speaker -fda build/main_floppy.img
qemu-system-i386 -chardev pty,id=serial1 \
-serial mon:stdio \
-serial chardev:serial1 \
-audiodev pa,id=speaker \
-machine pcspk-audiodev=speaker \
-fda build/main_floppy.img
echo --------
echo Finshed!
echo --------

View File

@ -3,4 +3,279 @@
|Copyright (C) 2025|
|Tyler McGurrin |
\*----------------*/
#include "serial.h"
#include "serial.h"
#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <arch/i686/io.h>
char Serial_Read_Buffer;
char Serial_Write_Buffer;
/*
IO Port Offset Setting of DLAB I/O Access Register mapped to this port
+0 0 Read Receive buffer.
+0 0 Write Transmit buffer.
+1 0 Read/Write Interrupt Enable Register.
+0 1 Read/Write With DLAB set to 1, this is the least significant byte of the divisor value for setting the baud rate.
+1 1 Read/Write With DLAB set to 1, this is the most significant byte of the divisor value.
+2 - Read Interrupt Identification
+2 - Write FIFO control registers
+3 - Read/Write Line Control Register. The most significant bit of this register is the DLAB.
+4 - Read/Write Modem Control Register.
+5 - Read Line Status Register.
+6 - Read Modem Status Register.
+7 - Read/Write Scratch Register.
*/
// Cannot Figure out what part of spec triggers this,
// OSDEV wiki just says it exists thats about it...
void COM1_Serial_Handler()
{
// Serial_Read_Buffer = Read_Serial(COM1_PORT);
// printf("Serial Read Buffer: %s", Serial_Read_Buffer);
printf("IRQ 4 Triggered!");
}
int Init_Serial(uint16_t COM_Port, int Baud)
{
uint8_t Divisor = 115200 / Baud;
i686_outb(COM_Port + 1, 0x00); // Disable all interrupts
i686_outb(COM_Port + 3, Divisor); // Enable DLAB (set baud rate divisor)
i686_outb(COM_Port + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
i686_outb(COM_Port + 1, 0x00); // (hi byte)
i686_outb(COM_Port + 3, 0x03); // 8 bits, no parity, one stop bit
i686_outb(COM_Port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
i686_outb(COM_Port + 4, 0x0B); // IRQs enabled, RTS/DSR set
i686_outb(COM_Port + 4, 0x1E); // Set in loopback mode, test the serial chip
i686_outb(COM_Port + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
// Check if serial is faulty (i.e: not same byte as sent)
if(i686_inb(COM_Port + 0) != 0xAE) {
return 1;
}
// If serial is not faulty set it in normal operation mode
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
i686_outb(COM_Port + 4, 0x0F);
return 0;
}
int Serial_Received(uint16_t COM_Port)
{
return i686_inb(COM_Port + 5) & 1;
}
char Read_Serial(uint16_t COM_Port)
{
while (Serial_Received(COM_Port) == 0);
return i686_inb(COM_Port);
}
int Serial_Transmit_Empty(uint16_t COM_Port)
{
return i686_inb(COM_Port + 5) & 0x20;
}
void Write_Serial(uint16_t COM_Port, char a)
{
while (Serial_Transmit_Empty(COM_Port) == 0);
i686_outb(COM_Port,a);
}
// We do the funny...
extern const char g_HexChars[];
void Serial_Puts(uint16_t COM_Port, const char* str)
{
while(*str)
{
Write_Serial(COM_Port, *str);
str++;
}
}
void Serial_Printf_Unsigned(uint16_t COM_Port,unsigned long long number, int radix)
{
char buffer[32];
int pos = 0;
//number to ASCII conversion
do {
unsigned long long rem = number % radix;
number /= radix;
buffer[pos++] = g_HexChars[rem];
} while (number > 0);
//print number in reverse order
while (--pos >= 0)
Write_Serial(COM_Port, buffer[pos]);
}
void Serial_Printf_Signed(uint16_t COM_Port,long long number, int radix)
{
if (number < 0)
{
Write_Serial(COM_Port, '-');
Serial_Printf_Unsigned(COM_Port, -number, radix);
}
else Serial_Printf_Unsigned(COM_Port, number, radix);
}
#define PRINTF_STATE_NORMAL 0
#define PRINTF_STATE_LENGTH 1
#define PRINTF_STATE_LENGTH_SHORT 2
#define PRINTF_STATE_LENGTH_LONG 3
#define PRINTF_STATE_SPEC 4
#define PRINTF_LENGTH_DEFAULT 0
#define PRINTF_LENGTH_SHORT_SHORT 1
#define PRINTF_LENGTH_SHORT 2
#define PRINTF_LENGTH_LONG 3
#define PRINTF_LENGTH_LONG_LONG 4
void Serial_Printf(uint16_t COM_Port, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
int state = PRINTF_STATE_NORMAL;
int length = PRINTF_LENGTH_DEFAULT;
int radix = 10;
bool sign = false;
bool number = false;
while (*fmt)
{
switch (state)
{
case PRINTF_STATE_NORMAL:
switch (*fmt)
{
case '%': state = PRINTF_STATE_LENGTH;
break;
default: Write_Serial(COM_Port, *fmt);
break;
}
break;
case PRINTF_STATE_LENGTH:
switch (*fmt)
{
case 'h': length = PRINTF_LENGTH_SHORT;
state = PRINTF_STATE_LENGTH_SHORT;
break;
case 'l': length = PRINTF_LENGTH_LONG;
state = PRINTF_STATE_LENGTH_LONG;
break;
default: goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_LENGTH_SHORT:
if (*fmt == 'h')
{
length = PRINTF_LENGTH_SHORT_SHORT;
state = PRINTF_STATE_SPEC;
}
else goto PRINTF_STATE_SPEC_;
break;
case PRINTF_STATE_LENGTH_LONG:
if (*fmt == 'l')
{
length = PRINTF_LENGTH_LONG_LONG;
state = PRINTF_STATE_SPEC;
}
else goto PRINTF_STATE_SPEC_;
break;
case PRINTF_STATE_SPEC:
PRINTF_STATE_SPEC_:
switch (*fmt)
{
case 'c': Write_Serial(COM_Port, (char)va_arg(args, int));
break;
case 's':
Serial_Puts(COM_Port, va_arg(args, const char*));
break;
case '%': Write_Serial(COM_Port, '%');
break;
case 'd':
case 'i': radix = 10; sign = true; number = true;
break;
case 'u': radix = 10; sign = false; number = true;
break;
case 'X':
case 'x':
case 'p': radix = 16; sign = false; number = true;
break;
case 'o': radix = 8; sign = false; number = true;
break;
// ignore invalid spec
default: break;
}
if (number)
{
if (sign)
{
switch (length)
{
case PRINTF_LENGTH_SHORT_SHORT:
case PRINTF_LENGTH_SHORT:
case PRINTF_LENGTH_DEFAULT: Serial_Printf_Signed(COM_Port, va_arg(args, int), radix);
break;
case PRINTF_LENGTH_LONG: Serial_Printf_Signed(COM_Port, va_arg(args, long), radix);
break;
case PRINTF_LENGTH_LONG_LONG: Serial_Printf_Signed(COM_Port, va_arg(args, long long), radix);
break;
}
}
else
{
switch (length)
{
case PRINTF_LENGTH_SHORT_SHORT:
case PRINTF_LENGTH_SHORT:
case PRINTF_LENGTH_DEFAULT: Serial_Printf_Unsigned(COM_Port, va_arg(args, unsigned int), radix);
break;
case PRINTF_LENGTH_LONG: Serial_Printf_Unsigned(COM_Port, va_arg(args, unsigned long), radix);
break;
case PRINTF_LENGTH_LONG_LONG: Serial_Printf_Unsigned(COM_Port, va_arg(args, unsigned long long), radix);
break;
}
}
}
// reset state
state = PRINTF_STATE_NORMAL;
length = PRINTF_LENGTH_DEFAULT;
radix = 10;
sign = false;
number = false;
break;
}
fmt++;
}
va_end(args);
}

View File

@ -3,4 +3,28 @@
|Copyright (C) 2025|
|Tyler McGurrin |
\*----------------*/
#pragma once
#pragma once
#include <stdint.h>
// You can really only trust the first and 2nd COM port addresses...
// fun.
enum COMPorts
{
COM1_PORT = 0x3F8,
COM2_PORT = 0x2F8,
COM3_PORT = 0x3E8,
COM4_PORT = 0x2E8,
COM5_PORT = 0x5F8,
COM6_PORT = 0x4F8,
COM7_PORT = 0x5E8,
COM8_PORT = 0x4E8
};
void COM1_Serial_Handler();
int Serial_Received(uint16_t COM_Port);
char Read_Serial(uint16_t COM_Port);
int Serial_Transmit_Empty(uint16_t COM_Port);
void Write_Serial(uint16_t COM_Port, char a);
int Init_Serial(uint16_t COM_Port, int Baud);
void Serial_Printf(uint16_t COM_Port, const char* fmt, ...);

View File

@ -12,6 +12,7 @@
#include <arch/i686/basicfunc.h>
#include <dri/keyboard.h>
#include <dri/cmos.h>
#include <dri/serial.h>
#include <dri/fat.h>
#include <dri/disk/floppy.h>
#include <dri/disk/ata.h>
@ -57,8 +58,10 @@ void __attribute__((section(".entry"))) start(BootParams* bootParams) {
HAL_Initialize();
movecursorpos(19, 8);
printf("Done!\n\n\n\n\n");
Init_Serial(COM1_PORT, 9600);
i686_IRQ_RegisterHandler(0, timer);
i686_IRQ_RegisterHandler(8, CMOS_RTC_Handler);
i686_IRQ_RegisterHandler(4, COM1_Serial_Handler);
// Begin Loading Basic Drivers
printf("Load Keyboard Driver...");
@ -72,7 +75,8 @@ void __attribute__((section(".entry"))) start(BootParams* bootParams) {
slaveFDDType = Slave_FDD_Detect();
Floppy_Drive_Start(1);
Print_Storage_Types(masterFDDType, slaveFDDType);
printf("Kernel Params: %s\n", bootParams->KernelParams);
// printf("Kernel Params: %s\n", bootParams->KernelParams);
Serial_Printf(COM1_PORT, "Hello World!");

View File

@ -6,5 +6,5 @@
#pragma once
#define LOGO " _ _____ _ __________________\n / | / / | / | / / _/_ __/ ____/\n / |/ / /| | / |/ // / / / / __/ \n / /| / ___ |/ /| // / / / / /___ \n/_/ |_/_/ |_/_/ |_/___/ /_/ /_____/ \n"
#define VERSION "RD-00020"
#define VERSION "RD-00023"
#define BOOTLOGO " _ ______ ____ ____ ______\n / | / / __ )/ __ \\/ __ /_ __/\n / |/ / __ / / / / / / // / \n / /| / /_/ / /_/ / /_/ // / \n/_/ |_/_____/\\____/\\____//_/ \n"