Pretty Much Finish Basic Serial Driver
This commit is contained in:
parent
b4388c9808
commit
16ab26257e
7
build.sh
7
build.sh
@ -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 --------
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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, ...);
|
||||
@ -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!");
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user