📄 vgacon.c
字号:
unsigned short video_port_status = vga_video_port_reg + 6; int font_select = 0x00, beg, i; char *charmap; if (vga_video_type != VIDEO_TYPE_EGAM) { charmap = (char *) VGA_MAP_MEM(colourmap); beg = 0x0e;#ifdef VGA_CAN_DO_64KB if (vga_video_type == VIDEO_TYPE_VGAC) beg = 0x06;#endif } else { charmap = (char *) VGA_MAP_MEM(blackwmap); beg = 0x0a; }#ifdef BROKEN_GRAPHICS_PROGRAMS /* * All fonts are loaded in slot 0 (0:1 for 512 ch) */ if (!arg) return -EINVAL; /* Return to default font not supported */ vga_font_is_default = 0; font_select = ch512 ? 0x04 : 0x00;#else /* * The default font is kept in slot 0 and is never touched. * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch) */ if (set) { vga_font_is_default = !arg; if (!arg) ch512 = 0; /* Default font is always 256 */ font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00; } if (!vga_font_is_default) charmap += 4 * cmapsz;#endif unlock_kernel(); spin_lock_irq(&vga_lock); /* First, the Sequencer */ vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); /* CPU writes only to map 2 */ vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04); /* Sequential addressing */ vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07); /* Clear synchronous reset */ vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); /* Now, the graphics controller, select map 2 */ vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02); /* disable odd-even addressing */ vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00); /* map start at A000:0000 */ vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00); spin_unlock_irq(&vga_lock); if (arg) { if (set) for (i = 0; i < cmapsz; i++) vga_writeb(arg[i], charmap + i); else for (i = 0; i < cmapsz; i++) arg[i] = vga_readb(charmap + i); /* * In 512-character mode, the character map is not contiguous if * we want to remain EGA compatible -- which we do */ if (ch512) { charmap += 2 * cmapsz; arg += cmapsz; if (set) for (i = 0; i < cmapsz; i++) vga_writeb(arg[i], charmap + i); else for (i = 0; i < cmapsz; i++) arg[i] = vga_readb(charmap + i); } } spin_lock_irq(&vga_lock); /* First, the sequencer, Synchronous reset */ vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01); /* CPU writes to maps 0 and 1 */ vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03); /* odd-even addressing */ vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03); /* Character Map Select */ if (set) vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select); /* clear synchronous reset */ vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); /* Now, the graphics controller, select map 0 for CPU */ vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00); /* enable even-odd addressing */ vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10); /* map starts at b800:0 or b000:0 */ vga_wgfx(state->vgabase, VGA_GFX_MISC, beg); /* if 512 char mode is already enabled don't re-enable it. */ if ((set) && (ch512 != vga_512_chars)) { int i; /* attribute controller */ for (i = 0; i < MAX_NR_CONSOLES; i++) { struct vc_data *c = vc_cons[i].d; if (c && c->vc_sw == &vga_con) c->vc_hi_font_mask = ch512 ? 0x0800 : 0; } vga_512_chars = ch512; /* 256-char: enable intensity bit 512-char: disable intensity bit */ inb_p(video_port_status); /* clear address flip-flop */ /* color plane enable register */ vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f); /* Wilton (1987) mentions the following; I don't know what it means, but it works, and it appears necessary */ inb_p(video_port_status); vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0); } spin_unlock_irq(&vga_lock); lock_kernel(); return 0;}/* * Adjust the screen to fit a font of a certain height */static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight){ unsigned char ovr, vde, fsr; int rows, maxscan, i; rows = vc->vc_scan_lines / fontheight; /* Number of video rows we end up with */ maxscan = rows * fontheight - 1; /* Scan lines to actually display-1 */ /* Reprogram the CRTC for the new font size Note: the attempt to read the overflow register will fail on an EGA, but using 0xff for the previous value appears to be OK for EGA text modes in the range 257-512 scan lines, so I guess we don't need to worry about it. The same applies for the spill bits in the font size and cursor registers; they are write-only on EGA, but it appears that they are all don't care bits on EGA, so I guess it doesn't matter. */ spin_lock_irq(&vga_lock); outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */ ovr = inb_p(vga_video_port_val); outb_p(0x09, vga_video_port_reg); /* Font size register */ fsr = inb_p(vga_video_port_val); spin_unlock_irq(&vga_lock); vde = maxscan & 0xff; /* Vertical display end reg */ ovr = (ovr & 0xbd) + /* Overflow register */ ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3); fsr = (fsr & 0xe0) + (fontheight - 1); /* Font size register */ spin_lock_irq(&vga_lock); outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */ outb_p(ovr, vga_video_port_val); outb_p(0x09, vga_video_port_reg); /* Font size */ outb_p(fsr, vga_video_port_val); outb_p(0x12, vga_video_port_reg); /* Vertical display limit */ outb_p(vde, vga_video_port_val); spin_unlock_irq(&vga_lock); vga_video_font_height = fontheight; for (i = 0; i < MAX_NR_CONSOLES; i++) { struct vc_data *c = vc_cons[i].d; if (c && c->vc_sw == &vga_con) { if (CON_IS_VISIBLE(c)) { /* void size to cause regs to be rewritten */ cursor_size_lastfrom = 0; cursor_size_lastto = 0; c->vc_sw->con_cursor(c, CM_DRAW); } c->vc_font.height = fontheight; vc_resize(c, 0, rows); /* Adjust console size */ } } return 0;}static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags){ unsigned charcount = font->charcount; int rc; if (vga_video_type < VIDEO_TYPE_EGAM) return -EINVAL; if (font->width != 8 || (charcount != 256 && charcount != 512)) return -EINVAL; rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512); if (rc) return rc; if (!(flags & KD_FONT_FLAG_DONT_RECALC)) rc = vgacon_adjust_height(c, font->height); return rc;}static int vgacon_font_get(struct vc_data *c, struct console_font *font){ if (vga_video_type < VIDEO_TYPE_EGAM) return -EINVAL; font->width = 8; font->height = c->vc_font.height; font->charcount = vga_512_chars ? 512 : 256; if (!font->data) return 0; return vgacon_do_font_op(&state, font->data, 0, 0);}#else#define vgacon_font_set NULL#define vgacon_font_get NULL#endifstatic int vgacon_resize(struct vc_data *c, unsigned int width, unsigned int height){ if (width % 2 || width > ORIG_VIDEO_COLS || height > (ORIG_VIDEO_LINES * vga_default_font_height)/ c->vc_font.height) /* let svgatextmode tinker with video timings */ return 0; if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ vgacon_doresize(c, width, height); return 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;}static int vgacon_set_origin(struct vc_data *c){ if (vga_is_gfx || /* We don't play origin tricks in graphic modes */ (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */ return 0; c->vc_origin = c->vc_visible_origin = vga_vram_base; vga_set_mem_top(c); vga_rolled_over = 0; return 1;}static void vgacon_save_screen(struct vc_data *c){ static int vga_bootup_console = 0; if (!vga_bootup_console) { /* This is a gross hack, but here is the only place we can * set bootup console parameters without messing up generic * console initialization routines. */ vga_bootup_console = 1; c->vc_x = ORIG_X; c->vc_y = ORIG_Y; } /* We can't copy in more then the size of the video buffer, * or we'll be copying in VGA BIOS */ if (!vga_is_gfx) scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);}static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, int lines){ unsigned long oldo; unsigned int delta; if (t || b != c->vc_rows || vga_is_gfx) return 0; if (c->vc_origin != c->vc_visible_origin) vgacon_scrolldelta(c, 0); if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2) return 0; oldo = c->vc_origin; delta = lines * c->vc_size_row; if (dir == SM_UP) { if (c->vc_scr_end + delta >= vga_vram_end) { scr_memcpyw((u16 *) vga_vram_base, (u16 *) (oldo + delta), c->vc_screenbuf_size - delta); c->vc_origin = vga_vram_base; vga_rolled_over = oldo - vga_vram_base; } else c->vc_origin += delta; scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size - delta), c->vc_video_erase_char, delta); } else { if (oldo - delta < vga_vram_base) { scr_memmovew((u16 *) (vga_vram_end - c->vc_screenbuf_size + delta), (u16 *) oldo, c->vc_screenbuf_size - delta); c->vc_origin = vga_vram_end - c->vc_screenbuf_size; vga_rolled_over = 0; } else c->vc_origin -= delta; c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char, delta); } c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; c->vc_visible_origin = c->vc_origin; vga_set_mem_top(c); c->vc_pos = (c->vc_pos - oldo) + c->vc_origin; return 1;}/* * The console `switch' structure for the VGA based console */static int vgacon_dummy(struct vc_data *c){ return 0;}#define DUMMY (void *) vgacon_dummyconst struct consw vga_con = { .owner = THIS_MODULE, .con_startup = vgacon_startup, .con_init = vgacon_init, .con_deinit = vgacon_deinit, .con_clear = DUMMY, .con_putc = DUMMY, .con_putcs = DUMMY, .con_cursor = vgacon_cursor, .con_scroll = vgacon_scroll, .con_bmove = DUMMY, .con_switch = vgacon_switch, .con_blank = vgacon_blank, .con_font_set = vgacon_font_set, .con_font_get = vgacon_font_get, .con_resize = vgacon_resize, .con_set_palette = vgacon_set_palette, .con_scrolldelta = vgacon_scrolldelta, .con_set_origin = vgacon_set_origin, .con_save_screen = vgacon_save_screen, .con_build_attr = vgacon_build_attr, .con_invert_region = vgacon_invert_region,};MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -