io: Complete serial support. Closes #155

This commit is contained in:
mintsuki 2022-03-01 17:53:46 +01:00
parent b1cf80c179
commit 93a00dee9b
6 changed files with 269 additions and 88 deletions

View File

@ -152,8 +152,10 @@ bool init_gop(struct fb_info *ret,
panic(false, "gop: Initialisation failed");
}
if (preset_mode == INVALID_PRESET_MODE)
if (preset_mode == INVALID_PRESET_MODE) {
preset_mode = gop->Mode->Mode;
current_video_mode = preset_mode;
}
struct resolution fallback_resolutions[] = {
{ 0, 0, 0 }, // Overridden by preset mode

12
common/drivers/serial.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __DRIVERS__SERIAL_H__
#define __DRIVERS__SERIAL_H__
#include <stdint.h>
void serial_out(uint8_t b);
#if bios == 1
int serial_in(void);
#endif
#endif

View File

@ -0,0 +1,76 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <drivers/serial.h>
#include <sys/cpu.h>
#include <lib/blib.h>
#if uefi == 1
# include <efi.h>
#endif
static bool serial_initialised = false;
#if uefi == 1
static EFI_SERIAL_IO_PROTOCOL *serial_protocol;
#endif
static void serial_initialise(void) {
if (serial_initialised) {
return;
}
#if uefi == 1
EFI_STATUS status;
EFI_GUID serial_guid = EFI_SERIAL_IO_PROTOCOL_GUID;
status = gBS->LocateProtocol(&serial_guid, NULL, (void **)&serial_protocol);
if (status) {
return;
}
serial_protocol->Reset(serial_protocol);
#endif
#if bios == 1
// Init com1
outb(0x3f8 + 1, 0x00);
outb(0x3f8 + 3, 0x80);
outb(0x3f8 + 0, 0x0c); // 9600 baud
outb(0x3f8 + 1, 0x00);
outb(0x3f8 + 3, 0x03);
outb(0x3f8 + 2, 0xc7);
outb(0x3f8 + 4, 0x0b);
#endif
serial_initialised = true;
}
void serial_out(uint8_t b) {
#if uefi == 1
if (efi_boot_services_exited) {
return;
}
#endif
serial_initialise();
#if uefi == 1
UINTN bsize = 1;
serial_protocol->Write(serial_protocol, &bsize, &b);
#elif bios == 1
while ((inb(0x3f8 + 5) & 0x20) == 0);
outb(0x3f8, b);
#endif
}
#if bios == 1
int serial_in(void) {
serial_initialise();
if ((inb(0x3f8 + 5) & 0x01) == 0) {
return -1;
}
return inb(0x3f8);
}
#endif

View File

@ -9,6 +9,7 @@
#include <lib/real.h>
#endif
#include <sys/cpu.h>
#include <drivers/serial.h>
#if bios == 1
static void s2_print(const char *s, size_t len) {
@ -140,27 +141,7 @@ void print(const char *fmt, ...) {
static char print_buf[PRINT_BUF_MAX];
static void serial_out(uint8_t b) {
while ((inb(0x3f8 + 5) & 0x20) == 0);
outb(0x3f8, b);
}
void vprint(const char *fmt, va_list args) {
static bool com_initialised = false;
if (COM_OUTPUT && !com_initialised) {
// Init com1
outb(0x3F8 + 1, 0x00);
outb(0x3F8 + 3, 0x80);
outb(0x3F8 + 0, 0x0c); // 9600 baud
outb(0x3F8 + 1, 0x00);
outb(0x3F8 + 3, 0x03);
outb(0x3F8 + 2, 0xc7);
outb(0x3F8 + 4, 0x0b);
com_initialised = true;
}
size_t print_buf_i = 0;
for (;;) {

View File

@ -10,6 +10,8 @@
#elif uefi == 1
# include <efi.h>
#endif
#include <drivers/serial.h>
#include <sys/cpu.h>
int getchar_internal(uint8_t scancode, uint8_t ascii, uint32_t shift_state) {
switch (scancode) {
@ -89,89 +91,171 @@ int getchar_internal(uint8_t scancode, uint8_t ascii, uint32_t shift_state) {
#if bios == 1
int getchar(void) {
uint8_t scancode = 0;
uint8_t ascii = 0;
uint32_t mods = 0;
again:;
struct rm_regs r = {0};
rm_int(0x16, &r, &r);
scancode = (r.eax >> 8) & 0xff;
ascii = r.eax & 0xff;
r = (struct rm_regs){ 0 };
r.eax = 0x0200; // GET SHIFT FLAGS
rm_int(0x16, &r, &r);
if (r.eax & GETCHAR_LCTRL) {
/* the bios subtracts 0x60 from ascii if ctrl is pressed */
mods = GETCHAR_LCTRL;
ascii += 0x60;
for (;;) {
int ret = pit_sleep_and_quit_on_keypress(65535);
if (ret != 0) {
return ret;
}
}
int ret = getchar_internal(scancode, ascii, mods);
if (ret == -1)
goto again;
return ret;
}
int _pit_sleep_and_quit_on_keypress(uint32_t ticks);
static int input_sequence(void) {
int val = 0;
for (;;) {
int ret = -1;
size_t retries = 0;
while (ret == -1 && retries < 1000000) {
ret = serial_in();
retries++;
}
if (ret == -1) {
return 0;
}
switch (ret) {
case 'A':
return GETCHAR_CURSOR_UP;
case 'B':
return GETCHAR_CURSOR_DOWN;
case 'C':
return GETCHAR_CURSOR_RIGHT;
case 'D':
return GETCHAR_CURSOR_LEFT;
case 'F':
return GETCHAR_END;
case 'H':
return GETCHAR_HOME;
}
if (ret > '9' || ret < '0') {
break;
}
val *= 10;
val += ret - '0';
}
switch (val) {
case 3:
return GETCHAR_DELETE;
case 5:
return GETCHAR_PGUP;
case 6:
return GETCHAR_PGDOWN;
case 21:
return GETCHAR_F10;
}
return 0;
}
int pit_sleep_and_quit_on_keypress(int seconds) {
return _pit_sleep_and_quit_on_keypress(seconds * 18);
for (int i = 0; i < seconds * 18; i++) {
int ret = _pit_sleep_and_quit_on_keypress(1);
if (ret != 0) {
return ret;
}
if (!serial) {
continue;
}
ret = serial_in();
if (ret != -1) {
again:
switch (ret) {
case '\r':
return '\n';
case 0x1b:
delay(10000);
ret = serial_in();
if (ret == -1) {
return GETCHAR_ESCAPE;
}
if (ret == '[') {
return input_sequence();
}
goto again;
}
return ret;
}
}
return 0;
}
#endif
#if uefi == 1
int getchar(void) {
static int input_sequence(bool ext,
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *exproto,
EFI_SIMPLE_TEXT_IN_PROTOCOL *sproto) {
EFI_STATUS status;
EFI_KEY_DATA kd;
UINTN which;
int val = 0;
EFI_EVENT events[1];
EFI_GUID exproto_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
EFI_GUID sproto_guid = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *exproto = NULL;
EFI_SIMPLE_TEXT_IN_PROTOCOL *sproto = NULL;
if (gBS->HandleProtocol(gST->ConsoleInHandle, &exproto_guid, (void **)&exproto) != EFI_SUCCESS) {
if (gBS->HandleProtocol(gST->ConsoleInHandle, &sproto_guid, (void **)&sproto) != EFI_SUCCESS) {
panic(false, "Your input device doesn't have an input protocol!");
for (;;) {
if (ext == false) {
status = sproto->ReadKeyStroke(sproto, &kd.Key);
} else {
status = exproto->ReadKeyStrokeEx(exproto, &kd);
}
events[0] = sproto->WaitForKey;
} else {
events[0] = exproto->WaitForKeyEx;
if (status != EFI_SUCCESS) {
return 0;
}
switch (kd.Key.UnicodeChar) {
case 'A':
return GETCHAR_CURSOR_UP;
case 'B':
return GETCHAR_CURSOR_DOWN;
case 'C':
return GETCHAR_CURSOR_RIGHT;
case 'D':
return GETCHAR_CURSOR_LEFT;
case 'F':
return GETCHAR_END;
case 'H':
return GETCHAR_HOME;
}
if (kd.Key.UnicodeChar > '9' || kd.Key.UnicodeChar < '0') {
break;
}
val *= 10;
val += kd.Key.UnicodeChar - '0';
}
again:
memset(&kd, 0, sizeof(EFI_KEY_DATA));
gBS->WaitForEvent(1, events, &which);
EFI_STATUS status;
if (events[0] == sproto->WaitForKey) {
status = sproto->ReadKeyStroke(sproto, &kd.Key);
} else {
status = exproto->ReadKeyStrokeEx(exproto, &kd);
switch (val) {
case 3:
return GETCHAR_DELETE;
case 5:
return GETCHAR_PGUP;
case 6:
return GETCHAR_PGDOWN;
case 21:
return GETCHAR_F10;
}
if (status != EFI_SUCCESS) {
goto again;
return 0;
}
int getchar(void) {
for (;;) {
int ret = pit_sleep_and_quit_on_keypress(65535);
if (ret != 0) {
return ret;
}
}
if ((kd.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) {
kd.KeyState.KeyShiftState = 0;
}
int ret = getchar_internal(kd.Key.ScanCode, kd.Key.UnicodeChar,
kd.KeyState.KeyShiftState);
if (ret == -1) {
goto again;
}
return ret;
}
int pit_sleep_and_quit_on_keypress(int seconds) {
@ -224,6 +308,32 @@ again:
kd.KeyState.KeyShiftState = 0;
}
if (kd.Key.ScanCode == SCAN_ESC) {
gBS->CreateEvent(EVT_TIMER, TPL_CALLBACK, NULL, NULL, &events[1]);
gBS->SetTimer(events[1], TimerRelative, 100000);
gBS->WaitForEvent(2, events, &which);
if (which == 1) {
return GETCHAR_ESCAPE;
}
if (events[0] == sproto->WaitForKey) {
status = sproto->ReadKeyStroke(sproto, &kd.Key);
} else {
status = exproto->ReadKeyStrokeEx(exproto, &kd);
}
if (status != EFI_SUCCESS) {
goto again;
}
if (kd.Key.UnicodeChar == '[') {
return input_sequence(events[0] == exproto->WaitForKeyEx, exproto, sproto);
}
}
int ret = getchar_internal(kd.Key.ScanCode, kd.Key.UnicodeChar,
kd.KeyState.KeyShiftState);

View File

@ -40,8 +40,8 @@ void term_vbe(size_t width, size_t height) {
}
if (serial) {
term_cols = 80;
term_rows = 24;
term_cols = term_cols > 80 ? 80 : term_cols;
term_rows = term_rows > 24 ? 24 : term_rows;
}
term_reinit();
@ -358,8 +358,8 @@ void term_textmode(void) {
init_vga_textmode(&term_rows, &term_cols, true);
if (serial) {
term_cols = 80;
term_rows = 24;
term_cols = term_cols > 80 ? 80 : term_cols;
term_rows = term_rows > 24 ? 24 : term_rows;
}
term_reinit();