summaryrefslogtreecommitdiff
path: root/src/kernel/arch/amd64/driver
diff options
context:
space:
mode:
authordzwdz2022-08-01 16:33:44 +0200
committerdzwdz2022-08-01 20:35:49 +0200
commit6a85c6ede66f723e1415552482e1c6640653efa2 (patch)
treebb3790a2d1f42d9cf3c69654f20cbd53cc929038 /src/kernel/arch/amd64/driver
parent24a5f2bf46432aef70fd8d2ebf6c7ba94a6ce5a2 (diff)
amd64: /video/b device, provided by grub
Diffstat (limited to 'src/kernel/arch/amd64/driver')
-rw-r--r--src/kernel/arch/amd64/driver/fsroot.c4
-rw-r--r--src/kernel/arch/amd64/driver/video.c82
-rw-r--r--src/kernel/arch/amd64/driver/video.h11
3 files changed, 96 insertions, 1 deletions
diff --git a/src/kernel/arch/amd64/driver/fsroot.c b/src/kernel/arch/amd64/driver/fsroot.c
index 2feaf67..e0f5e77 100644
--- a/src/kernel/arch/amd64/driver/fsroot.c
+++ b/src/kernel/arch/amd64/driver/fsroot.c
@@ -58,11 +58,13 @@ static int handle(struct vfs_request *req) {
switch (id) {
case HANDLE_ROOT: {
// TODO document directory read format
+ // TODO don't hardcode
const char src[] =
"vga\0"
"com1\0"
"ps2\0"
- "ata/";
+ "ata/\0"
+ "video/";
return req_readcopy(req, src, sizeof src);
}
case HANDLE_VGA:
diff --git a/src/kernel/arch/amd64/driver/video.c b/src/kernel/arch/amd64/driver/video.c
new file mode 100644
index 0000000..8ace3d4
--- /dev/null
+++ b/src/kernel/arch/amd64/driver/video.c
@@ -0,0 +1,82 @@
+#include <camellia/fsutil.h>
+#include <camellia/errno.h>
+#include <kernel/arch/amd64/driver/video.h>
+#include <kernel/mem/virt.h>
+#include <kernel/panic.h>
+#include <kernel/vfs/request.h>
+
+static struct fb_info fb;
+
+enum {
+ H_ROOT,
+ H_FB,
+};
+
+/* stolen from fsroot.c, TODO shared copy? i guess? */
+static int req_readcopy(struct vfs_request *req, const void *buf, size_t len) {
+ if (!req->caller) return -1;
+ assert(req->type == VFSOP_READ);
+ fs_normslice(&req->offset, &req->output.len, len, false);
+ virt_cpy_to(
+ req->caller->pages, req->output.buf,
+ buf + req->offset, req->output.len);
+ /* read errors are ignored. TODO write docs */
+ return req->output.len;
+}
+
+static int handle(struct vfs_request *req) {
+ switch (req->type) {
+ case VFSOP_OPEN:
+ if (req->input.len == 1) {
+ return H_ROOT;
+ } else if (req->input.len == 2 && req->input.kern && req->input.buf_kern[1] == 'b') {
+ return H_FB;
+ } else {
+ return -1;
+ }
+
+ case VFSOP_READ:
+ if (req->id == H_ROOT) {
+ // TODO list available modes, e.g /640x480x24
+ const char src[] = "b";
+ return req_readcopy(req, src, sizeof src);
+ } else {
+ return req_readcopy(req, fb.b, fb.pitch * fb.height);
+ }
+
+ case VFSOP_WRITE:
+ if ((long)req->id != H_FB) {
+ return -1;
+ }
+ fs_normslice(&req->offset, &req->input.len, fb.pitch * fb.height, false);
+ if (!virt_cpy_from(req->caller->pages, fb.b + req->offset,
+ req->input.buf, req->input.len))
+ {
+ panic_invalid_state();
+ return -EFAULT;
+ }
+ return req->input.len;
+
+ default:
+ return -1;
+ }
+}
+
+static void accept(struct vfs_request *req) {
+ if (req->caller) {
+ vfsreq_finish_short(req, handle(req));
+ } else {
+ vfsreq_finish_short(req, -1);
+ }
+}
+
+static bool is_ready(struct vfs_backend *self) {
+ (void)self;
+ return true;
+}
+
+static struct vfs_backend backend = BACKEND_KERN(is_ready, accept);
+void video_init(struct fb_info fb_) {
+ fb = fb_;
+ vfs_mount_root_register("/video", &backend);
+}
diff --git a/src/kernel/arch/amd64/driver/video.h b/src/kernel/arch/amd64/driver/video.h
new file mode 100644
index 0000000..c1680c4
--- /dev/null
+++ b/src/kernel/arch/amd64/driver/video.h
@@ -0,0 +1,11 @@
+#pragma once
+#include <stdint.h>
+
+struct fb_info {
+ char *b;
+ uint32_t width, height;
+ uint32_t pitch; /* width in bytes of a single scanline */
+ uint8_t bpp;
+};
+
+void video_init(struct fb_info);