From 3876b531222c53124b0eb154fb331c0c662f5e09 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Tue, 24 Jan 2012 00:07:44 -0500 Subject: [PATCH] vgabios: Add support for vbe get/set line length function. Signed-off-by: Kevin O'Connor --- vgasrc/bochsvga.c | 15 ++++++++++++++ vgasrc/bochsvga.h | 2 ++ vgasrc/clext.c | 51 +++++++++++++++++++---------------------------- vgasrc/clext.h | 2 ++ vgasrc/stdvga.c | 31 ++++++++++++++++++++++++++++ vgasrc/stdvga.h | 3 +++ vgasrc/vbe.c | 29 +++++++++++++++++++++++++-- vgasrc/vgabios.c | 16 +++++++++++++++ vgasrc/vgabios.h | 1 + vgasrc/vgahw.h | 16 +++++++++++++++ 10 files changed, 133 insertions(+), 33 deletions(-) diff --git a/vgasrc/bochsvga.c b/vgasrc/bochsvga.c index 74da887..2a4b0d5 100644 --- a/vgasrc/bochsvga.c +++ b/vgasrc/bochsvga.c @@ -217,6 +217,21 @@ bochsvga_set_window(struct vgamode_s *vmode_g, int window, int val) return 0; } +int +bochsvga_get_linelength(struct vgamode_s *vmode_g) +{ + return dispi_read(VBE_DISPI_INDEX_VIRT_WIDTH) * vga_bpp(vmode_g) / 8; +} + +int +bochsvga_set_linelength(struct vgamode_s *vmode_g, int val) +{ + stdvga_set_linelength(vmode_g, val); + int pixels = (val * 8) / vga_bpp(vmode_g); + dispi_write(VBE_DISPI_INDEX_VIRT_WIDTH, pixels); + return 0; +} + static void bochsvga_clear_scr(void) { diff --git a/vgasrc/bochsvga.h b/vgasrc/bochsvga.h index 26a82e0..b6abf0a 100644 --- a/vgasrc/bochsvga.h +++ b/vgasrc/bochsvga.h @@ -57,6 +57,8 @@ void bochsvga_list_modes(u16 seg, u16 *dest, u16 *last); struct vgamode_s *bochsvga_find_mode(int mode); int bochsvga_get_window(struct vgamode_s *vmode_g, int window); int bochsvga_set_window(struct vgamode_s *vmode_g, int window, int val); +int bochsvga_get_linelength(struct vgamode_s *vmode_g); +int bochsvga_set_linelength(struct vgamode_s *vmode_g, int val); int bochsvga_set_mode(struct vgamode_s *vmode_g, int flags); #endif // bochsvga.h diff --git a/vgasrc/clext.c b/vgasrc/clext.c index ee39c5e..27af810 100644 --- a/vgasrc/clext.c +++ b/vgasrc/clext.c @@ -415,6 +415,26 @@ clext_set_window(struct vgamode_s *vmode_g, int window, int val) return 0; } +int +clext_get_linelength(struct vgamode_s *vmode_g) +{ + u16 crtc_addr = stdvga_get_crtc(); + u8 reg13 = stdvga_crtc_read(crtc_addr, 0x13); + u8 reg1b = stdvga_crtc_read(crtc_addr, 0x1b); + return (((reg1b & 0x10) << 4) + reg13) * stdvga_bpp_factor(vmode_g) * 2; +} + +int +clext_set_linelength(struct vgamode_s *vmode_g, int val) +{ + u16 crtc_addr = stdvga_get_crtc(); + int factor = stdvga_bpp_factor(vmode_g) * 2; + int new_line_offset = DIV_ROUND_UP(val, factor); + stdvga_crtc_write(crtc_addr, 0x13, new_line_offset); + stdvga_crtc_mask(crtc_addr, 0x1b, 0x10, (new_line_offset & 0x100) >> 4); + return 0; +} + static void cirrus_enable_16k_granularity(void) { @@ -593,15 +613,6 @@ cirrus_get_bpp_bytes(void) return v; } -static void -cirrus_set_line_offset(u16 new_line_offset) -{ - new_line_offset /= 8; - u16 crtc_addr = stdvga_get_crtc(); - stdvga_crtc_write(crtc_addr, 0x13, new_line_offset); - stdvga_crtc_mask(crtc_addr, 0x1b, 0x10, (new_line_offset & 0x100) >> 4); -} - static u16 cirrus_get_line_offset(void) { @@ -634,27 +645,6 @@ cirrus_get_start_addr(void) | ((b4 & 0x80) << 12)); } -static void -cirrus_vesa_06h(struct bregs *regs) -{ - if (regs->bl > 2) { - regs->ax = 0x0100; - return; - } - - if (regs->bl == 0x00) { - cirrus_set_line_offset(cirrus_get_bpp_bytes() * regs->cx); - } else if (regs->bl == 0x02) { - cirrus_set_line_offset(regs->cx); - } - - u32 v = cirrus_get_line_offset(); - regs->cx = v / cirrus_get_bpp_bytes(); - regs->bx = v; - regs->dx = GET_GLOBAL(VBE_total_memory) / v; - regs->ax = 0x004f; -} - static void cirrus_vesa_07h(struct bregs *regs) { @@ -707,7 +697,6 @@ void cirrus_vesa(struct bregs *regs) { switch (regs->al) { - case 0x06: cirrus_vesa_06h(regs); break; case 0x07: cirrus_vesa_07h(regs); break; case 0x10: cirrus_vesa_10h(regs); break; default: cirrus_vesa_not_handled(regs); break; diff --git a/vgasrc/clext.h b/vgasrc/clext.h index b300cf4..55476a0 100644 --- a/vgasrc/clext.h +++ b/vgasrc/clext.h @@ -6,6 +6,8 @@ struct vgamode_s *clext_find_mode(int mode); int clext_get_window(struct vgamode_s *vmode_g, int window); int clext_set_window(struct vgamode_s *vmode_g, int window, int val); +int clext_get_linelength(struct vgamode_s *vmode_g); +int clext_set_linelength(struct vgamode_s *vmode_g, int val); int clext_set_mode(struct vgamode_s *vmode_g, int flags); void clext_list_modes(u16 seg, u16 *dest, u16 *last); int clext_init(void); diff --git a/vgasrc/stdvga.c b/vgasrc/stdvga.c index 9c0cba9..a310167 100644 --- a/vgasrc/stdvga.c +++ b/vgasrc/stdvga.c @@ -229,6 +229,22 @@ stdvga_get_crtc(void) return VGAREG_MDA_CRTC_ADDRESS; } +// Return the multiplication factor needed for the vga offset register. +int +stdvga_bpp_factor(struct vgamode_s *vmode_g) +{ + switch (GET_GLOBAL(vmode_g->memmodel)) { + case MM_TEXT: + return 2; + case MM_CGA: + return GET_GLOBAL(vmode_g->depth); + case MM_PLANAR: + return 1; + default: + return 4; + } +} + void stdvga_set_cursor_shape(u8 start, u8 end) { @@ -282,6 +298,21 @@ stdvga_set_window(struct vgamode_s *vmode_g, int window, int val) return -1; } +int +stdvga_get_linelength(struct vgamode_s *vmode_g) +{ + u8 val = stdvga_crtc_read(stdvga_get_crtc(), 0x13); + return val * stdvga_bpp_factor(vmode_g) * 2; +} + +int +stdvga_set_linelength(struct vgamode_s *vmode_g, int val) +{ + int factor = stdvga_bpp_factor(vmode_g) * 2; + stdvga_crtc_write(stdvga_get_crtc(), 0x13, DIV_ROUND_UP(val, factor)); + return 0; +} + /**************************************************************** * Save/Restore/Set state diff --git a/vgasrc/stdvga.h b/vgasrc/stdvga.h index 05f2bf5..ad496b5 100644 --- a/vgasrc/stdvga.h +++ b/vgasrc/stdvga.h @@ -129,6 +129,7 @@ void stdvga_planar4_plane(int plane); void stdvga_load_font(u16 seg, void *src_far, u16 count , u16 start, u8 destflags, u8 fontsize); u16 stdvga_get_crtc(void); +int stdvga_bpp_factor(struct vgamode_s *vmode_g); void stdvga_set_cursor_shape(u8 start, u8 end); void stdvga_set_active_page(u16 address); void stdvga_set_cursor_pos(u16 address); @@ -136,6 +137,8 @@ void stdvga_set_scan_lines(u8 lines); u16 stdvga_get_vde(void); int stdvga_get_window(struct vgamode_s *vmode_g, int window); int stdvga_set_window(struct vgamode_s *vmode_g, int window, int val); +int stdvga_get_linelength(struct vgamode_s *vmode_g); +int stdvga_set_linelength(struct vgamode_s *vmode_g, int val); void stdvga_save_state(u16 seg, struct saveVideoHardware *info); void stdvga_restore_state(u16 seg, struct saveVideoHardware *info); int stdvga_set_mode(struct vgamode_s *vmode_g, int flags); diff --git a/vgasrc/vbe.c b/vgasrc/vbe.c index 7e84794..68d2025 100644 --- a/vgasrc/vbe.c +++ b/vgasrc/vbe.c @@ -241,8 +241,33 @@ fail: static void vbe_104f06(struct bregs *regs) { - debug_stub(regs); - regs->ax = 0x0100; + if (regs->bl > 0x02) + goto fail; + struct vgamode_s *vmode_g = get_current_mode(); + if (! vmode_g) + goto fail; + int bpp = vga_bpp(vmode_g); + + if (regs->bl == 0x00) { + int ret = vgahw_set_linelength(vmode_g, DIV_ROUND_UP(regs->cx * bpp, 8)); + if (ret) + goto fail; + } else if (regs->bl == 0x02) { + int ret = vgahw_set_linelength(vmode_g, regs->cx); + if (ret) + goto fail; + } + int linelength = vgahw_get_linelength(vmode_g); + if (linelength < 0) + goto fail; + + regs->bx = linelength; + regs->cx = (linelength * 8) / bpp; + regs->dx = GET_GLOBAL(VBE_total_memory) / linelength; + regs->ax = 0x004f; + return; +fail: + regs->ax = 0x014f; } static void diff --git a/vgasrc/vgabios.c b/vgasrc/vgabios.c index d35cb02..d000166 100644 --- a/vgasrc/vgabios.c +++ b/vgasrc/vgabios.c @@ -63,6 +63,22 @@ struct pci_data rom_pci_data VAR16VISIBLE = { * Helper functions ****************************************************************/ +// Return the bits per pixel in system memory for a given mode. +int +vga_bpp(struct vgamode_s *vmode_g) +{ + switch (GET_GLOBAL(vmode_g->memmodel)) { + case MM_TEXT: + return 16; + case MM_PLANAR: + return 1; + } + u8 depth = GET_GLOBAL(vmode_g->depth); + if (depth > 8) + return ALIGN(depth, 8); + return depth; +} + u16 calc_page_size(u8 memmodel, u16 width, u16 height) { diff --git a/vgasrc/vgabios.h b/vgasrc/vgabios.h index 23d234a..aca95be 100644 --- a/vgasrc/vgabios.h +++ b/vgasrc/vgabios.h @@ -82,6 +82,7 @@ struct carattr { struct cursorpos { u8 x, y, page; }; +int vga_bpp(struct vgamode_s *vmode_g); u16 calc_page_size(u8 memmodel, u16 width, u16 height); struct vgamode_s *get_current_mode(void); int vga_set_mode(int mode, int flags); diff --git a/vgasrc/vgahw.h b/vgasrc/vgahw.h index ca8798c..494309b 100644 --- a/vgasrc/vgahw.h +++ b/vgasrc/vgahw.h @@ -61,4 +61,20 @@ static inline int vgahw_set_window(struct vgamode_s *vmode_g, int window return stdvga_set_window(vmode_g, window, val); } +static inline int vgahw_get_linelength(struct vgamode_s *vmode_g) { + if (CONFIG_VGA_CIRRUS) + return clext_get_linelength(vmode_g); + if (CONFIG_VGA_BOCHS) + return bochsvga_get_linelength(vmode_g); + return stdvga_get_linelength(vmode_g); +} + +static inline int vgahw_set_linelength(struct vgamode_s *vmode_g, int val) { + if (CONFIG_VGA_CIRRUS) + return clext_set_linelength(vmode_g, val); + if (CONFIG_VGA_BOCHS) + return bochsvga_set_linelength(vmode_g, val); + return stdvga_set_linelength(vmode_g, val); +} + #endif // vgahw.h -- 2.25.1