Skip to content

Commit

Permalink
drivers(graphics): adopt Linux framebuffer API
Browse files Browse the repository at this point in the history
  • Loading branch information
mosmeh committed Sep 14, 2024
1 parent d4ddb50 commit c4c0410
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 104 deletions.
12 changes: 0 additions & 12 deletions kernel/api/fb.h

This file was deleted.

70 changes: 70 additions & 0 deletions kernel/api/linux/fb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#pragma once

#include <stdint.h>

#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
};
4 changes: 3 additions & 1 deletion kernel/drivers/graphics/bochs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
53 changes: 41 additions & 12 deletions kernel/drivers/graphics/fb.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "graphics.h"
#include <common/string.h>
#include <kernel/api/linux/fb.h>
#include <kernel/api/sys/sysmacros.h>
#include <kernel/fs/fs.h>
#include <kernel/memory/memory.h>
Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 9 additions & 1 deletion kernel/drivers/graphics/graphics.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
#pragma once

#include <kernel/api/fb.h>
#include <kernel/api/sys/types.h>
#include <stddef.h>

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);
Expand Down
11 changes: 7 additions & 4 deletions kernel/drivers/graphics/multiboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
32 changes: 20 additions & 12 deletions userland/eyes.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include "moused.h"
#include <errno.h>
#include <extra.h>
#include <fb.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <math.h>
#include <panic.h>
#include <stdio.h>
Expand All @@ -14,7 +14,8 @@
#include <unistd.h>

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
Expand All @@ -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,
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand Down
42 changes: 24 additions & 18 deletions userland/imgview.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <errno.h>
#include <extra.h>
#include <fb.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <panic.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -202,12 +202,18 @@ 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);

(void)getchar();

return EXIT_SUCCESS;

fail:
if (fb_fd >= 0)
close(fb_fd);
free(bytes);
return EXIT_FAILURE;
}
Loading

0 comments on commit c4c0410

Please sign in to comment.