diff --git a/kernel/api/fb.h b/kernel/api/fb.h deleted file mode 100644 index 6c229213..00000000 --- a/kernel/api/fb.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -enum { FBIOGET_INFO, FBIOSET_INFO }; - -struct fb_info { - size_t width; - size_t height; - size_t pitch; - size_t bpp; -}; diff --git a/kernel/api/linux/fb.h b/kernel/api/linux/fb.h new file mode 100644 index 00000000..7a784bd4 --- /dev/null +++ b/kernel/api/linux/fb.h @@ -0,0 +1,70 @@ +#pragma once + +#include + +#define FBIOGET_VSCREENINFO 0x4600 +#define FBIOPUT_VSCREENINFO 0x4601 +#define FBIOGET_FSCREENINFO 0x4602 + +struct fb_fix_screeninfo { + char id[16]; // identification string eg "TT Builtin" + unsigned long smem_start; // Start of frame buffer mem (physical address) + uint32_t smem_len; // Length of frame buffer mem + uint32_t type; // see FB_TYPE_* + uint32_t type_aux; // Interleave for interleaved Planes + uint32_t visual; // see FB_VISUAL_* + uint16_t xpanstep; // zero if no hardware panning + uint16_t ypanstep; // zero if no hardware panning + uint16_t ywrapstep; // zero if no hardware ywrap + uint32_t line_length; // length of a line in bytes + unsigned long mmio_start; // Start of Memory Mapped I/O (physical address) + uint32_t mmio_len; // Length of Memory Mapped I/O + uint32_t accel; // Indicate to driver which specific chip/card we have + uint16_t capabilities; // see FB_CAP_* + uint16_t reserved[2]; // Reserved for future compatibility +}; + +struct fb_bitfield { + uint32_t offset; // beginning of bitfield + uint32_t length; // length of bitfield + uint32_t msb_right; // != 0 : Most significant bit is right +}; + +struct fb_var_screeninfo { + uint32_t xres; // visible resolution + uint32_t yres; + uint32_t xres_virtual; // virtual resolution + uint32_t yres_virtual; + uint32_t xoffset; // offset from virtual to visible + uint32_t yoffset; // resolution + + uint32_t bits_per_pixel; // guess what + uint32_t grayscale; // 0 = color, 1 = grayscale, >1 = FOURCC + struct fb_bitfield red; // bitfield in fb mem if true color, + struct fb_bitfield green; // else only length is significant + struct fb_bitfield blue; + struct fb_bitfield transp; // transparency + + uint32_t nonstd; // != 0 Non standard pixel format + + uint32_t activate; // see FB_ACTIVATE_* + + uint32_t height; // height of picture in mm + uint32_t width; // width of picture in mm + + uint32_t accel_flags; // (OBSOLETE) see fb_info.flags + + // Timing: All values in pixclocks, except pixclock (of course) + uint32_t pixclock; // pixel clock in ps (pico seconds) + uint32_t left_margin; // time from sync to picture + uint32_t right_margin; // time from picture to sync + uint32_t upper_margin; // time from sync to picture + uint32_t lower_margin; + uint32_t hsync_len; // length of horizontal sync + uint32_t vsync_len; // length of vertical sync + uint32_t sync; // see FB_SYNC_* + uint32_t vmode; // see FB_VMODE_* + uint32_t rotate; // angle we rotate counter clockwise + uint32_t colorspace; // colorspace for FOURCC-based modes + uint32_t reserved[4]; // Reserved for future compatibility +}; diff --git a/kernel/drivers/graphics/bochs.c b/kernel/drivers/graphics/bochs.c index 32a63c99..eae4eeab 100644 --- a/kernel/drivers/graphics/bochs.c +++ b/kernel/drivers/graphics/bochs.c @@ -25,7 +25,9 @@ #define VBE_DISPI_LFB_ENABLED 0x40 static uintptr_t phys_addr; -static struct fb_info info; +static struct fb_info info = { + .id = "bochs", +}; static struct mutex lock; static void pci_device_callback(const struct pci_addr* addr, uint16_t vendor_id, diff --git a/kernel/drivers/graphics/fb.c b/kernel/drivers/graphics/fb.c index ffdc5764..62714d94 100644 --- a/kernel/drivers/graphics/fb.c +++ b/kernel/drivers/graphics/fb.c @@ -1,4 +1,6 @@ #include "graphics.h" +#include +#include #include #include #include @@ -28,29 +30,56 @@ static void* fb_device_mmap(struct file* file, size_t length, off_t offset, static int fb_device_ioctl(struct file* file, int request, void* user_argp) { (void)file; - struct fb_info info; switch (request) { - case FBIOGET_INFO: { + case FBIOGET_FSCREENINFO: { + struct fb_info info; int rc = fb->get_info(&info); if (IS_ERR(rc)) return rc; - break; + struct fb_fix_screeninfo fix = { + .smem_len = info.pitch * info.height, + .line_length = info.pitch, + }; + strlcpy(fix.id, info.id, sizeof(fix.id)); + if (copy_to_user(user_argp, &fix, sizeof(struct fb_fix_screeninfo))) + return -EFAULT; + return 0; } - case FBIOSET_INFO: { - if (copy_from_user(&info, user_argp, sizeof(struct fb_info))) + case FBIOGET_VSCREENINFO: { + struct fb_info info; + int rc = fb->get_info(&info); + if (IS_ERR(rc)) + return rc; + struct fb_var_screeninfo var = { + .xres = info.width, + .yres = info.height, + .xres_virtual = info.width, + .yres_virtual = info.height, + .bits_per_pixel = info.bpp, + .red = {.offset = 16, .length = 8}, + .green = {.offset = 8, .length = 8}, + .blue = {.offset = 0, .length = 8}, + }; + if (copy_to_user(user_argp, &var, sizeof(struct fb_var_screeninfo))) return -EFAULT; - int rc = fb->set_info(&info); + return 0; + } + case FBIOPUT_VSCREENINFO: { + struct fb_var_screeninfo var; + if (copy_from_user(&var, user_argp, sizeof(struct fb_var_screeninfo))) + return -EFAULT; + struct fb_info info; + int rc = fb->get_info(&info); if (IS_ERR(rc)) return rc; - break; + info.width = var.xres; + info.height = var.yres; + info.bpp = var.bits_per_pixel; + return fb->set_info(&info); } - default: - return -EINVAL; } - if (copy_to_user(user_argp, &info, sizeof(struct fb_info))) - return -EFAULT; - return 0; + return -EINVAL; } static struct inode* fb_device_get(void) { diff --git a/kernel/drivers/graphics/graphics.h b/kernel/drivers/graphics/graphics.h index 208c8e56..e1ad0360 100644 --- a/kernel/drivers/graphics/graphics.h +++ b/kernel/drivers/graphics/graphics.h @@ -1,7 +1,15 @@ #pragma once -#include #include +#include + +struct fb_info { + char id[16]; + size_t width; + size_t height; + size_t pitch; + size_t bpp; +}; struct fb { int (*get_info)(struct fb_info* out_info); diff --git a/kernel/drivers/graphics/multiboot.c b/kernel/drivers/graphics/multiboot.c index 4cedcc14..c8563c32 100644 --- a/kernel/drivers/graphics/multiboot.c +++ b/kernel/drivers/graphics/multiboot.c @@ -33,10 +33,13 @@ struct fb* multiboot_fb_init(const multiboot_info_t* mb_info) { return NULL; phys_addr = mb_info->framebuffer_addr; - info.width = mb_info->framebuffer_width; - info.height = mb_info->framebuffer_height; - info.pitch = mb_info->framebuffer_pitch; - info.bpp = mb_info->framebuffer_bpp; + info = (struct fb_info){ + .id = "multiboot", + .width = mb_info->framebuffer_width, + .height = mb_info->framebuffer_height, + .pitch = mb_info->framebuffer_pitch, + .bpp = mb_info->framebuffer_bpp, + }; kprintf("multiboot_fb: found framebuffer at P%#x\n", phys_addr); static struct fb fb = { diff --git a/userland/eyes.c b/userland/eyes.c index 70f8b37a..42586e12 100644 --- a/userland/eyes.c +++ b/userland/eyes.c @@ -1,8 +1,8 @@ #include "moused.h" #include #include -#include #include +#include #include #include #include @@ -14,7 +14,8 @@ #include static uint32_t* fb; -static struct fb_info fb_info; +static struct fb_fix_screeninfo fb_fix; +static struct fb_var_screeninfo fb_var; // based on "A Fast Bresenham Type Algorithm For Drawing Ellipses" // https://dai.fmph.uniba.sk/upload/0/01/Ellipse.pdf @@ -23,8 +24,8 @@ static void draw_ellipse_part(uint32_t cx, uint32_t cy, uint32_t x, uint32_t y, uint32_t color) { unsigned char* s = (unsigned char*)(fb + cx - x); size_t n = 2 * x + 1; - memset32((uint32_t*)(s + fb_info.pitch * (cy - y)), color, n); - memset32((uint32_t*)(s + fb_info.pitch * (cy + y)), color, n); + memset32((uint32_t*)(s + fb_fix.line_length * (cy - y)), color, n); + memset32((uint32_t*)(s + fb_fix.line_length * (cy + y)), color, n); } static void fill_ellipse(uint32_t cx, uint32_t cy, uint32_t x_radius, @@ -76,8 +77,8 @@ static void fill_ellipse(uint32_t cx, uint32_t cy, uint32_t x_radius, } static void draw_eyeball(unsigned i, uint32_t mouse_x, uint32_t mouse_y) { - uint32_t eye_width = fb_info.width / 2; - uint32_t eye_height = fb_info.height; + uint32_t eye_width = fb_var.xres / 2; + uint32_t eye_height = fb_var.yres; uint32_t eye_x = eye_width * i; uint32_t eye_y = 0; @@ -140,17 +141,22 @@ int main(void) { perror("open"); return EXIT_FAILURE; } - if (ioctl(fb_fd, FBIOGET_INFO, &fb_info) < 0) { + if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_fix) < 0) { perror("ioctl"); close(fb_fd); return EXIT_FAILURE; } - if (fb_info.bpp != 32) { + if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var) < 0) { + perror("ioctl"); + close(fb_fd); + return EXIT_FAILURE; + } + if (fb_var.bits_per_pixel != 32) { dprintf(STDERR_FILENO, "Unsupported bpp\n"); return EXIT_FAILURE; } - fb = mmap(NULL, fb_info.pitch * fb_info.height, PROT_READ | PROT_WRITE, - MAP_SHARED, fb_fd, 0); + fb = mmap(NULL, fb_fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, + 0); if (fb == MAP_FAILED) { perror("mmap"); close(fb_fd); @@ -171,8 +177,10 @@ int main(void) { return EXIT_FAILURE; } - struct moused_event event = {.x = fb_info.width / 2, - .y = fb_info.height / 2}; + struct moused_event event = { + .x = fb_var.xres / 2, + .y = fb_var.yres / 2, + }; for (;;) { draw(event.x, event.y); diff --git a/userland/imgview.c b/userland/imgview.c index 4820b3b7..2772bded 100644 --- a/userland/imgview.c +++ b/userland/imgview.c @@ -1,7 +1,7 @@ #include #include -#include #include +#include #include #include #include @@ -117,31 +117,31 @@ int main(int argc, char* const argv[]) { perror("open"); return EXIT_FAILURE; } - struct fb_info fb_info; - if (ioctl(fb_fd, FBIOGET_INFO, &fb_info) < 0) { + struct fb_fix_screeninfo fb_fix; + if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_fix) < 0) { perror("ioctl"); - close(fb_fd); - free(bytes); - return EXIT_FAILURE; + goto fail; } - if (fb_info.bpp != 32) { + struct fb_var_screeninfo fb_var; + if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var) < 0) { + perror("ioctl"); + goto fail; + } + if (fb_var.bits_per_pixel != 32) { dprintf(STDERR_FILENO, "Unsupported bit depth\n"); - close(fb_fd); - free(bytes); - return EXIT_FAILURE; + goto fail; } - void* fb = mmap(NULL, fb_info.pitch * fb_info.height, - PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0); + void* fb = mmap(NULL, fb_fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, + fb_fd, 0); if (fb == MAP_FAILED) { perror("mmap"); - close(fb_fd); - free(bytes); - return EXIT_FAILURE; + goto fail; } close(fb_fd); + fb_fd = -1; - size_t visible_width = MIN(width, fb_info.width); - size_t visible_height = MIN(height, fb_info.height); + size_t visible_width = MIN(width, fb_var.xres); + size_t visible_height = MIN(height, fb_var.yres); qoi_rgba_t index[64]; memset(index, 0, sizeof(index)); @@ -202,7 +202,7 @@ int main(int argc, char* const argv[]) { *pixel++ = (px.rgba.r << 16) | (px.rgba.g << 8) | px.rgba.b; } - fb_row_addr += fb_info.pitch; + fb_row_addr += fb_fix.line_length; } free(bytes); @@ -210,4 +210,10 @@ int main(int argc, char* const argv[]) { (void)getchar(); return EXIT_SUCCESS; + +fail: + if (fb_fd >= 0) + close(fb_fd); + free(bytes); + return EXIT_FAILURE; } diff --git a/userland/mandelbrot.c b/userland/mandelbrot.c index 59cf53b2..2d06fce3 100644 --- a/userland/mandelbrot.c +++ b/userland/mandelbrot.c @@ -1,6 +1,6 @@ #include -#include #include +#include #include #include #include @@ -102,19 +102,25 @@ int main(void) { perror("open"); return EXIT_FAILURE; } - struct fb_info fb_info; - if (ioctl(fd, FBIOGET_INFO, &fb_info) < 0) { + struct fb_fix_screeninfo fb_fix; + if (ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix) < 0) { perror("ioctl"); close(fd); return EXIT_FAILURE; } - if (fb_info.bpp != 32) { + struct fb_var_screeninfo fb_var; + if (ioctl(fd, FBIOGET_VSCREENINFO, &fb_var) < 0) { + perror("ioctl"); + close(fd); + return EXIT_FAILURE; + } + if (fb_var.bits_per_pixel != 32) { dprintf(STDERR_FILENO, "Unsupported bit depth\n"); close(fd); return EXIT_FAILURE; } - void* fb = mmap(NULL, fb_info.pitch * fb_info.height, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + void* fb = + mmap(NULL, fb_fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (fb == MAP_FAILED) { perror("mmap"); close(fd); @@ -123,21 +129,21 @@ int main(void) { close(fd); double width = VIEW_WIDTH; - double height = width * fb_info.height / fb_info.width; + double height = width * fb_var.yres / fb_var.xres; double left = (CENTER_X - width) / 2; double top = (CENTER_Y - height) / 2; uintptr_t row_addr = (uintptr_t)fb; - for (size_t y = 0; y < fb_info.height; ++y) { - double y0 = y * height / fb_info.height + top; + for (size_t y = 0; y < fb_var.yres; ++y) { + double y0 = y * height / fb_var.yres + top; uint32_t* pixel = (uint32_t*)row_addr; - for (size_t x = 0; x < fb_info.width; ++x) { - double x0 = x * width / fb_info.width + left; + for (size_t x = 0; x < fb_var.xres; ++x) { + double x0 = x * width / fb_var.xres + left; *pixel++ = calc_pixel_value(x0, y0); } - row_addr += fb_info.pitch; + row_addr += fb_fix.line_length; } (void)getchar(); diff --git a/userland/mouse-cursor.c b/userland/mouse-cursor.c index 0927dc67..5c585778 100644 --- a/userland/mouse-cursor.c +++ b/userland/mouse-cursor.c @@ -1,8 +1,8 @@ #include "moused.h" #include #include -#include #include +#include #include #include #include @@ -33,7 +33,8 @@ static const char mask[] = "x......." ".....xx."; static uintptr_t fb_addr; -static struct fb_info fb_info; +static struct fb_fix_screeninfo fb_fix; +static struct fb_var_screeninfo fb_var; static uint32_t cursor_x; static uint32_t cursor_y; static size_t visible_width; @@ -41,20 +42,20 @@ static size_t visible_height; static uint32_t fb_buf[CURSOR_WIDTH * CURSOR_HEIGHT]; static void move_cursor_to(uint32_t x, uint32_t y) { - cursor_x = MIN(fb_info.width - 1, x); - cursor_y = MIN(fb_info.height - 1, y); - visible_width = MIN(CURSOR_WIDTH, fb_info.width - cursor_x); - visible_height = MIN(CURSOR_HEIGHT, fb_info.height - cursor_y); + cursor_x = MIN(fb_var.xres - 1, x); + cursor_y = MIN(fb_var.yres - 1, y); + visible_width = MIN(CURSOR_WIDTH, fb_var.xres - cursor_x); + visible_height = MIN(CURSOR_HEIGHT, fb_var.yres - cursor_y); uintptr_t origin_addr = - fb_addr + cursor_x * sizeof(uint32_t) + cursor_y * fb_info.pitch; + fb_addr + cursor_x * sizeof(uint32_t) + cursor_y * fb_fix.line_length; // save framebuffer content to fb_buf uintptr_t row_addr = origin_addr; uint32_t* dest = fb_buf; for (size_t y = 0; y < visible_height; ++y) { memcpy32(dest, (uint32_t*)row_addr, visible_width); - row_addr += fb_info.pitch; + row_addr += fb_fix.line_length; dest += visible_width; } @@ -69,18 +70,18 @@ static void move_cursor_to(uint32_t x, uint32_t y) { *pixel = CURSOR_COLOR; ++pixel; } - row_addr += fb_info.pitch; + row_addr += fb_fix.line_length; row_mask += CURSOR_WIDTH; } } static void restore_fb(void) { uintptr_t row_addr = - fb_addr + cursor_x * sizeof(uint32_t) + cursor_y * fb_info.pitch; + fb_addr + cursor_x * sizeof(uint32_t) + cursor_y * fb_fix.line_length; uint32_t* src = fb_buf; for (size_t y = 0; y < visible_height; ++y) { memcpy32((uint32_t*)row_addr, src, visible_width); - row_addr += fb_info.pitch; + row_addr += fb_fix.line_length; src += visible_width; } } @@ -93,18 +94,23 @@ int main(void) { perror("open"); return EXIT_FAILURE; } - if (ioctl(fb_fd, FBIOGET_INFO, &fb_info) < 0) { + if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_fix) < 0) { perror("ioctl"); close(fb_fd); return EXIT_FAILURE; } - if (fb_info.bpp != 32) { + if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var) < 0) { + perror("ioctl"); + close(fb_fd); + return EXIT_FAILURE; + } + if (fb_var.bits_per_pixel != 32) { dprintf(STDERR_FILENO, "Unsupported bit depth\n"); close(fb_fd); return EXIT_FAILURE; } - void* fb = mmap(NULL, fb_info.pitch * fb_info.height, - PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0); + void* fb = mmap(NULL, fb_fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, + fb_fd, 0); if (fb == MAP_FAILED) { perror("mmap"); close(fb_fd); @@ -135,7 +141,7 @@ int main(void) { if (pid > 0) exit(0); - move_cursor_to(fb_info.width / 2, fb_info.height / 2); + move_cursor_to(fb_var.xres / 2, fb_var.yres / 2); struct moused_event event; for (;;) { diff --git a/userland/moused.c b/userland/moused.c index 1ade28f0..9e68191a 100644 --- a/userland/moused.c +++ b/userland/moused.c @@ -1,8 +1,8 @@ #include "moused.h" #include #include -#include #include +#include #include #include #include @@ -13,11 +13,11 @@ #include #include -static bool get_fb_info(struct fb_info* out_fb_info) { +static bool get_fb_info(struct fb_var_screeninfo* out_fb_var) { int fd = open("/dev/fb0", 0); if (fd < 0) return false; - if (ioctl(fd, FBIOGET_INFO, out_fb_info) < 0) { + if (ioctl(fd, FBIOGET_VSCREENINFO, out_fb_var) < 0) { close(fd); return false; } @@ -112,10 +112,10 @@ int main(void) { if (set_non_blocking(mouse_fd) < 0) goto fail; - struct fb_info fb_info; - if (get_fb_info(&fb_info)) { - width = fb_info.width; - height = fb_info.height; + struct fb_var_screeninfo fb_var; + if (get_fb_info(&fb_var)) { + width = fb_var.xres; + height = fb_var.yres; cursor_x = width / 2; cursor_y = height / 2; } diff --git a/userland/usertests.c b/userland/usertests.c index dca502d1..c994d295 100644 --- a/userland/usertests.c +++ b/userland/usertests.c @@ -1,7 +1,7 @@ #include #include -#include #include +#include #include #include #include @@ -488,19 +488,21 @@ static void test_framebuffer(void) { return; } - struct fb_info fb_info; - ASSERT_OK(ioctl(fd, FBIOGET_INFO, &fb_info)); + struct fb_fix_screeninfo fix; + ASSERT_OK(ioctl(fd, FBIOGET_FSCREENINFO, &fix)); + struct fb_var_screeninfo var; + ASSERT_OK(ioctl(fd, FBIOGET_VSCREENINFO, &var)); - size_t size = fb_info.pitch * fb_info.height; - void* fb = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + void* fb = + mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); ASSERT_OK(close(fd)); ASSERT(fb != MAP_FAILED); - void* buf = malloc(size); + void* buf = malloc(fix.smem_len); ASSERT(buf); - memcpy(buf, fb, size); - memcpy(fb, buf, size); + memcpy(buf, fb, fix.smem_len); + memcpy(fb, buf, fix.smem_len); free(buf); - ASSERT_OK(munmap(fb, size)); + ASSERT_OK(munmap(fb, fix.smem_len)); } static void test_malloc(void) {