📄 vgacon.c
字号:
/* * linux/drivers/video/vgacon.c -- Low level VGA based console driver * * Created 28 Sep 1997 by Geert Uytterhoeven * * Rewritten by Martin Mares <mj@ucw.cz>, July 1998 * * This file is based on the old console.c, vga.c and vesa_blank.c drivers. * * Copyright (C) 1991, 1992 Linus Torvalds * 1995 Jay Estabrook * * User definable mapping table and font loading by Eugene G. Crosser, * <crosser@average.org> * * Improved loadable font/UTF-8 support by H. Peter Anvin * Feb-Sep 1995 <peter.anvin@linux.org> * * Colour palette handling, by Simon Tatham * 17-Jun-95 <sgt20@cam.ac.uk> * * if 512 char mode is already enabled don't re-enable it, * because it causes screen to flicker, by Mitja Horvat * 5-May-96 <mitja.horvat@guest.arnes.si> * * Use 2 outw instead of 4 outb_p to reduce erroneous text * flashing on RHS of screen during heavy console scrolling . * Oct 1996, Paul Gortmaker. * * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */#include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/console.h>#include <linux/string.h>#include <linux/kd.h>#include <linux/slab.h>#include <linux/vt_kern.h>#include <linux/selection.h>#include <linux/spinlock.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/screen_info.h>#include <linux/smp_lock.h>#include <video/vga.h>#include <asm/io.h>static DEFINE_SPINLOCK(vga_lock);static int cursor_size_lastfrom;static int cursor_size_lastto;static u32 vgacon_xres;static u32 vgacon_yres;static struct vgastate state;#define BLANK 0x0020#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */#define CAN_LOAD_PALETTE /* undefine if the user must not do this *//* You really do _NOT_ want to define this, unless you have buggy * Trident VGA which will resize cursor when moving it between column * 15 & 16. If you define this and your VGA is OK, inverse bug will * appear. */#undef TRIDENT_GLITCH#define VGA_FONTWIDTH 8 /* VGA does not support fontwidths != 8 *//* * Interface used by the world */static const char *vgacon_startup(void);static void vgacon_init(struct vc_data *c, int init);static void vgacon_deinit(struct vc_data *c);static void vgacon_cursor(struct vc_data *c, int mode);static int vgacon_switch(struct vc_data *c);static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);static int vgacon_set_palette(struct vc_data *vc, unsigned char *table);static int vgacon_scrolldelta(struct vc_data *c, int lines);static int vgacon_set_origin(struct vc_data *c);static void vgacon_save_screen(struct vc_data *c);static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines);static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);static unsigned long vgacon_uni_pagedir[2];/* Description of the hardware situation */static int vga_init_done __read_mostly;static unsigned long vga_vram_base __read_mostly; /* Base of video memory */static unsigned long vga_vram_end __read_mostly; /* End of video memory */static unsigned int vga_vram_size __read_mostly; /* Size of video memory */static u16 vga_video_port_reg __read_mostly; /* Video register select port */static u16 vga_video_port_val __read_mostly; /* Video register value port */static unsigned int vga_video_num_columns; /* Number of text columns */static unsigned int vga_video_num_lines; /* Number of text lines */static int vga_can_do_color __read_mostly; /* Do we support colors? */static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */static unsigned char vga_video_type __read_mostly; /* Card type */static unsigned char vga_hardscroll_enabled __read_mostly;static unsigned char vga_hardscroll_user_enable __read_mostly = 1;static unsigned char vga_font_is_default = 1;static int vga_vesa_blanked;static int vga_palette_blanked;static int vga_is_gfx;static int vga_512_chars;static int vga_video_font_height;static int vga_scan_lines __read_mostly;static unsigned int vga_rolled_over;int vgacon_text_mode_force = 0;bool vgacon_text_force(void){ return vgacon_text_mode_force ? true : false;}EXPORT_SYMBOL(vgacon_text_force);static int __init text_mode(char *str){ vgacon_text_mode_force = 1; return 1;}/* force text mode - used by kernel modesetting */__setup("nomodeset", text_mode);static int __init no_scroll(char *str){ /* * Disabling scrollback is required for the Braillex ib80-piezo * Braille reader made by F.H. Papenmeier (Germany). * Use the "no-scroll" bootflag. */ vga_hardscroll_user_enable = vga_hardscroll_enabled = 0; return 1;}__setup("no-scroll", no_scroll);/* * By replacing the four outb_p with two back to back outw, we can reduce * the window of opportunity to see text mislocated to the RHS of the * console during heavy scrolling activity. However there is the remote * possibility that some pre-dinosaur hardware won't like the back to back * I/O. Since the Xservers get away with it, we should be able to as well. */static inline void write_vga(unsigned char reg, unsigned int val){ unsigned int v1, v2; unsigned long flags; /* * ddprintk might set the console position from interrupt * handlers, thus the write has to be IRQ-atomic. */ spin_lock_irqsave(&vga_lock, flags);#ifndef SLOW_VGA v1 = reg + (val & 0xff00); v2 = reg + 1 + ((val << 8) & 0xff00); outw(v1, vga_video_port_reg); outw(v2, vga_video_port_reg);#else outb_p(reg, vga_video_port_reg); outb_p(val >> 8, vga_video_port_val); outb_p(reg + 1, vga_video_port_reg); outb_p(val & 0xff, vga_video_port_val);#endif spin_unlock_irqrestore(&vga_lock, flags);}static inline void vga_set_mem_top(struct vc_data *c){ write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);}#ifdef CONFIG_VGACON_SOFT_SCROLLBACK#include <linux/bootmem.h>/* software scrollback */static void *vgacon_scrollback;static int vgacon_scrollback_tail;static int vgacon_scrollback_size;static int vgacon_scrollback_rows;static int vgacon_scrollback_cnt;static int vgacon_scrollback_cur;static int vgacon_scrollback_save;static int vgacon_scrollback_restore;static void vgacon_scrollback_init(int pitch){ int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch; if (vgacon_scrollback) { vgacon_scrollback_cnt = 0; vgacon_scrollback_tail = 0; vgacon_scrollback_cur = 0; vgacon_scrollback_rows = rows - 1; vgacon_scrollback_size = rows * pitch; }}/* * Called only duing init so call of alloc_bootmen is ok. * Marked __init_refok to silence modpost. */static void __init_refok vgacon_scrollback_startup(void){ vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024); vgacon_scrollback_init(vga_video_num_columns * 2);}static void vgacon_scrollback_update(struct vc_data *c, int t, int count){ void *p; if (!vgacon_scrollback_size || c->vc_num != fg_console) return; p = (void *) (c->vc_origin + t * c->vc_size_row); while (count--) { scr_memcpyw(vgacon_scrollback + vgacon_scrollback_tail, p, c->vc_size_row); vgacon_scrollback_cnt++; p += c->vc_size_row; vgacon_scrollback_tail += c->vc_size_row; if (vgacon_scrollback_tail >= vgacon_scrollback_size) vgacon_scrollback_tail = 0; if (vgacon_scrollback_cnt > vgacon_scrollback_rows) vgacon_scrollback_cnt = vgacon_scrollback_rows; vgacon_scrollback_cur = vgacon_scrollback_cnt; }}static void vgacon_restore_screen(struct vc_data *c){ vgacon_scrollback_save = 0; if (!vga_is_gfx && !vgacon_scrollback_restore) { scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); vgacon_scrollback_restore = 1; vgacon_scrollback_cur = vgacon_scrollback_cnt; }}static int vgacon_scrolldelta(struct vc_data *c, int lines){ int start, end, count, soff; if (!lines) { c->vc_visible_origin = c->vc_origin; vga_set_mem_top(c); return 1; } if (!vgacon_scrollback) return 1; if (!vgacon_scrollback_save) { vgacon_cursor(c, CM_ERASE); vgacon_save_screen(c); vgacon_scrollback_save = 1; } vgacon_scrollback_restore = 0; start = vgacon_scrollback_cur + lines; end = start + abs(lines); if (start < 0) start = 0; if (start > vgacon_scrollback_cnt) start = vgacon_scrollback_cnt; if (end < 0) end = 0; if (end > vgacon_scrollback_cnt) end = vgacon_scrollback_cnt; vgacon_scrollback_cur = start; count = end - start; soff = vgacon_scrollback_tail - ((vgacon_scrollback_cnt - end) * c->vc_size_row); soff -= count * c->vc_size_row; if (soff < 0) soff += vgacon_scrollback_size; count = vgacon_scrollback_cnt - start; if (count > c->vc_rows) count = c->vc_rows; if (count) { int copysize; int diff = c->vc_rows - count; void *d = (void *) c->vc_origin; void *s = (void *) c->vc_screenbuf; count *= c->vc_size_row; /* how much memory to end of buffer left? */ copysize = min(count, vgacon_scrollback_size - soff); scr_memcpyw(d, vgacon_scrollback + soff, copysize); d += copysize; count -= copysize; if (count) { scr_memcpyw(d, vgacon_scrollback, count); d += count; } if (diff) scr_memcpyw(d, s, diff * c->vc_size_row); } else vgacon_cursor(c, CM_MOVE); return 1;}#else#define vgacon_scrollback_startup(...) do { } while (0)#define vgacon_scrollback_init(...) do { } while (0)#define vgacon_scrollback_update(...) do { } while (0)static void vgacon_restore_screen(struct vc_data *c){ if (c->vc_origin != c->vc_visible_origin) vgacon_scrolldelta(c, 0);}static int vgacon_scrolldelta(struct vc_data *c, int lines){ if (!lines) /* Turn scrollback off */ c->vc_visible_origin = c->vc_origin; else { int margin = c->vc_size_row * 4; int ul, we, p, st; if (vga_rolled_over > (c->vc_scr_end - vga_vram_base) + margin) { ul = c->vc_scr_end - vga_vram_base; we = vga_rolled_over + c->vc_size_row; } else { ul = 0; we = vga_vram_size; } p = (c->vc_visible_origin - vga_vram_base - ul + we) % we + lines * c->vc_size_row; st = (c->vc_origin - vga_vram_base - ul + we) % we; if (st < 2 * margin) margin = 0; if (p < margin) p = 0; if (p > st - margin) p = st; c->vc_visible_origin = vga_vram_base + (p + ul) % we; } vga_set_mem_top(c); return 1;}#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */static const char *vgacon_startup(void){ const char *display_desc = NULL; u16 saved1, saved2; volatile u16 *p; if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) { no_vga:#ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; return conswitchp->con_startup();#else return NULL;#endif } /* boot_params.screen_info initialized? */ if ((screen_info.orig_video_mode == 0) && (screen_info.orig_video_lines == 0) && (screen_info.orig_video_cols == 0)) goto no_vga; /* VGA16 modes are not handled by VGACON */ if ((screen_info.orig_video_mode == 0x0D) || /* 320x200/4 */ (screen_info.orig_video_mode == 0x0E) || /* 640x200/4 */ (screen_info.orig_video_mode == 0x10) || /* 640x350/4 */ (screen_info.orig_video_mode == 0x12) || /* 640x480/4 */ (screen_info.orig_video_mode == 0x6A)) /* 800x600/4 (VESA) */ goto no_vga; vga_video_num_lines = screen_info.orig_video_lines; vga_video_num_columns = screen_info.orig_video_cols; state.vgabase = NULL; if (screen_info.orig_video_mode == 7) { /* Monochrome display */ vga_vram_base = 0xb0000; vga_video_port_reg = VGA_CRT_IM; vga_video_port_val = VGA_CRT_DM; if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) { static struct resource ega_console_resource = { .name = "ega", .start = 0x3B0, .end = 0x3BF }; vga_video_type = VIDEO_TYPE_EGAM; vga_vram_size = 0x8000; display_desc = "EGA+"; request_resource(&ioport_resource, &ega_console_resource); } else { static struct resource mda1_console_resource = { .name = "mda", .start = 0x3B0, .end = 0x3BB }; static struct resource mda2_console_resource = { .name = "mda", .start = 0x3BF, .end = 0x3BF }; vga_video_type = VIDEO_TYPE_MDA; vga_vram_size = 0x2000; display_desc = "*MDA"; request_resource(&ioport_resource, &mda1_console_resource); request_resource(&ioport_resource, &mda2_console_resource); vga_video_font_height = 14; } } else { /* If not, it is color. */ vga_can_do_color = 1; vga_vram_base = 0xb8000; vga_video_port_reg = VGA_CRT_IC; vga_video_port_val = VGA_CRT_DC; if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) { int i; vga_vram_size = 0x8000; if (!screen_info.orig_video_isVGA) { static struct resource ega_console_resource = { .name = "ega", .start = 0x3C0, .end = 0x3DF }; vga_video_type = VIDEO_TYPE_EGAC; display_desc = "EGA"; request_resource(&ioport_resource, &ega_console_resource); } else { static struct resource vga_console_resource = { .name = "vga+", .start = 0x3C0, .end = 0x3DF }; vga_video_type = VIDEO_TYPE_VGAC; display_desc = "VGA+"; request_resource(&ioport_resource, &vga_console_resource);#ifdef VGA_CAN_DO_64KB /* * get 64K rather than 32K of video RAM. * This doesn't actually work on all "VGA" * controllers (it seems like setting MM=01 * and COE=1 isn't necessarily a good idea) */ vga_vram_base = 0xa0000; vga_vram_size = 0x10000; outb_p(6, VGA_GFX_I); outb_p(6, VGA_GFX_D);#endif /* * Normalise the palette registers, to point * the 16 screen colours to the first 16 * DAC entries.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -