diff options
author | dzwdz | 2022-08-01 16:33:44 +0200 |
---|---|---|
committer | dzwdz | 2022-08-01 20:35:49 +0200 |
commit | 6a85c6ede66f723e1415552482e1c6640653efa2 (patch) | |
tree | bb3790a2d1f42d9cf3c69654f20cbd53cc929038 /src/kernel/arch/amd64/driver | |
parent | 24a5f2bf46432aef70fd8d2ebf6c7ba94a6ce5a2 (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.c | 4 | ||||
-rw-r--r-- | src/kernel/arch/amd64/driver/video.c | 82 | ||||
-rw-r--r-- | src/kernel/arch/amd64/driver/video.h | 11 |
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); |