127 lines
3.1 KiB
C
127 lines
3.1 KiB
C
/*
|
|
* @author xamidev <xamidev@riseup.net>
|
|
* @brief Framebuffer-based terminal driver
|
|
* @license GPL-3.0-only
|
|
*/
|
|
|
|
// Terminal output
|
|
/*
|
|
There are a couple of bugs here and there but for now I don't care too much
|
|
because this shitty implementation will be replaced one day by Flanterm
|
|
(once memory management is okay: paging & kernel malloc)
|
|
*/
|
|
|
|
#include <limine.h>
|
|
#include <stddef.h>
|
|
#include <kernel.h>
|
|
#include "term.h"
|
|
#include "mem/misc/utils.h"
|
|
#include "config.h"
|
|
#include "flanterm.h"
|
|
|
|
extern struct boot_context boot_ctx;
|
|
|
|
// Importing the PSF object file
|
|
extern unsigned char _binary_zap_light16_psf_start[];
|
|
extern unsigned char _binary_zap_light16_psf_end[];
|
|
|
|
PSF1_Header* font = (PSF1_Header*)_binary_zap_light16_psf_start;
|
|
uint8_t* glyphs = _binary_zap_light16_psf_start + sizeof(PSF1_Header);
|
|
|
|
#define FONT_WIDTH 8
|
|
#define FONT_HEIGHT font->characterSize
|
|
|
|
extern struct flanterm_context* ft_ctx;
|
|
|
|
// Character cursor
|
|
typedef struct
|
|
{
|
|
size_t x;
|
|
size_t y;
|
|
} Cursor;
|
|
|
|
static Cursor cursor = {0, 0};
|
|
|
|
static uint8_t* fb;
|
|
static struct limine_framebuffer* framebuffer;
|
|
|
|
uint8_t lines_length[TERM_HISTORY_MAX_LINES];
|
|
|
|
static inline size_t term_max_cols(void)
|
|
{
|
|
return framebuffer->width / FONT_WIDTH;
|
|
}
|
|
|
|
static inline size_t term_max_lines(void)
|
|
{
|
|
return framebuffer->height / FONT_HEIGHT;
|
|
}
|
|
|
|
int term_init()
|
|
{
|
|
// Get framebuffer address from Limine struct
|
|
|
|
if (!boot_ctx.fb)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
framebuffer = boot_ctx.fb;
|
|
fb = (uint8_t*)framebuffer->address;
|
|
|
|
memset(lines_length, 0, sizeof(lines_length));
|
|
|
|
DEBUG("terminal initialized, fb=0x%p (width=%u height=%u pitch=%u bpp=%u)", fb, framebuffer->width, framebuffer->height, framebuffer->pitch, framebuffer->bpp);
|
|
return 0;
|
|
}
|
|
|
|
// These are marked "static" because we don't wanna expose them all around
|
|
// AKA they should just be seen here (kind of like private functions in cpp)
|
|
static inline void putpixel(size_t x, size_t y, uint32_t color)
|
|
{
|
|
// Guard so we don't write past fb boundaries
|
|
if (x >= framebuffer->width || y >= framebuffer->height) return;
|
|
// Depth isn't part of limine_framebuffer attributes so it will be 4
|
|
size_t pos = x*4 + y*framebuffer->pitch;
|
|
fb[pos] = color & 255; // blue channel
|
|
fb[pos+1] = (color >> 8) & 255; // green
|
|
fb[pos+2] = (color >> 16) & 255; // blue
|
|
}
|
|
|
|
void term_scroll()
|
|
{
|
|
// Erase first text line
|
|
memset(fb, 255, FONT_HEIGHT*framebuffer->pitch);
|
|
|
|
// Move whole framebuffer up by one text line
|
|
memmove(fb, fb+(FONT_HEIGHT*framebuffer->pitch), (framebuffer->height-FONT_HEIGHT)*framebuffer->pitch);
|
|
|
|
// Clear last text line
|
|
size_t clear_start = (framebuffer->height - FONT_HEIGHT) * framebuffer->pitch;
|
|
memset(fb + clear_start, 255, FONT_HEIGHT * framebuffer->pitch);
|
|
|
|
// Shift line lengths by 1 (for backspace handling)
|
|
size_t max_lines = term_max_lines();
|
|
for (size_t i = 1; i < max_lines; i++)
|
|
{
|
|
lines_length[i - 1] = lines_length[i];
|
|
}
|
|
lines_length[max_lines - 1] = 0;
|
|
}
|
|
|
|
// Overhead that could be avoided, right? (for printf)
|
|
void _putchar(char character)
|
|
{
|
|
flanterm_write(ft_ctx, &character, 1);
|
|
}
|
|
|
|
// Debug-printing
|
|
void kputs(const char* str)
|
|
{
|
|
size_t i=0;
|
|
while (str[i] != 0)
|
|
{
|
|
_putchar(str[i]);
|
|
i++;
|
|
}
|
|
} |