mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 18:44:01 +00:00
代码分类
This commit is contained in:
126
clks/kernel/hal/audio/pcspeaker.c
Normal file
126
clks/kernel/hal/audio/pcspeaker.c
Normal file
@@ -0,0 +1,126 @@
|
||||
#include <clks/audio.h>
|
||||
#include <clks/exec.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_AUDIO_PIT_BASE_HZ 1193182ULL
|
||||
#define CLKS_AUDIO_FREQ_MIN 20ULL
|
||||
#define CLKS_AUDIO_FREQ_MAX 20000ULL
|
||||
#define CLKS_AUDIO_TICKS_MAX 2048ULL
|
||||
|
||||
static clks_bool clks_audio_ready = CLKS_FALSE;
|
||||
static u64 clks_audio_played_count = 0ULL;
|
||||
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
static inline void clks_audio_outb(u16 port, u8 value) {
|
||||
__asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline u8 clks_audio_inb(u16 port) {
|
||||
u8 value;
|
||||
__asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static void clks_audio_program_pc_speaker(u64 hz) {
|
||||
u64 divisor64 = CLKS_AUDIO_PIT_BASE_HZ / hz;
|
||||
u16 divisor;
|
||||
u8 control;
|
||||
|
||||
if (divisor64 == 0ULL) {
|
||||
divisor64 = 1ULL;
|
||||
}
|
||||
|
||||
if (divisor64 > 0xFFFFULL) {
|
||||
divisor64 = 0xFFFFULL;
|
||||
}
|
||||
|
||||
divisor = (u16)divisor64;
|
||||
clks_audio_outb(0x43U, 0xB6U);
|
||||
clks_audio_outb(0x42U, (u8)(divisor & 0xFFU));
|
||||
clks_audio_outb(0x42U, (u8)((divisor >> 8) & 0xFFU));
|
||||
|
||||
control = clks_audio_inb(0x61U);
|
||||
clks_audio_outb(0x61U, (u8)(control | 0x03U));
|
||||
}
|
||||
#endif
|
||||
|
||||
static u64 clks_audio_clamp_hz(u64 hz) {
|
||||
if (hz < CLKS_AUDIO_FREQ_MIN) {
|
||||
return CLKS_AUDIO_FREQ_MIN;
|
||||
}
|
||||
|
||||
if (hz > CLKS_AUDIO_FREQ_MAX) {
|
||||
return CLKS_AUDIO_FREQ_MAX;
|
||||
}
|
||||
|
||||
return hz;
|
||||
}
|
||||
|
||||
void clks_audio_init(void) {
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
clks_audio_ready = CLKS_TRUE;
|
||||
clks_audio_played_count = 0ULL;
|
||||
clks_audio_stop();
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "AUDIO", "PC SPEAKER ONLINE");
|
||||
clks_log_hex(CLKS_LOG_INFO, "AUDIO", "PIT_BASE_HZ", CLKS_AUDIO_PIT_BASE_HZ);
|
||||
#else
|
||||
clks_audio_ready = CLKS_FALSE;
|
||||
clks_audio_played_count = 0ULL;
|
||||
clks_log(CLKS_LOG_WARN, "AUDIO", "AUDIO OUTPUT NOT AVAILABLE ON THIS ARCH");
|
||||
#endif
|
||||
}
|
||||
|
||||
clks_bool clks_audio_available(void) {
|
||||
return clks_audio_ready;
|
||||
}
|
||||
|
||||
clks_bool clks_audio_play_tone(u64 hz, u64 ticks) {
|
||||
if (clks_audio_ready == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (ticks == 0ULL) {
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
if (ticks > CLKS_AUDIO_TICKS_MAX) {
|
||||
ticks = CLKS_AUDIO_TICKS_MAX;
|
||||
}
|
||||
|
||||
if (hz == 0ULL) {
|
||||
clks_audio_stop();
|
||||
(void)clks_exec_sleep_ticks(ticks);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
hz = clks_audio_clamp_hz(hz);
|
||||
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
clks_audio_program_pc_speaker(hz);
|
||||
(void)clks_exec_sleep_ticks(ticks);
|
||||
clks_audio_stop();
|
||||
clks_audio_played_count++;
|
||||
return CLKS_TRUE;
|
||||
#else
|
||||
return CLKS_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void clks_audio_stop(void) {
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
u8 control;
|
||||
|
||||
if (clks_audio_ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
control = clks_audio_inb(0x61U);
|
||||
clks_audio_outb(0x61U, (u8)(control & 0xFCU));
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 clks_audio_play_count(void) {
|
||||
return clks_audio_played_count;
|
||||
}
|
||||
67
clks/kernel/hal/serial/serial.c
Normal file
67
clks/kernel/hal/serial/serial.c
Normal file
@@ -0,0 +1,67 @@
|
||||
#include <clks/compiler.h>
|
||||
#include <clks/serial.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
|
||||
#define CLKS_COM1_PORT 0x3F8
|
||||
|
||||
static inline void clks_x86_outb(u16 port, u8 value) {
|
||||
__asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline u8 clks_x86_inb(u16 port) {
|
||||
u8 value;
|
||||
__asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
void clks_serial_init(void) {
|
||||
clks_x86_outb(CLKS_COM1_PORT + 1, 0x00);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 3, 0x80);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 0, 0x03);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 1, 0x00);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 3, 0x03);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 2, 0xC7);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 4, 0x0B);
|
||||
}
|
||||
|
||||
void clks_serial_write_char(char ch) {
|
||||
while ((clks_x86_inb(CLKS_COM1_PORT + 5) & 0x20) == 0) {
|
||||
}
|
||||
|
||||
clks_x86_outb(CLKS_COM1_PORT, (u8)ch);
|
||||
}
|
||||
|
||||
#elif defined(CLKS_ARCH_AARCH64)
|
||||
|
||||
#define CLKS_PL011_BASE 0x09000000ULL
|
||||
#define CLKS_PL011_DR (*(volatile u32 *)(CLKS_PL011_BASE + 0x00))
|
||||
#define CLKS_PL011_FR (*(volatile u32 *)(CLKS_PL011_BASE + 0x18))
|
||||
#define CLKS_PL011_TXFF (1U << 5)
|
||||
|
||||
void clks_serial_init(void) {}
|
||||
|
||||
void clks_serial_write_char(char ch) {
|
||||
while ((CLKS_PL011_FR & CLKS_PL011_TXFF) != 0) {
|
||||
}
|
||||
|
||||
CLKS_PL011_DR = (u32)(u8)ch;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Unsupported architecture"
|
||||
#endif
|
||||
|
||||
void clks_serial_write(const char *text) {
|
||||
usize i = 0;
|
||||
|
||||
while (text[i] != '\0') {
|
||||
if (text[i] == '\n') {
|
||||
clks_serial_write_char('\r');
|
||||
}
|
||||
|
||||
clks_serial_write_char(text[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
53
clks/kernel/hal/video/font8x8.c
Normal file
53
clks/kernel/hal/video/font8x8.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "font8x8.h"
|
||||
|
||||
#include <clks/types.h>
|
||||
|
||||
struct clks_glyph8x8 {
|
||||
char ch;
|
||||
u8 rows[8];
|
||||
};
|
||||
|
||||
static const struct clks_glyph8x8 clks_font_table[] = {
|
||||
{' ', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, {'[', {0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E, 0x00}},
|
||||
{']', {0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00}}, {':', {0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00}},
|
||||
{'.', {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}}, {'-', {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}},
|
||||
{'/', {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00}}, {'_', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00}},
|
||||
{'?', {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00}}, {'0', {0x3C, 0x42, 0x46, 0x4A, 0x52, 0x62, 0x3C, 0x00}},
|
||||
{'1', {0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}}, {'2', {0x3C, 0x42, 0x02, 0x0C, 0x30, 0x40, 0x7E, 0x00}},
|
||||
{'3', {0x3C, 0x42, 0x02, 0x1C, 0x02, 0x42, 0x3C, 0x00}}, {'4', {0x0C, 0x14, 0x24, 0x44, 0x7E, 0x04, 0x04, 0x00}},
|
||||
{'5', {0x7E, 0x40, 0x7C, 0x02, 0x02, 0x42, 0x3C, 0x00}}, {'6', {0x1C, 0x20, 0x40, 0x7C, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'7', {0x7E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00}}, {'8', {0x3C, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'9', {0x3C, 0x42, 0x42, 0x3E, 0x02, 0x04, 0x38, 0x00}}, {'A', {0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}},
|
||||
{'B', {0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00}}, {'C', {0x3C, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3C, 0x00}},
|
||||
{'D', {0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00}}, {'E', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00}},
|
||||
{'F', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'G', {0x3C, 0x42, 0x40, 0x4E, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'H', {0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}}, {'I', {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}},
|
||||
{'J', {0x1E, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00}}, {'K', {0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00}},
|
||||
{'L', {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00}}, {'M', {0x42, 0x66, 0x5A, 0x5A, 0x42, 0x42, 0x42, 0x00}},
|
||||
{'N', {0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x00}}, {'O', {0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'P', {0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'Q', {0x3C, 0x42, 0x42, 0x42, 0x4A, 0x44, 0x3A, 0x00}},
|
||||
{'R', {0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x42, 0x00}}, {'S', {0x3C, 0x42, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00}},
|
||||
{'T', {0x7F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}}, {'U', {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'V', {0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00}}, {'W', {0x42, 0x42, 0x42, 0x5A, 0x5A, 0x66, 0x42, 0x00}},
|
||||
{'X', {0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x00}}, {'Y', {0x42, 0x42, 0x24, 0x18, 0x08, 0x08, 0x08, 0x00}},
|
||||
{'Z', {0x7E, 0x02, 0x04, 0x18, 0x20, 0x40, 0x7E, 0x00}},
|
||||
};
|
||||
|
||||
static const u8 clks_unknown[8] = {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00};
|
||||
|
||||
const u8 *clks_font8x8_get(char ch) {
|
||||
usize i;
|
||||
char upper = ch;
|
||||
|
||||
if (upper >= 'a' && upper <= 'z') {
|
||||
upper = (char)(upper - ('a' - 'A'));
|
||||
}
|
||||
|
||||
for (i = 0; i < (sizeof(clks_font_table) / sizeof(clks_font_table[0])); i++) {
|
||||
if (clks_font_table[i].ch == upper) {
|
||||
return clks_font_table[i].rows;
|
||||
}
|
||||
}
|
||||
|
||||
return clks_unknown;
|
||||
}
|
||||
8
clks/kernel/hal/video/font8x8.h
Normal file
8
clks/kernel/hal/video/font8x8.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef CLKS_FONT8X8_H
|
||||
#define CLKS_FONT8X8_H
|
||||
|
||||
#include <clks/types.h>
|
||||
|
||||
const u8 *clks_font8x8_get(char ch);
|
||||
|
||||
#endif
|
||||
315
clks/kernel/hal/video/framebuffer.c
Normal file
315
clks/kernel/hal/video/framebuffer.c
Normal file
@@ -0,0 +1,315 @@
|
||||
#include <clks/framebuffer.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#include "psf_font.h"
|
||||
|
||||
struct clks_fb_state {
|
||||
volatile u8 *address;
|
||||
struct clks_framebuffer_info info;
|
||||
const struct clks_psf_font *font;
|
||||
struct clks_psf_font external_font;
|
||||
clks_bool external_font_active;
|
||||
u32 glyph_width;
|
||||
u32 glyph_height;
|
||||
clks_bool ready;
|
||||
};
|
||||
|
||||
static struct clks_fb_state clks_fb = {
|
||||
.address = CLKS_NULL,
|
||||
.info = {0, 0, 0, 0},
|
||||
.font = CLKS_NULL,
|
||||
.external_font = {0, 0, 0, 0, 0, CLKS_NULL},
|
||||
.external_font_active = CLKS_FALSE,
|
||||
.glyph_width = 8U,
|
||||
.glyph_height = 8U,
|
||||
.ready = CLKS_FALSE,
|
||||
};
|
||||
|
||||
static void clks_fb_apply_font(const struct clks_psf_font *font) {
|
||||
clks_fb.font = font;
|
||||
clks_fb.glyph_width = 8U;
|
||||
clks_fb.glyph_height = 8U;
|
||||
|
||||
if (font != CLKS_NULL) {
|
||||
if (font->width != 0U) {
|
||||
clks_fb.glyph_width = font->width;
|
||||
}
|
||||
|
||||
if (font->height != 0U) {
|
||||
clks_fb.glyph_height = font->height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_fb_put_pixel(u32 x, u32 y, u32 rgb) {
|
||||
volatile u8 *row;
|
||||
volatile u32 *pixel;
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x >= clks_fb.info.width || y >= clks_fb.info.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fb.info.bpp != 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
row = clks_fb.address + ((usize)y * (usize)clks_fb.info.pitch);
|
||||
pixel = (volatile u32 *)(row + ((usize)x * 4U));
|
||||
*pixel = rgb;
|
||||
}
|
||||
|
||||
void clks_fb_init(const struct limine_framebuffer *fb) {
|
||||
if (fb == CLKS_NULL) {
|
||||
clks_fb.ready = CLKS_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
clks_fb.address = (volatile u8 *)fb->address;
|
||||
clks_fb.info.width = (u32)fb->width;
|
||||
clks_fb.info.height = (u32)fb->height;
|
||||
clks_fb.info.pitch = (u32)fb->pitch;
|
||||
clks_fb.info.bpp = fb->bpp;
|
||||
|
||||
clks_fb.external_font_active = CLKS_FALSE;
|
||||
clks_fb_apply_font(clks_psf_default_font());
|
||||
|
||||
clks_fb.ready = CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_fb_ready(void) {
|
||||
return clks_fb.ready;
|
||||
}
|
||||
|
||||
struct clks_framebuffer_info clks_fb_info(void) {
|
||||
return clks_fb.info;
|
||||
}
|
||||
|
||||
void clks_fb_draw_pixel(u32 x, u32 y, u32 rgb) {
|
||||
clks_fb_put_pixel(x, y, rgb);
|
||||
}
|
||||
|
||||
clks_bool clks_fb_read_pixel(u32 x, u32 y, u32 *out_rgb) {
|
||||
volatile u8 *row;
|
||||
volatile u32 *pixel;
|
||||
|
||||
if (out_rgb == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (x >= clks_fb.info.width || y >= clks_fb.info.height) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fb.info.bpp != 32) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
row = clks_fb.address + ((usize)y * (usize)clks_fb.info.pitch);
|
||||
pixel = (volatile u32 *)(row + ((usize)x * 4U));
|
||||
*out_rgb = *pixel;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
void clks_fb_fill_rect(u32 x, u32 y, u32 width, u32 height, u32 rgb) {
|
||||
u32 px;
|
||||
u32 py;
|
||||
u32 end_x;
|
||||
u32 end_y;
|
||||
u64 end_x64;
|
||||
u64 end_y64;
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (width == 0U || height == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x >= clks_fb.info.width || y >= clks_fb.info.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
end_x64 = (u64)x + (u64)width;
|
||||
end_y64 = (u64)y + (u64)height;
|
||||
|
||||
end_x = (end_x64 > (u64)clks_fb.info.width) ? clks_fb.info.width : (u32)end_x64;
|
||||
end_y = (end_y64 > (u64)clks_fb.info.height) ? clks_fb.info.height : (u32)end_y64;
|
||||
|
||||
for (py = y; py < end_y; py++) {
|
||||
for (px = x; px < end_x; px++) {
|
||||
clks_fb_put_pixel(px, py, rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clks_fb_clear(u32 rgb) {
|
||||
clks_fb_fill_rect(0U, 0U, clks_fb.info.width, clks_fb.info.height, rgb);
|
||||
}
|
||||
|
||||
void clks_fb_scroll_up(u32 pixel_rows, u32 fill_rgb) {
|
||||
usize row_bytes;
|
||||
usize move_bytes;
|
||||
u32 y;
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fb.info.bpp != 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pixel_rows == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pixel_rows >= clks_fb.info.height) {
|
||||
clks_fb_clear(fill_rgb);
|
||||
return;
|
||||
}
|
||||
|
||||
row_bytes = (usize)clks_fb.info.pitch;
|
||||
move_bytes = (usize)(clks_fb.info.height - pixel_rows) * row_bytes;
|
||||
|
||||
clks_memmove((void *)clks_fb.address, (const void *)(clks_fb.address + ((usize)pixel_rows * row_bytes)),
|
||||
move_bytes);
|
||||
|
||||
for (y = clks_fb.info.height - pixel_rows; y < clks_fb.info.height; y++) {
|
||||
volatile u32 *row_ptr = (volatile u32 *)(clks_fb.address + ((usize)y * row_bytes));
|
||||
u32 x;
|
||||
|
||||
for (x = 0U; x < clks_fb.info.width; x++) {
|
||||
row_ptr[x] = fill_rgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clks_fb_draw_char_styled(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb, u32 style_flags) {
|
||||
const u8 *glyph;
|
||||
u32 row;
|
||||
u32 col;
|
||||
u32 cols;
|
||||
u32 rows;
|
||||
u32 row_stride;
|
||||
u32 draw_cols;
|
||||
u32 draw_rows;
|
||||
clks_bool style_bold;
|
||||
clks_bool style_underline;
|
||||
u32 underline_row;
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE || clks_fb.font == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fb.info.bpp != 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x >= clks_fb.info.width || y >= clks_fb.info.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
glyph = clks_psf_glyph(clks_fb.font, (u32)(u8)ch);
|
||||
|
||||
cols = clks_fb.glyph_width;
|
||||
rows = clks_fb.glyph_height;
|
||||
|
||||
if (cols == 0U) {
|
||||
cols = 8U;
|
||||
}
|
||||
|
||||
if (rows == 0U) {
|
||||
rows = 8U;
|
||||
}
|
||||
|
||||
row_stride = clks_fb.font->bytes_per_row;
|
||||
|
||||
if (row_stride == 0U) {
|
||||
row_stride = (cols + 7U) / 8U;
|
||||
}
|
||||
|
||||
if (row_stride == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (((usize)row_stride * (usize)rows) > (usize)clks_fb.font->bytes_per_glyph) {
|
||||
return;
|
||||
}
|
||||
|
||||
draw_cols = cols;
|
||||
if (x + draw_cols > clks_fb.info.width) {
|
||||
draw_cols = clks_fb.info.width - x;
|
||||
}
|
||||
|
||||
draw_rows = rows;
|
||||
if (y + draw_rows > clks_fb.info.height) {
|
||||
draw_rows = clks_fb.info.height - y;
|
||||
}
|
||||
|
||||
style_bold = ((style_flags & CLKS_FB_STYLE_BOLD) != 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
style_underline = ((style_flags & CLKS_FB_STYLE_UNDERLINE) != 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
underline_row = (rows > 1U) ? (rows - 2U) : 0U;
|
||||
|
||||
for (row = 0U; row < draw_rows; row++) {
|
||||
const u8 *row_bits = glyph + ((usize)row * (usize)row_stride);
|
||||
volatile u32 *dst_row =
|
||||
(volatile u32 *)(clks_fb.address + ((usize)(y + row) * (usize)clks_fb.info.pitch) + ((usize)x * 4U));
|
||||
|
||||
for (col = 0U; col < draw_cols; col++) {
|
||||
u8 bits = row_bits[col >> 3U];
|
||||
u8 mask = (u8)(0x80U >> (col & 7U));
|
||||
clks_bool pixel_on = ((bits & mask) != 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
|
||||
if (style_bold == CLKS_TRUE && pixel_on == CLKS_FALSE && col > 0U) {
|
||||
u32 left_col = col - 1U;
|
||||
u8 left_bits = row_bits[left_col >> 3U];
|
||||
u8 left_mask = (u8)(0x80U >> (left_col & 7U));
|
||||
|
||||
if ((left_bits & left_mask) != 0U) {
|
||||
pixel_on = CLKS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (style_underline == CLKS_TRUE && row == underline_row) {
|
||||
pixel_on = CLKS_TRUE;
|
||||
}
|
||||
|
||||
dst_row[col] = (pixel_on == CLKS_TRUE) ? fg_rgb : bg_rgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb) {
|
||||
clks_fb_draw_char_styled(x, y, ch, fg_rgb, bg_rgb, 0U);
|
||||
}
|
||||
|
||||
clks_bool clks_fb_load_psf_font(const void *blob, u64 blob_size) {
|
||||
struct clks_psf_font parsed = {0, 0, 0, 0, 0, CLKS_NULL};
|
||||
|
||||
if (clks_psf_parse_font(blob, blob_size, &parsed) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_fb.external_font = parsed;
|
||||
clks_fb.external_font_active = CLKS_TRUE;
|
||||
clks_fb_apply_font(&clks_fb.external_font);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
u32 clks_fb_cell_width(void) {
|
||||
return clks_fb.glyph_width == 0U ? 8U : clks_fb.glyph_width;
|
||||
}
|
||||
|
||||
u32 clks_fb_cell_height(void) {
|
||||
return clks_fb.glyph_height == 0U ? 8U : clks_fb.glyph_height;
|
||||
}
|
||||
258
clks/kernel/hal/video/psf_font.c
Normal file
258
clks/kernel/hal/video/psf_font.c
Normal file
@@ -0,0 +1,258 @@
|
||||
#include "psf_font.h"
|
||||
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_PSF1_MAGIC0 0x36U
|
||||
#define CLKS_PSF1_MAGIC1 0x04U
|
||||
#define CLKS_PSF1_HEADER_SIZE 4U
|
||||
#define CLKS_PSF1_GLYPH_COUNT 256U
|
||||
#define CLKS_PSF1_GLYPH_BYTES 8U
|
||||
#define CLKS_PSF1_BLOB_SIZE (CLKS_PSF1_HEADER_SIZE + (CLKS_PSF1_GLYPH_COUNT * CLKS_PSF1_GLYPH_BYTES))
|
||||
|
||||
#define CLKS_PSF2_MAGIC 0x864AB572U
|
||||
#define CLKS_PSF2_HEADER_MIN_SIZE 32U
|
||||
|
||||
struct clks_psf1_header {
|
||||
u8 magic[2];
|
||||
u8 mode;
|
||||
u8 charsize;
|
||||
};
|
||||
|
||||
struct clks_psf2_header {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u32 headersize;
|
||||
u32 flags;
|
||||
u32 length;
|
||||
u32 charsize;
|
||||
u32 height;
|
||||
u32 width;
|
||||
};
|
||||
|
||||
struct clks_psf_seed_glyph {
|
||||
u8 code;
|
||||
u8 rows[CLKS_PSF1_GLYPH_BYTES];
|
||||
};
|
||||
|
||||
static const u8 clks_psf_unknown[CLKS_PSF1_GLYPH_BYTES] = {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00};
|
||||
|
||||
static const struct clks_psf_seed_glyph clks_psf_seed_table[] = {
|
||||
{' ', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, {'[', {0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E, 0x00}},
|
||||
{']', {0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00}}, {':', {0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00}},
|
||||
{'.', {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}}, {'-', {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}},
|
||||
{'/', {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00}}, {'_', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00}},
|
||||
{'?', {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00}}, {'0', {0x3C, 0x42, 0x46, 0x4A, 0x52, 0x62, 0x3C, 0x00}},
|
||||
{'1', {0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}}, {'2', {0x3C, 0x42, 0x02, 0x0C, 0x30, 0x40, 0x7E, 0x00}},
|
||||
{'3', {0x3C, 0x42, 0x02, 0x1C, 0x02, 0x42, 0x3C, 0x00}}, {'4', {0x0C, 0x14, 0x24, 0x44, 0x7E, 0x04, 0x04, 0x00}},
|
||||
{'5', {0x7E, 0x40, 0x7C, 0x02, 0x02, 0x42, 0x3C, 0x00}}, {'6', {0x1C, 0x20, 0x40, 0x7C, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'7', {0x7E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00}}, {'8', {0x3C, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'9', {0x3C, 0x42, 0x42, 0x3E, 0x02, 0x04, 0x38, 0x00}}, {'A', {0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}},
|
||||
{'B', {0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00}}, {'C', {0x3C, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3C, 0x00}},
|
||||
{'D', {0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00}}, {'E', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00}},
|
||||
{'F', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'G', {0x3C, 0x42, 0x40, 0x4E, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'H', {0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}}, {'I', {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}},
|
||||
{'J', {0x1E, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00}}, {'K', {0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00}},
|
||||
{'L', {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00}}, {'M', {0x42, 0x66, 0x5A, 0x5A, 0x42, 0x42, 0x42, 0x00}},
|
||||
{'N', {0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x00}}, {'O', {0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'P', {0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'Q', {0x3C, 0x42, 0x42, 0x42, 0x4A, 0x44, 0x3A, 0x00}},
|
||||
{'R', {0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x42, 0x00}}, {'S', {0x3C, 0x42, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00}},
|
||||
{'T', {0x7F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}}, {'U', {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'V', {0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00}}, {'W', {0x42, 0x42, 0x42, 0x5A, 0x5A, 0x66, 0x42, 0x00}},
|
||||
{'X', {0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x00}}, {'Y', {0x42, 0x42, 0x24, 0x18, 0x08, 0x08, 0x08, 0x00}},
|
||||
{'Z', {0x7E, 0x02, 0x04, 0x18, 0x20, 0x40, 0x7E, 0x00}},
|
||||
};
|
||||
|
||||
static u8 clks_psf_default_blob[CLKS_PSF1_BLOB_SIZE];
|
||||
static struct clks_psf_font clks_psf_default = {8U, 8U, 0U, 0U, 1U, CLKS_NULL};
|
||||
static clks_bool clks_psf_default_ready = CLKS_FALSE;
|
||||
|
||||
static clks_bool clks_psf_parse_psf1(const u8 *blob, usize blob_size, struct clks_psf_font *out_font) {
|
||||
const struct clks_psf1_header *hdr;
|
||||
u32 glyph_count;
|
||||
u32 glyph_bytes;
|
||||
usize payload_size;
|
||||
|
||||
if (blob == CLKS_NULL || out_font == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (blob_size < CLKS_PSF1_HEADER_SIZE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
hdr = (const struct clks_psf1_header *)blob;
|
||||
|
||||
if (hdr->magic[0] != CLKS_PSF1_MAGIC0 || hdr->magic[1] != CLKS_PSF1_MAGIC1) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
glyph_count = (hdr->mode & 0x01U) != 0U ? 512U : 256U;
|
||||
glyph_bytes = (u32)hdr->charsize;
|
||||
|
||||
if (glyph_bytes == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
payload_size = (usize)glyph_count * (usize)glyph_bytes;
|
||||
|
||||
if (blob_size < (usize)CLKS_PSF1_HEADER_SIZE + payload_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
out_font->width = 8U;
|
||||
out_font->height = glyph_bytes;
|
||||
out_font->glyph_count = glyph_count;
|
||||
out_font->bytes_per_glyph = glyph_bytes;
|
||||
out_font->bytes_per_row = 1U;
|
||||
out_font->glyphs = blob + CLKS_PSF1_HEADER_SIZE;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_psf_parse_psf2(const u8 *blob, usize blob_size, struct clks_psf_font *out_font) {
|
||||
const struct clks_psf2_header *hdr;
|
||||
u32 bytes_per_row;
|
||||
usize min_bytes_per_glyph;
|
||||
usize payload_size;
|
||||
|
||||
if (blob == CLKS_NULL || out_font == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (blob_size < CLKS_PSF2_HEADER_MIN_SIZE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
hdr = (const struct clks_psf2_header *)blob;
|
||||
|
||||
if (hdr->magic != CLKS_PSF2_MAGIC) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (hdr->headersize < CLKS_PSF2_HEADER_MIN_SIZE || hdr->headersize > blob_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (hdr->width == 0U || hdr->height == 0U || hdr->length == 0U || hdr->charsize == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
bytes_per_row = (hdr->width + 7U) / 8U;
|
||||
|
||||
if (bytes_per_row == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
min_bytes_per_glyph = (usize)bytes_per_row * (usize)hdr->height;
|
||||
|
||||
if (min_bytes_per_glyph > hdr->charsize) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if ((usize)hdr->length > (((usize)-1) / (usize)hdr->charsize)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
payload_size = (usize)hdr->length * (usize)hdr->charsize;
|
||||
|
||||
if (payload_size > (blob_size - (usize)hdr->headersize)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
out_font->width = hdr->width;
|
||||
out_font->height = hdr->height;
|
||||
out_font->glyph_count = hdr->length;
|
||||
out_font->bytes_per_glyph = hdr->charsize;
|
||||
out_font->bytes_per_row = bytes_per_row;
|
||||
out_font->glyphs = blob + hdr->headersize;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_psf_seed_default_blob(void) {
|
||||
struct clks_psf1_header *hdr;
|
||||
u32 i;
|
||||
|
||||
clks_memset(clks_psf_default_blob, 0, sizeof(clks_psf_default_blob));
|
||||
|
||||
hdr = (struct clks_psf1_header *)clks_psf_default_blob;
|
||||
hdr->magic[0] = CLKS_PSF1_MAGIC0;
|
||||
hdr->magic[1] = CLKS_PSF1_MAGIC1;
|
||||
hdr->mode = 0x00U;
|
||||
hdr->charsize = (u8)CLKS_PSF1_GLYPH_BYTES;
|
||||
|
||||
for (i = 0U; i < CLKS_PSF1_GLYPH_COUNT; i++) {
|
||||
u8 *dst = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)i * CLKS_PSF1_GLYPH_BYTES);
|
||||
clks_memcpy(dst, clks_psf_unknown, CLKS_PSF1_GLYPH_BYTES);
|
||||
}
|
||||
|
||||
for (i = 0U; i < (u32)(sizeof(clks_psf_seed_table) / sizeof(clks_psf_seed_table[0])); i++) {
|
||||
const struct clks_psf_seed_glyph *seed = &clks_psf_seed_table[i];
|
||||
u8 *dst = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)seed->code * CLKS_PSF1_GLYPH_BYTES);
|
||||
clks_memcpy(dst, seed->rows, CLKS_PSF1_GLYPH_BYTES);
|
||||
}
|
||||
|
||||
for (i = (u32)'A'; i <= (u32)'Z'; i++) {
|
||||
const u8 *upper = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)i * CLKS_PSF1_GLYPH_BYTES);
|
||||
u8 *lower = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)(i + ('a' - 'A')) * CLKS_PSF1_GLYPH_BYTES);
|
||||
clks_memcpy(lower, upper, CLKS_PSF1_GLYPH_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
const struct clks_psf_font *clks_psf_default_font(void) {
|
||||
if (clks_psf_default_ready == CLKS_FALSE) {
|
||||
clks_psf_seed_default_blob();
|
||||
|
||||
if (clks_psf_parse_psf1(clks_psf_default_blob, sizeof(clks_psf_default_blob), &clks_psf_default) ==
|
||||
CLKS_FALSE) {
|
||||
clks_psf_default.width = 8U;
|
||||
clks_psf_default.height = 8U;
|
||||
clks_psf_default.glyph_count = 1U;
|
||||
clks_psf_default.bytes_per_glyph = CLKS_PSF1_GLYPH_BYTES;
|
||||
clks_psf_default.bytes_per_row = 1U;
|
||||
clks_psf_default.glyphs = clks_psf_unknown;
|
||||
}
|
||||
|
||||
clks_psf_default_ready = CLKS_TRUE;
|
||||
}
|
||||
|
||||
return &clks_psf_default;
|
||||
}
|
||||
|
||||
const u8 *clks_psf_glyph(const struct clks_psf_font *font, u32 codepoint) {
|
||||
u32 index = codepoint;
|
||||
|
||||
if (font == CLKS_NULL || font->glyphs == CLKS_NULL || font->bytes_per_glyph == 0U) {
|
||||
return clks_psf_unknown;
|
||||
}
|
||||
|
||||
if (index >= font->glyph_count) {
|
||||
index = (u32)'?';
|
||||
|
||||
if (index >= font->glyph_count) {
|
||||
index = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
return font->glyphs + ((usize)index * (usize)font->bytes_per_glyph);
|
||||
}
|
||||
|
||||
clks_bool clks_psf_parse_font(const void *blob, u64 blob_size, struct clks_psf_font *out_font) {
|
||||
const u8 *bytes;
|
||||
u32 magic32;
|
||||
|
||||
if (blob == CLKS_NULL || out_font == CLKS_NULL || blob_size == 0ULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
bytes = (const u8 *)blob;
|
||||
|
||||
if (blob_size >= 4ULL) {
|
||||
magic32 = ((u32)bytes[0]) | (((u32)bytes[1]) << 8U) | (((u32)bytes[2]) << 16U) | (((u32)bytes[3]) << 24U);
|
||||
|
||||
if (magic32 == CLKS_PSF2_MAGIC) {
|
||||
return clks_psf_parse_psf2(bytes, (usize)blob_size, out_font);
|
||||
}
|
||||
}
|
||||
|
||||
return clks_psf_parse_psf1(bytes, (usize)blob_size, out_font);
|
||||
}
|
||||
19
clks/kernel/hal/video/psf_font.h
Normal file
19
clks/kernel/hal/video/psf_font.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef CLKS_PSF_FONT_H
|
||||
#define CLKS_PSF_FONT_H
|
||||
|
||||
#include <clks/types.h>
|
||||
|
||||
struct clks_psf_font {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 glyph_count;
|
||||
u32 bytes_per_glyph;
|
||||
u32 bytes_per_row;
|
||||
const u8 *glyphs;
|
||||
};
|
||||
|
||||
const struct clks_psf_font *clks_psf_default_font(void);
|
||||
const u8 *clks_psf_glyph(const struct clks_psf_font *font, u32 codepoint);
|
||||
clks_bool clks_psf_parse_font(const void *blob, u64 blob_size, struct clks_psf_font *out_font);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user