Serial implementation Pt1
Serial testing with COM1 works - need to rework I/O to have it output tho. That's next.
This commit is contained in:
parent
d5f996973c
commit
981c224f55
5 changed files with 155 additions and 30 deletions
|
|
@ -7,6 +7,20 @@
|
||||||
#define KTTOOLS_H
|
#define KTTOOLS_H
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert a hex int to string, up to 32 bits.
|
||||||
|
*
|
||||||
|
* Converts int "num" into a null-terminated string, placed into buffer "buf".
|
||||||
|
* Evaluates from right to left, so left hand digits will be cut off if the buffer is too small
|
||||||
|
* Should work for non 32-bit integers actually, but is uint32_t for now.
|
||||||
|
*
|
||||||
|
* @param num: Value to convert to string
|
||||||
|
* @param buf: Memory to place the string into
|
||||||
|
* @param size: Size of the memory buffer
|
||||||
|
* @param radix: Base counting system to use for output
|
||||||
|
* @return No return value
|
||||||
|
*
|
||||||
|
*/
|
||||||
void i_to_str(uint32_t num, char* buf, int size, int radix);
|
void i_to_str(uint32_t num, char* buf, int size, int radix);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
47
include/serial.h
Normal file
47
include/serial.h
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* serial.h
|
||||||
|
* Serial Interface
|
||||||
|
*
|
||||||
|
* Send/receive data via serial ports.
|
||||||
|
*/
|
||||||
|
#ifndef SERIAL_H
|
||||||
|
#define SERIAL_H
|
||||||
|
#include "asm.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct SerialState_s {
|
||||||
|
uint16_t port;
|
||||||
|
} SerialState_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize a serial port for communication
|
||||||
|
* @param port The serial port number to initialize
|
||||||
|
* @return Status code indicating success or failure
|
||||||
|
*/
|
||||||
|
int serial_init(uint16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if there is pending data to receive on the serial port
|
||||||
|
* @return Non-zero if data is pending, 0 otherwise
|
||||||
|
*/
|
||||||
|
int serial_recv_pending();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Receive a single byte from the serial port
|
||||||
|
* @return The received byte as an 8-bit unsigned integer
|
||||||
|
*/
|
||||||
|
uint8_t serial_recv8(uint16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if the serial port is ready to send data
|
||||||
|
* @return Non-zero if ready to send, 0 otherwise
|
||||||
|
*/
|
||||||
|
int serial_send_pending(uint16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a single byte through the serial port
|
||||||
|
* @param data The 8-bit data byte to send
|
||||||
|
*/
|
||||||
|
int serial_send8(uint16_t port, char data);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -12,20 +12,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Convert a hex int to string, up to 32 bits.
|
|
||||||
*
|
|
||||||
* Converts int "num" into a null-terminated string, placed into buffer "buf".
|
|
||||||
* Evaluates from right to left, so left hand digits will be cut off if the buffer is too small
|
|
||||||
* Should work for non 32-bit integers actually, but is uint32_t for now.
|
|
||||||
*
|
|
||||||
* @param num: Value to convert to string
|
|
||||||
* @param buf: Memory to place the string into
|
|
||||||
* @param size: Size of the memory buffer
|
|
||||||
*
|
|
||||||
* @return No return value
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void i_to_str(uint32_t num, char* buf, int size, int radix) {
|
void i_to_str(uint32_t num, char* buf, int size, int radix) {
|
||||||
//null terminate the string
|
//null terminate the string
|
||||||
if(num == 0){
|
if(num == 0){
|
||||||
|
|
|
||||||
44
src/main.c
44
src/main.c
|
|
@ -1,32 +1,50 @@
|
||||||
//Our own code, at this point...
|
//Our own code, at this point...
|
||||||
//#include <stddef.h>
|
//Output table:
|
||||||
|
//0: VGA
|
||||||
|
//1: COM1
|
||||||
|
#define OUTPUT_TYPE 1
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "kttools.h"
|
#include "kttools.h"
|
||||||
#include "kmultiboot.h"
|
#include "kmultiboot.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
//finally, main.
|
#include "serial.h"
|
||||||
void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
void kern_main(uint32_t multiboot_magic, mb_info_t* multiboot_info)
|
||||||
{
|
{
|
||||||
//Hello C! Let's get to work in cleaning up our environment a bit and creating some safety.
|
//Hello C! Let's get to work in cleaning up our environment a bit and creating some safety.
|
||||||
//First interrupts.
|
//First interrupts.
|
||||||
setup_idt();
|
setup_idt();
|
||||||
|
|
||||||
//wipe the screen
|
//Let's pick an output schema.
|
||||||
|
int (*outWriter)(char) = 0;
|
||||||
|
int comstatus = 1234;
|
||||||
|
switch(OUTPUT_TYPE) {
|
||||||
|
case 1:
|
||||||
|
comstatus = serial_init(COM1);
|
||||||
|
if(comstatus) {
|
||||||
|
//Fail...
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
outWriter = serial_send8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//VGA is selected or the selected option failed, falling back
|
||||||
|
if(outWriter == 0){
|
||||||
|
outWriter = vga_out;
|
||||||
vga_clear();
|
vga_clear();
|
||||||
|
|
||||||
printf(vga_out, "Entry eax:%X\n", multiboot_magic);
|
|
||||||
|
|
||||||
if(multiboot_magic != 0x2BADB002) {
|
|
||||||
println(vga_out, "Bootloader not multiboot1 compliant! Needed for mmap, etc. Can't work without it, kthxbye!");
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
println(vga_out, "Multiboot detected! Continuing...");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(vga_out, "MEM_LOWER:%X\n", multiboot_info->mem_lower);
|
printf(outWriter, "Entry eax:%X\n", multiboot_magic);
|
||||||
printf(vga_out, "MEM_UPPER:%X\n", multiboot_info->mem_upper);
|
|
||||||
|
|
||||||
|
if(multiboot_magic != 0x2BADB002) {
|
||||||
|
println(outWriter, writerState, "Bootloader not multiboot1 compliant! Needed for mmap, etc. Can't work without it, kthxbye!");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
println(outWriter, writerState, "Multiboot detected! Continuing...");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(outWriter, writerState, "MEM_LOWER:%X\n", multiboot_info->mem_lower);
|
||||||
|
printf(outWriter, writerState"MEM_UPPER:%X\n", multiboot_info->mem_upper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
60
src/serial.c
Normal file
60
src/serial.c
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
#include "serial.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
int serial_init(uint16_t port) {
|
||||||
|
//disable interrupts when messing with it
|
||||||
|
outb(port + 1, 0x00);
|
||||||
|
//set the dlab latch in order to make the baud rate accessible. In binary for clarity.
|
||||||
|
outb(port + 3, 0b10000000);
|
||||||
|
|
||||||
|
//Sets the baud rate. Quick except on baud rate:
|
||||||
|
//internal clock for the serial controller is 115200 ticks/sec. Or 115200hz.
|
||||||
|
//This value we set, the "clock divisor", will check it every x ticks.
|
||||||
|
//So for example, if we wanted to check it every second, we'd want a divisor of 115200. Or, to check it as fast as possible, 1.
|
||||||
|
//Higher baud rates however equate to more error, so keep the divisor high.
|
||||||
|
//In ourcase, the osdev wiki uses 3 for the divisor, or 38400 baud, and we will go with this example until further notice.
|
||||||
|
//(Source:https://wiki.osdev.org/Serial_Ports#Baud_Rate)
|
||||||
|
|
||||||
|
//Baud lo byte
|
||||||
|
outb(port, 0x03);
|
||||||
|
//Baud hi byte
|
||||||
|
outb(port+1, 0x00);
|
||||||
|
|
||||||
|
//Again from OSWiki we're going to use their defaults for now.
|
||||||
|
//DLAB off
|
||||||
|
//Parity=0(no Parity)
|
||||||
|
//One stop bit (set to 0)
|
||||||
|
//Transmit in units of 8 bits
|
||||||
|
outb(port+3, 0b00000011);
|
||||||
|
|
||||||
|
//FIFO Control register
|
||||||
|
//14 bit threshold for interrupt trigger
|
||||||
|
//flush and enable FIFOs.
|
||||||
|
outb(port+2, 0b11000111);
|
||||||
|
|
||||||
|
//Enable IRQs + DTR + RTS
|
||||||
|
//Nicely explained here: https://stackoverflow.com/questions/957337/what-is-the-difference-between-dtr-dsr-and-rts-cts-flow-control
|
||||||
|
//In the future, this will be referred to 0x0B.
|
||||||
|
outb(port+4, 0b00001011);
|
||||||
|
|
||||||
|
//done! Let's test our chip. put it in loopback mode.
|
||||||
|
outb(port+4, 0x1E);
|
||||||
|
//Lets try sending C4 (boom!) to test it
|
||||||
|
outb(port, 0xC4);
|
||||||
|
|
||||||
|
if(inb(port) != 0xC4) {
|
||||||
|
//Boo womp
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//we're good! All set up. Lets put it back into normal operational mode and gtfo.
|
||||||
|
outb(port+4, 0x0B);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int serial_send_pending(uint16_t port) {
|
||||||
|
//Bit 5 of the line status register has our output queue, essentially
|
||||||
|
return !(inb(port + 5) & 0x20);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue