162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/video/vgacon.c -- Low level VGA based console driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Created 28 Sep 1997 by Geert Uytterhoeven 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Rewritten by Martin Mares <mj@ucw.cz>, July 1998 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This file is based on the old console.c, vga.c and vesa_blank.c drivers. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 1162306a36Sopenharmony_ci * 1995 Jay Estabrook 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * User definable mapping table and font loading by Eugene G. Crosser, 1462306a36Sopenharmony_ci * <crosser@average.org> 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Improved loadable font/UTF-8 support by H. Peter Anvin 1762306a36Sopenharmony_ci * Feb-Sep 1995 <peter.anvin@linux.org> 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Colour palette handling, by Simon Tatham 2062306a36Sopenharmony_ci * 17-Jun-95 <sgt20@cam.ac.uk> 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * if 512 char mode is already enabled don't re-enable it, 2362306a36Sopenharmony_ci * because it causes screen to flicker, by Mitja Horvat 2462306a36Sopenharmony_ci * 5-May-96 <mitja.horvat@guest.arnes.si> 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Use 2 outw instead of 4 outb_p to reduce erroneous text 2762306a36Sopenharmony_ci * flashing on RHS of screen during heavy console scrolling . 2862306a36Sopenharmony_ci * Oct 1996, Paul Gortmaker. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 3262306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 3362306a36Sopenharmony_ci * more details. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/module.h> 3762306a36Sopenharmony_ci#include <linux/types.h> 3862306a36Sopenharmony_ci#include <linux/fs.h> 3962306a36Sopenharmony_ci#include <linux/kernel.h> 4062306a36Sopenharmony_ci#include <linux/console.h> 4162306a36Sopenharmony_ci#include <linux/string.h> 4262306a36Sopenharmony_ci#include <linux/kd.h> 4362306a36Sopenharmony_ci#include <linux/slab.h> 4462306a36Sopenharmony_ci#include <linux/vt_kern.h> 4562306a36Sopenharmony_ci#include <linux/sched.h> 4662306a36Sopenharmony_ci#include <linux/selection.h> 4762306a36Sopenharmony_ci#include <linux/spinlock.h> 4862306a36Sopenharmony_ci#include <linux/ioport.h> 4962306a36Sopenharmony_ci#include <linux/init.h> 5062306a36Sopenharmony_ci#include <linux/screen_info.h> 5162306a36Sopenharmony_ci#include <video/vga.h> 5262306a36Sopenharmony_ci#include <asm/io.h> 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(vga_lock); 5562306a36Sopenharmony_cistatic int cursor_size_lastfrom; 5662306a36Sopenharmony_cistatic int cursor_size_lastto; 5762306a36Sopenharmony_cistatic u32 vgacon_xres; 5862306a36Sopenharmony_cistatic u32 vgacon_yres; 5962306a36Sopenharmony_cistatic struct vgastate vgastate; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define BLANK 0x0020 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define VGA_FONTWIDTH 8 /* VGA does not support fontwidths != 8 */ 6462306a36Sopenharmony_ci/* 6562306a36Sopenharmony_ci * Interface used by the world 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int vgacon_set_origin(struct vc_data *c); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic struct uni_pagedict *vgacon_uni_pagedir; 7162306a36Sopenharmony_cistatic int vgacon_refcount; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* Description of the hardware situation */ 7462306a36Sopenharmony_cistatic unsigned long vga_vram_base __read_mostly; /* Base of video memory */ 7562306a36Sopenharmony_cistatic unsigned long vga_vram_end __read_mostly; /* End of video memory */ 7662306a36Sopenharmony_cistatic unsigned int vga_vram_size __read_mostly; /* Size of video memory */ 7762306a36Sopenharmony_cistatic u16 vga_video_port_reg __read_mostly; /* Video register select port */ 7862306a36Sopenharmony_cistatic u16 vga_video_port_val __read_mostly; /* Video register value port */ 7962306a36Sopenharmony_cistatic unsigned int vga_video_num_columns; /* Number of text columns */ 8062306a36Sopenharmony_cistatic unsigned int vga_video_num_lines; /* Number of text lines */ 8162306a36Sopenharmony_cistatic bool vga_can_do_color; /* Do we support colors? */ 8262306a36Sopenharmony_cistatic unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */ 8362306a36Sopenharmony_cistatic unsigned char vga_video_type __read_mostly; /* Card type */ 8462306a36Sopenharmony_cistatic int vga_vesa_blanked; 8562306a36Sopenharmony_cistatic bool vga_palette_blanked; 8662306a36Sopenharmony_cistatic bool vga_is_gfx; 8762306a36Sopenharmony_cistatic bool vga_512_chars; 8862306a36Sopenharmony_cistatic int vga_video_font_height; 8962306a36Sopenharmony_cistatic int vga_scan_lines __read_mostly; 9062306a36Sopenharmony_cistatic unsigned int vga_rolled_over; /* last vc_origin offset before wrap */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic bool vga_hardscroll_enabled; 9362306a36Sopenharmony_cistatic bool vga_hardscroll_user_enable = true; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int __init no_scroll(char *str) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci /* 9862306a36Sopenharmony_ci * Disabling scrollback is required for the Braillex ib80-piezo 9962306a36Sopenharmony_ci * Braille reader made by F.H. Papenmeier (Germany). 10062306a36Sopenharmony_ci * Use the "no-scroll" bootflag. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci vga_hardscroll_user_enable = vga_hardscroll_enabled = false; 10362306a36Sopenharmony_ci return 1; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci__setup("no-scroll", no_scroll); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* 10962306a36Sopenharmony_ci * By replacing the four outb_p with two back to back outw, we can reduce 11062306a36Sopenharmony_ci * the window of opportunity to see text mislocated to the RHS of the 11162306a36Sopenharmony_ci * console during heavy scrolling activity. However there is the remote 11262306a36Sopenharmony_ci * possibility that some pre-dinosaur hardware won't like the back to back 11362306a36Sopenharmony_ci * I/O. Since the Xservers get away with it, we should be able to as well. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_cistatic inline void write_vga(unsigned char reg, unsigned int val) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci unsigned int v1, v2; 11862306a36Sopenharmony_ci unsigned long flags; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* 12162306a36Sopenharmony_ci * ddprintk might set the console position from interrupt 12262306a36Sopenharmony_ci * handlers, thus the write has to be IRQ-atomic. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci raw_spin_lock_irqsave(&vga_lock, flags); 12562306a36Sopenharmony_ci v1 = reg + (val & 0xff00); 12662306a36Sopenharmony_ci v2 = reg + 1 + ((val << 8) & 0xff00); 12762306a36Sopenharmony_ci outw(v1, vga_video_port_reg); 12862306a36Sopenharmony_ci outw(v2, vga_video_port_reg); 12962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&vga_lock, flags); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic inline void vga_set_mem_top(struct vc_data *c) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void vgacon_scrolldelta(struct vc_data *c, int lines) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base, 14062306a36Sopenharmony_ci vga_vram_size); 14162306a36Sopenharmony_ci vga_set_mem_top(c); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic void vgacon_restore_screen(struct vc_data *c) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci if (c->vc_origin != c->vc_visible_origin) 14762306a36Sopenharmony_ci vgacon_scrolldelta(c, 0); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic const char *vgacon_startup(void) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci const char *display_desc = NULL; 15362306a36Sopenharmony_ci u16 saved1, saved2; 15462306a36Sopenharmony_ci volatile u16 *p; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB || 15762306a36Sopenharmony_ci screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) { 15862306a36Sopenharmony_ci no_vga: 15962306a36Sopenharmony_ci#ifdef CONFIG_DUMMY_CONSOLE 16062306a36Sopenharmony_ci conswitchp = &dummy_con; 16162306a36Sopenharmony_ci return conswitchp->con_startup(); 16262306a36Sopenharmony_ci#else 16362306a36Sopenharmony_ci return NULL; 16462306a36Sopenharmony_ci#endif 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* boot_params.screen_info reasonably initialized? */ 16862306a36Sopenharmony_ci if ((screen_info.orig_video_lines == 0) || 16962306a36Sopenharmony_ci (screen_info.orig_video_cols == 0)) 17062306a36Sopenharmony_ci goto no_vga; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* VGA16 modes are not handled by VGACON */ 17362306a36Sopenharmony_ci if ((screen_info.orig_video_mode == 0x0D) || /* 320x200/4 */ 17462306a36Sopenharmony_ci (screen_info.orig_video_mode == 0x0E) || /* 640x200/4 */ 17562306a36Sopenharmony_ci (screen_info.orig_video_mode == 0x10) || /* 640x350/4 */ 17662306a36Sopenharmony_ci (screen_info.orig_video_mode == 0x12) || /* 640x480/4 */ 17762306a36Sopenharmony_ci (screen_info.orig_video_mode == 0x6A)) /* 800x600/4 (VESA) */ 17862306a36Sopenharmony_ci goto no_vga; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci vga_video_num_lines = screen_info.orig_video_lines; 18162306a36Sopenharmony_ci vga_video_num_columns = screen_info.orig_video_cols; 18262306a36Sopenharmony_ci vgastate.vgabase = NULL; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (screen_info.orig_video_mode == 7) { 18562306a36Sopenharmony_ci /* Monochrome display */ 18662306a36Sopenharmony_ci vga_vram_base = 0xb0000; 18762306a36Sopenharmony_ci vga_video_port_reg = VGA_CRT_IM; 18862306a36Sopenharmony_ci vga_video_port_val = VGA_CRT_DM; 18962306a36Sopenharmony_ci if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) { 19062306a36Sopenharmony_ci static struct resource ega_console_resource = 19162306a36Sopenharmony_ci { .name = "ega", 19262306a36Sopenharmony_ci .flags = IORESOURCE_IO, 19362306a36Sopenharmony_ci .start = 0x3B0, 19462306a36Sopenharmony_ci .end = 0x3BF }; 19562306a36Sopenharmony_ci vga_video_type = VIDEO_TYPE_EGAM; 19662306a36Sopenharmony_ci vga_vram_size = 0x8000; 19762306a36Sopenharmony_ci display_desc = "EGA+"; 19862306a36Sopenharmony_ci request_resource(&ioport_resource, 19962306a36Sopenharmony_ci &ega_console_resource); 20062306a36Sopenharmony_ci } else { 20162306a36Sopenharmony_ci static struct resource mda1_console_resource = 20262306a36Sopenharmony_ci { .name = "mda", 20362306a36Sopenharmony_ci .flags = IORESOURCE_IO, 20462306a36Sopenharmony_ci .start = 0x3B0, 20562306a36Sopenharmony_ci .end = 0x3BB }; 20662306a36Sopenharmony_ci static struct resource mda2_console_resource = 20762306a36Sopenharmony_ci { .name = "mda", 20862306a36Sopenharmony_ci .flags = IORESOURCE_IO, 20962306a36Sopenharmony_ci .start = 0x3BF, 21062306a36Sopenharmony_ci .end = 0x3BF }; 21162306a36Sopenharmony_ci vga_video_type = VIDEO_TYPE_MDA; 21262306a36Sopenharmony_ci vga_vram_size = 0x2000; 21362306a36Sopenharmony_ci display_desc = "*MDA"; 21462306a36Sopenharmony_ci request_resource(&ioport_resource, 21562306a36Sopenharmony_ci &mda1_console_resource); 21662306a36Sopenharmony_ci request_resource(&ioport_resource, 21762306a36Sopenharmony_ci &mda2_console_resource); 21862306a36Sopenharmony_ci vga_video_font_height = 14; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci } else { 22162306a36Sopenharmony_ci /* If not, it is color. */ 22262306a36Sopenharmony_ci vga_can_do_color = true; 22362306a36Sopenharmony_ci vga_vram_base = 0xb8000; 22462306a36Sopenharmony_ci vga_video_port_reg = VGA_CRT_IC; 22562306a36Sopenharmony_ci vga_video_port_val = VGA_CRT_DC; 22662306a36Sopenharmony_ci if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) { 22762306a36Sopenharmony_ci int i; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci vga_vram_size = 0x8000; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (!screen_info.orig_video_isVGA) { 23262306a36Sopenharmony_ci static struct resource ega_console_resource = 23362306a36Sopenharmony_ci { .name = "ega", 23462306a36Sopenharmony_ci .flags = IORESOURCE_IO, 23562306a36Sopenharmony_ci .start = 0x3C0, 23662306a36Sopenharmony_ci .end = 0x3DF }; 23762306a36Sopenharmony_ci vga_video_type = VIDEO_TYPE_EGAC; 23862306a36Sopenharmony_ci display_desc = "EGA"; 23962306a36Sopenharmony_ci request_resource(&ioport_resource, 24062306a36Sopenharmony_ci &ega_console_resource); 24162306a36Sopenharmony_ci } else { 24262306a36Sopenharmony_ci static struct resource vga_console_resource = 24362306a36Sopenharmony_ci { .name = "vga+", 24462306a36Sopenharmony_ci .flags = IORESOURCE_IO, 24562306a36Sopenharmony_ci .start = 0x3C0, 24662306a36Sopenharmony_ci .end = 0x3DF }; 24762306a36Sopenharmony_ci vga_video_type = VIDEO_TYPE_VGAC; 24862306a36Sopenharmony_ci display_desc = "VGA+"; 24962306a36Sopenharmony_ci request_resource(&ioport_resource, 25062306a36Sopenharmony_ci &vga_console_resource); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* 25362306a36Sopenharmony_ci * Normalise the palette registers, to point 25462306a36Sopenharmony_ci * the 16 screen colours to the first 16 25562306a36Sopenharmony_ci * DAC entries. 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 25962306a36Sopenharmony_ci inb_p(VGA_IS1_RC); 26062306a36Sopenharmony_ci outb_p(i, VGA_ATT_W); 26162306a36Sopenharmony_ci outb_p(i, VGA_ATT_W); 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci outb_p(0x20, VGA_ATT_W); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * Now set the DAC registers back to their 26762306a36Sopenharmony_ci * default values 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 27062306a36Sopenharmony_ci outb_p(color_table[i], VGA_PEL_IW); 27162306a36Sopenharmony_ci outb_p(default_red[i], VGA_PEL_D); 27262306a36Sopenharmony_ci outb_p(default_grn[i], VGA_PEL_D); 27362306a36Sopenharmony_ci outb_p(default_blu[i], VGA_PEL_D); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } else { 27762306a36Sopenharmony_ci static struct resource cga_console_resource = 27862306a36Sopenharmony_ci { .name = "cga", 27962306a36Sopenharmony_ci .flags = IORESOURCE_IO, 28062306a36Sopenharmony_ci .start = 0x3D4, 28162306a36Sopenharmony_ci .end = 0x3D5 }; 28262306a36Sopenharmony_ci vga_video_type = VIDEO_TYPE_CGA; 28362306a36Sopenharmony_ci vga_vram_size = 0x2000; 28462306a36Sopenharmony_ci display_desc = "*CGA"; 28562306a36Sopenharmony_ci request_resource(&ioport_resource, 28662306a36Sopenharmony_ci &cga_console_resource); 28762306a36Sopenharmony_ci vga_video_font_height = 8; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size); 29262306a36Sopenharmony_ci vga_vram_end = vga_vram_base + vga_vram_size; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* 29562306a36Sopenharmony_ci * Find out if there is a graphics card present. 29662306a36Sopenharmony_ci * Are there smarter methods around? 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci p = (volatile u16 *) vga_vram_base; 29962306a36Sopenharmony_ci saved1 = scr_readw(p); 30062306a36Sopenharmony_ci saved2 = scr_readw(p + 1); 30162306a36Sopenharmony_ci scr_writew(0xAA55, p); 30262306a36Sopenharmony_ci scr_writew(0x55AA, p + 1); 30362306a36Sopenharmony_ci if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) { 30462306a36Sopenharmony_ci scr_writew(saved1, p); 30562306a36Sopenharmony_ci scr_writew(saved2, p + 1); 30662306a36Sopenharmony_ci goto no_vga; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci scr_writew(0x55AA, p); 30962306a36Sopenharmony_ci scr_writew(0xAA55, p + 1); 31062306a36Sopenharmony_ci if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) { 31162306a36Sopenharmony_ci scr_writew(saved1, p); 31262306a36Sopenharmony_ci scr_writew(saved2, p + 1); 31362306a36Sopenharmony_ci goto no_vga; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci scr_writew(saved1, p); 31662306a36Sopenharmony_ci scr_writew(saved2, p + 1); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (vga_video_type == VIDEO_TYPE_EGAC 31962306a36Sopenharmony_ci || vga_video_type == VIDEO_TYPE_VGAC 32062306a36Sopenharmony_ci || vga_video_type == VIDEO_TYPE_EGAM) { 32162306a36Sopenharmony_ci vga_hardscroll_enabled = vga_hardscroll_user_enable; 32262306a36Sopenharmony_ci vga_default_font_height = screen_info.orig_video_points; 32362306a36Sopenharmony_ci vga_video_font_height = screen_info.orig_video_points; 32462306a36Sopenharmony_ci /* This may be suboptimal but is a safe bet - go with it */ 32562306a36Sopenharmony_ci vga_scan_lines = 32662306a36Sopenharmony_ci vga_video_font_height * vga_video_num_lines; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH; 33062306a36Sopenharmony_ci vgacon_yres = vga_scan_lines; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return display_desc; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic void vgacon_init(struct vc_data *c, int init) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct uni_pagedict *p; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* 34062306a36Sopenharmony_ci * We cannot be loaded as a module, therefore init will be 1 34162306a36Sopenharmony_ci * if we are the default console, however if we are a fallback 34262306a36Sopenharmony_ci * console, for example if fbcon has failed registration, then 34362306a36Sopenharmony_ci * init will be 0, so we need to make sure our boot parameters 34462306a36Sopenharmony_ci * have been copied to the console structure for vgacon_resize 34562306a36Sopenharmony_ci * ultimately called by vc_resize. Any subsequent calls to 34662306a36Sopenharmony_ci * vgacon_init init will have init set to 0 too. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci c->vc_can_do_color = vga_can_do_color; 34962306a36Sopenharmony_ci c->vc_scan_lines = vga_scan_lines; 35062306a36Sopenharmony_ci c->vc_font.height = c->vc_cell_height = vga_video_font_height; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* set dimensions manually if init != 0 since vc_resize() will fail */ 35362306a36Sopenharmony_ci if (init) { 35462306a36Sopenharmony_ci c->vc_cols = vga_video_num_columns; 35562306a36Sopenharmony_ci c->vc_rows = vga_video_num_lines; 35662306a36Sopenharmony_ci } else 35762306a36Sopenharmony_ci vc_resize(c, vga_video_num_columns, vga_video_num_lines); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci c->vc_complement_mask = 0x7700; 36062306a36Sopenharmony_ci if (vga_512_chars) 36162306a36Sopenharmony_ci c->vc_hi_font_mask = 0x0800; 36262306a36Sopenharmony_ci p = *c->uni_pagedict_loc; 36362306a36Sopenharmony_ci if (c->uni_pagedict_loc != &vgacon_uni_pagedir) { 36462306a36Sopenharmony_ci con_free_unimap(c); 36562306a36Sopenharmony_ci c->uni_pagedict_loc = &vgacon_uni_pagedir; 36662306a36Sopenharmony_ci vgacon_refcount++; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci if (!vgacon_uni_pagedir && p) 36962306a36Sopenharmony_ci con_set_default_unimap(c); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* Only set the default if the user didn't deliberately override it */ 37262306a36Sopenharmony_ci if (global_cursor_default == -1) 37362306a36Sopenharmony_ci global_cursor_default = 37462306a36Sopenharmony_ci !(screen_info.flags & VIDEO_FLAGS_NOCURSOR); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic void vgacon_deinit(struct vc_data *c) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci /* When closing the active console, reset video origin */ 38062306a36Sopenharmony_ci if (con_is_visible(c)) { 38162306a36Sopenharmony_ci c->vc_visible_origin = vga_vram_base; 38262306a36Sopenharmony_ci vga_set_mem_top(c); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (!--vgacon_refcount) 38662306a36Sopenharmony_ci con_free_unimap(c); 38762306a36Sopenharmony_ci c->uni_pagedict_loc = &c->uni_pagedict; 38862306a36Sopenharmony_ci con_set_default_unimap(c); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic u8 vgacon_build_attr(struct vc_data *c, u8 color, 39262306a36Sopenharmony_ci enum vc_intensity intensity, 39362306a36Sopenharmony_ci bool blink, bool underline, bool reverse, 39462306a36Sopenharmony_ci bool italic) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci u8 attr = color; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (vga_can_do_color) { 39962306a36Sopenharmony_ci if (italic) 40062306a36Sopenharmony_ci attr = (attr & 0xF0) | c->vc_itcolor; 40162306a36Sopenharmony_ci else if (underline) 40262306a36Sopenharmony_ci attr = (attr & 0xf0) | c->vc_ulcolor; 40362306a36Sopenharmony_ci else if (intensity == VCI_HALF_BRIGHT) 40462306a36Sopenharmony_ci attr = (attr & 0xf0) | c->vc_halfcolor; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci if (reverse) 40762306a36Sopenharmony_ci attr = 40862306a36Sopenharmony_ci ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) & 40962306a36Sopenharmony_ci 0x77); 41062306a36Sopenharmony_ci if (blink) 41162306a36Sopenharmony_ci attr ^= 0x80; 41262306a36Sopenharmony_ci if (intensity == VCI_BOLD) 41362306a36Sopenharmony_ci attr ^= 0x08; 41462306a36Sopenharmony_ci if (!vga_can_do_color) { 41562306a36Sopenharmony_ci if (italic) 41662306a36Sopenharmony_ci attr = (attr & 0xF8) | 0x02; 41762306a36Sopenharmony_ci else if (underline) 41862306a36Sopenharmony_ci attr = (attr & 0xf8) | 0x01; 41962306a36Sopenharmony_ci else if (intensity == VCI_HALF_BRIGHT) 42062306a36Sopenharmony_ci attr = (attr & 0xf0) | 0x08; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci return attr; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic void vgacon_invert_region(struct vc_data *c, u16 * p, int count) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci const bool col = vga_can_do_color; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci while (count--) { 43062306a36Sopenharmony_ci u16 a = scr_readw(p); 43162306a36Sopenharmony_ci if (col) 43262306a36Sopenharmony_ci a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | 43362306a36Sopenharmony_ci (((a) & 0x0700) << 4); 43462306a36Sopenharmony_ci else 43562306a36Sopenharmony_ci a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700; 43662306a36Sopenharmony_ci scr_writew(a, p++); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void vgacon_set_cursor_size(int from, int to) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci unsigned long flags; 44362306a36Sopenharmony_ci int curs, cure; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto)) 44662306a36Sopenharmony_ci return; 44762306a36Sopenharmony_ci cursor_size_lastfrom = from; 44862306a36Sopenharmony_ci cursor_size_lastto = to; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci raw_spin_lock_irqsave(&vga_lock, flags); 45162306a36Sopenharmony_ci if (vga_video_type >= VIDEO_TYPE_VGAC) { 45262306a36Sopenharmony_ci outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg); 45362306a36Sopenharmony_ci curs = inb_p(vga_video_port_val); 45462306a36Sopenharmony_ci outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg); 45562306a36Sopenharmony_ci cure = inb_p(vga_video_port_val); 45662306a36Sopenharmony_ci } else { 45762306a36Sopenharmony_ci curs = 0; 45862306a36Sopenharmony_ci cure = 0; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci curs = (curs & 0xc0) | from; 46262306a36Sopenharmony_ci cure = (cure & 0xe0) | to; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg); 46562306a36Sopenharmony_ci outb_p(curs, vga_video_port_val); 46662306a36Sopenharmony_ci outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg); 46762306a36Sopenharmony_ci outb_p(cure, vga_video_port_val); 46862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&vga_lock, flags); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic void vgacon_cursor(struct vc_data *c, int mode) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci unsigned int c_height; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (c->vc_mode != KD_TEXT) 47662306a36Sopenharmony_ci return; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci vgacon_restore_screen(c); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci c_height = c->vc_cell_height; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci switch (mode) { 48362306a36Sopenharmony_ci case CM_ERASE: 48462306a36Sopenharmony_ci write_vga(14, (c->vc_pos - vga_vram_base) / 2); 48562306a36Sopenharmony_ci if (vga_video_type >= VIDEO_TYPE_VGAC) 48662306a36Sopenharmony_ci vgacon_set_cursor_size(31, 30); 48762306a36Sopenharmony_ci else 48862306a36Sopenharmony_ci vgacon_set_cursor_size(31, 31); 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci case CM_MOVE: 49262306a36Sopenharmony_ci case CM_DRAW: 49362306a36Sopenharmony_ci write_vga(14, (c->vc_pos - vga_vram_base) / 2); 49462306a36Sopenharmony_ci switch (CUR_SIZE(c->vc_cursor_type)) { 49562306a36Sopenharmony_ci case CUR_UNDERLINE: 49662306a36Sopenharmony_ci vgacon_set_cursor_size(c_height - 49762306a36Sopenharmony_ci (c_height < 10 ? 2 : 3), 49862306a36Sopenharmony_ci c_height - 49962306a36Sopenharmony_ci (c_height < 10 ? 1 : 2)); 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci case CUR_TWO_THIRDS: 50262306a36Sopenharmony_ci vgacon_set_cursor_size(c_height / 3, c_height - 50362306a36Sopenharmony_ci (c_height < 10 ? 1 : 2)); 50462306a36Sopenharmony_ci break; 50562306a36Sopenharmony_ci case CUR_LOWER_THIRD: 50662306a36Sopenharmony_ci vgacon_set_cursor_size(c_height * 2 / 3, c_height - 50762306a36Sopenharmony_ci (c_height < 10 ? 1 : 2)); 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci case CUR_LOWER_HALF: 51062306a36Sopenharmony_ci vgacon_set_cursor_size(c_height / 2, c_height - 51162306a36Sopenharmony_ci (c_height < 10 ? 1 : 2)); 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci case CUR_NONE: 51462306a36Sopenharmony_ci if (vga_video_type >= VIDEO_TYPE_VGAC) 51562306a36Sopenharmony_ci vgacon_set_cursor_size(31, 30); 51662306a36Sopenharmony_ci else 51762306a36Sopenharmony_ci vgacon_set_cursor_size(31, 31); 51862306a36Sopenharmony_ci break; 51962306a36Sopenharmony_ci default: 52062306a36Sopenharmony_ci vgacon_set_cursor_size(1, c_height); 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci break; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void vgacon_doresize(struct vc_data *c, 52862306a36Sopenharmony_ci unsigned int width, unsigned int height) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci unsigned long flags; 53162306a36Sopenharmony_ci unsigned int scanlines = height * c->vc_cell_height; 53262306a36Sopenharmony_ci u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci raw_spin_lock_irqsave(&vga_lock, flags); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci vgacon_xres = width * VGA_FONTWIDTH; 53762306a36Sopenharmony_ci vgacon_yres = height * c->vc_cell_height; 53862306a36Sopenharmony_ci if (vga_video_type >= VIDEO_TYPE_VGAC) { 53962306a36Sopenharmony_ci outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg); 54062306a36Sopenharmony_ci max_scan = inb_p(vga_video_port_val); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (max_scan & 0x80) 54362306a36Sopenharmony_ci scanlines <<= 1; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci outb_p(VGA_CRTC_MODE, vga_video_port_reg); 54662306a36Sopenharmony_ci mode = inb_p(vga_video_port_val); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (mode & 0x04) 54962306a36Sopenharmony_ci scanlines >>= 1; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci scanlines -= 1; 55262306a36Sopenharmony_ci scanlines_lo = scanlines & 0xff; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg); 55562306a36Sopenharmony_ci r7 = inb_p(vga_video_port_val) & ~0x42; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (scanlines & 0x100) 55862306a36Sopenharmony_ci r7 |= 0x02; 55962306a36Sopenharmony_ci if (scanlines & 0x200) 56062306a36Sopenharmony_ci r7 |= 0x40; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* deprotect registers */ 56362306a36Sopenharmony_ci outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); 56462306a36Sopenharmony_ci vsync_end = inb_p(vga_video_port_val); 56562306a36Sopenharmony_ci outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); 56662306a36Sopenharmony_ci outb_p(vsync_end & ~0x80, vga_video_port_val); 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci outb_p(VGA_CRTC_H_DISP, vga_video_port_reg); 57062306a36Sopenharmony_ci outb_p(width - 1, vga_video_port_val); 57162306a36Sopenharmony_ci outb_p(VGA_CRTC_OFFSET, vga_video_port_reg); 57262306a36Sopenharmony_ci outb_p(width >> 1, vga_video_port_val); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (vga_video_type >= VIDEO_TYPE_VGAC) { 57562306a36Sopenharmony_ci outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg); 57662306a36Sopenharmony_ci outb_p(scanlines_lo, vga_video_port_val); 57762306a36Sopenharmony_ci outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg); 57862306a36Sopenharmony_ci outb_p(r7,vga_video_port_val); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* reprotect registers */ 58162306a36Sopenharmony_ci outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); 58262306a36Sopenharmony_ci outb_p(vsync_end, vga_video_port_val); 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&vga_lock, flags); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic int vgacon_switch(struct vc_data *c) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci int x = c->vc_cols * VGA_FONTWIDTH; 59162306a36Sopenharmony_ci int y = c->vc_rows * c->vc_cell_height; 59262306a36Sopenharmony_ci int rows = screen_info.orig_video_lines * vga_default_font_height/ 59362306a36Sopenharmony_ci c->vc_cell_height; 59462306a36Sopenharmony_ci /* 59562306a36Sopenharmony_ci * We need to save screen size here as it's the only way 59662306a36Sopenharmony_ci * we can spot the screen has been resized and we need to 59762306a36Sopenharmony_ci * set size of freshly allocated screens ourselves. 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_ci vga_video_num_columns = c->vc_cols; 60062306a36Sopenharmony_ci vga_video_num_lines = c->vc_rows; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* We can only copy out the size of the video buffer here, 60362306a36Sopenharmony_ci * otherwise we get into VGA BIOS */ 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (!vga_is_gfx) { 60662306a36Sopenharmony_ci scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, 60762306a36Sopenharmony_ci c->vc_screenbuf_size > vga_vram_size ? 60862306a36Sopenharmony_ci vga_vram_size : c->vc_screenbuf_size); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if ((vgacon_xres != x || vgacon_yres != y) && 61162306a36Sopenharmony_ci (!(vga_video_num_columns % 2) && 61262306a36Sopenharmony_ci vga_video_num_columns <= screen_info.orig_video_cols && 61362306a36Sopenharmony_ci vga_video_num_lines <= rows)) 61462306a36Sopenharmony_ci vgacon_doresize(c, c->vc_cols, c->vc_rows); 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci return 0; /* Redrawing not needed */ 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic void vga_set_palette(struct vc_data *vc, const unsigned char *table) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci int i, j; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff); 62562306a36Sopenharmony_ci for (i = j = 0; i < 16; i++) { 62662306a36Sopenharmony_ci vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]); 62762306a36Sopenharmony_ci vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); 62862306a36Sopenharmony_ci vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); 62962306a36Sopenharmony_ci vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic void vgacon_set_palette(struct vc_data *vc, const unsigned char *table) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked 63662306a36Sopenharmony_ci || !con_is_visible(vc)) 63762306a36Sopenharmony_ci return; 63862306a36Sopenharmony_ci vga_set_palette(vc, table); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/* structure holding original VGA register settings */ 64262306a36Sopenharmony_cistatic struct { 64362306a36Sopenharmony_ci unsigned char SeqCtrlIndex; /* Sequencer Index reg. */ 64462306a36Sopenharmony_ci unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */ 64562306a36Sopenharmony_ci unsigned char CrtMiscIO; /* Miscellaneous register */ 64662306a36Sopenharmony_ci unsigned char HorizontalTotal; /* CRT-Controller:00h */ 64762306a36Sopenharmony_ci unsigned char HorizDisplayEnd; /* CRT-Controller:01h */ 64862306a36Sopenharmony_ci unsigned char StartHorizRetrace; /* CRT-Controller:04h */ 64962306a36Sopenharmony_ci unsigned char EndHorizRetrace; /* CRT-Controller:05h */ 65062306a36Sopenharmony_ci unsigned char Overflow; /* CRT-Controller:07h */ 65162306a36Sopenharmony_ci unsigned char StartVertRetrace; /* CRT-Controller:10h */ 65262306a36Sopenharmony_ci unsigned char EndVertRetrace; /* CRT-Controller:11h */ 65362306a36Sopenharmony_ci unsigned char ModeControl; /* CRT-Controller:17h */ 65462306a36Sopenharmony_ci unsigned char ClockingMode; /* Seq-Controller:01h */ 65562306a36Sopenharmony_ci} vga_state; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic void vga_vesa_blank(struct vgastate *state, int mode) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci /* save original values of VGA controller registers */ 66062306a36Sopenharmony_ci if (!vga_vesa_blanked) { 66162306a36Sopenharmony_ci raw_spin_lock_irq(&vga_lock); 66262306a36Sopenharmony_ci vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I); 66362306a36Sopenharmony_ci vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg); 66462306a36Sopenharmony_ci vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R); 66562306a36Sopenharmony_ci raw_spin_unlock_irq(&vga_lock); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */ 66862306a36Sopenharmony_ci vga_state.HorizontalTotal = inb_p(vga_video_port_val); 66962306a36Sopenharmony_ci outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */ 67062306a36Sopenharmony_ci vga_state.HorizDisplayEnd = inb_p(vga_video_port_val); 67162306a36Sopenharmony_ci outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */ 67262306a36Sopenharmony_ci vga_state.StartHorizRetrace = inb_p(vga_video_port_val); 67362306a36Sopenharmony_ci outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */ 67462306a36Sopenharmony_ci vga_state.EndHorizRetrace = inb_p(vga_video_port_val); 67562306a36Sopenharmony_ci outb_p(0x07, vga_video_port_reg); /* Overflow */ 67662306a36Sopenharmony_ci vga_state.Overflow = inb_p(vga_video_port_val); 67762306a36Sopenharmony_ci outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */ 67862306a36Sopenharmony_ci vga_state.StartVertRetrace = inb_p(vga_video_port_val); 67962306a36Sopenharmony_ci outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */ 68062306a36Sopenharmony_ci vga_state.EndVertRetrace = inb_p(vga_video_port_val); 68162306a36Sopenharmony_ci outb_p(0x17, vga_video_port_reg); /* ModeControl */ 68262306a36Sopenharmony_ci vga_state.ModeControl = inb_p(vga_video_port_val); 68362306a36Sopenharmony_ci vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE); 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* assure that video is enabled */ 68762306a36Sopenharmony_ci /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */ 68862306a36Sopenharmony_ci raw_spin_lock_irq(&vga_lock); 68962306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci /* test for vertical retrace in process.... */ 69262306a36Sopenharmony_ci if ((vga_state.CrtMiscIO & 0x80) == 0x80) 69362306a36Sopenharmony_ci vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* 69662306a36Sopenharmony_ci * Set <End of vertical retrace> to minimum (0) and 69762306a36Sopenharmony_ci * <Start of vertical Retrace> to maximum (incl. overflow) 69862306a36Sopenharmony_ci * Result: turn off vertical sync (VSync) pulse. 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_ci if (mode & VESA_VSYNC_SUSPEND) { 70162306a36Sopenharmony_ci outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */ 70262306a36Sopenharmony_ci outb_p(0xff, vga_video_port_val); /* maximum value */ 70362306a36Sopenharmony_ci outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */ 70462306a36Sopenharmony_ci outb_p(0x40, vga_video_port_val); /* minimum (bits 0..3) */ 70562306a36Sopenharmony_ci outb_p(0x07, vga_video_port_reg); /* Overflow */ 70662306a36Sopenharmony_ci outb_p(vga_state.Overflow | 0x84, vga_video_port_val); /* bits 9,10 of vert. retrace */ 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (mode & VESA_HSYNC_SUSPEND) { 71062306a36Sopenharmony_ci /* 71162306a36Sopenharmony_ci * Set <End of horizontal retrace> to minimum (0) and 71262306a36Sopenharmony_ci * <Start of horizontal Retrace> to maximum 71362306a36Sopenharmony_ci * Result: turn off horizontal sync (HSync) pulse. 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_ci outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */ 71662306a36Sopenharmony_ci outb_p(0xff, vga_video_port_val); /* maximum */ 71762306a36Sopenharmony_ci outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */ 71862306a36Sopenharmony_ci outb_p(0x00, vga_video_port_val); /* minimum (0) */ 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* restore both index registers */ 72262306a36Sopenharmony_ci vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex); 72362306a36Sopenharmony_ci outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg); 72462306a36Sopenharmony_ci raw_spin_unlock_irq(&vga_lock); 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic void vga_vesa_unblank(struct vgastate *state) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci /* restore original values of VGA controller registers */ 73062306a36Sopenharmony_ci raw_spin_lock_irq(&vga_lock); 73162306a36Sopenharmony_ci vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */ 73462306a36Sopenharmony_ci outb_p(vga_state.HorizontalTotal, vga_video_port_val); 73562306a36Sopenharmony_ci outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */ 73662306a36Sopenharmony_ci outb_p(vga_state.HorizDisplayEnd, vga_video_port_val); 73762306a36Sopenharmony_ci outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */ 73862306a36Sopenharmony_ci outb_p(vga_state.StartHorizRetrace, vga_video_port_val); 73962306a36Sopenharmony_ci outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */ 74062306a36Sopenharmony_ci outb_p(vga_state.EndHorizRetrace, vga_video_port_val); 74162306a36Sopenharmony_ci outb_p(0x07, vga_video_port_reg); /* Overflow */ 74262306a36Sopenharmony_ci outb_p(vga_state.Overflow, vga_video_port_val); 74362306a36Sopenharmony_ci outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */ 74462306a36Sopenharmony_ci outb_p(vga_state.StartVertRetrace, vga_video_port_val); 74562306a36Sopenharmony_ci outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */ 74662306a36Sopenharmony_ci outb_p(vga_state.EndVertRetrace, vga_video_port_val); 74762306a36Sopenharmony_ci outb_p(0x17, vga_video_port_reg); /* ModeControl */ 74862306a36Sopenharmony_ci outb_p(vga_state.ModeControl, vga_video_port_val); 74962306a36Sopenharmony_ci /* ClockingMode */ 75062306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* restore index/control registers */ 75362306a36Sopenharmony_ci vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex); 75462306a36Sopenharmony_ci outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg); 75562306a36Sopenharmony_ci raw_spin_unlock_irq(&vga_lock); 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cistatic void vga_pal_blank(struct vgastate *state) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci int i; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci vga_w(state->vgabase, VGA_PEL_MSK, 0xff); 76362306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 76462306a36Sopenharmony_ci vga_w(state->vgabase, VGA_PEL_IW, i); 76562306a36Sopenharmony_ci vga_w(state->vgabase, VGA_PEL_D, 0); 76662306a36Sopenharmony_ci vga_w(state->vgabase, VGA_PEL_D, 0); 76762306a36Sopenharmony_ci vga_w(state->vgabase, VGA_PEL_D, 0); 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic int vgacon_blank(struct vc_data *c, int blank, int mode_switch) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci switch (blank) { 77462306a36Sopenharmony_ci case 0: /* Unblank */ 77562306a36Sopenharmony_ci if (vga_vesa_blanked) { 77662306a36Sopenharmony_ci vga_vesa_unblank(&vgastate); 77762306a36Sopenharmony_ci vga_vesa_blanked = 0; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci if (vga_palette_blanked) { 78062306a36Sopenharmony_ci vga_set_palette(c, color_table); 78162306a36Sopenharmony_ci vga_palette_blanked = false; 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci vga_is_gfx = false; 78562306a36Sopenharmony_ci /* Tell console.c that it has to restore the screen itself */ 78662306a36Sopenharmony_ci return 1; 78762306a36Sopenharmony_ci case 1: /* Normal blanking */ 78862306a36Sopenharmony_ci case -1: /* Obsolete */ 78962306a36Sopenharmony_ci if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) { 79062306a36Sopenharmony_ci vga_pal_blank(&vgastate); 79162306a36Sopenharmony_ci vga_palette_blanked = true; 79262306a36Sopenharmony_ci return 0; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci vgacon_set_origin(c); 79562306a36Sopenharmony_ci scr_memsetw((void *) vga_vram_base, BLANK, 79662306a36Sopenharmony_ci c->vc_screenbuf_size); 79762306a36Sopenharmony_ci if (mode_switch) 79862306a36Sopenharmony_ci vga_is_gfx = true; 79962306a36Sopenharmony_ci return 1; 80062306a36Sopenharmony_ci default: /* VESA blanking */ 80162306a36Sopenharmony_ci if (vga_video_type == VIDEO_TYPE_VGAC) { 80262306a36Sopenharmony_ci vga_vesa_blank(&vgastate, blank - 1); 80362306a36Sopenharmony_ci vga_vesa_blanked = blank; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci return 0; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci/* 81062306a36Sopenharmony_ci * PIO_FONT support. 81162306a36Sopenharmony_ci * 81262306a36Sopenharmony_ci * The font loading code goes back to the codepage package by 81362306a36Sopenharmony_ci * Joel Hoffman (joel@wam.umd.edu). (He reports that the original 81462306a36Sopenharmony_ci * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2 81562306a36Sopenharmony_ci * Video Systems_ by Richard Wilton. 1987. Microsoft Press".) 81662306a36Sopenharmony_ci * 81762306a36Sopenharmony_ci * Change for certain monochrome monitors by Yury Shevchuck 81862306a36Sopenharmony_ci * (sizif@botik.yaroslavl.su). 81962306a36Sopenharmony_ci */ 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci#define colourmap 0xa0000 82262306a36Sopenharmony_ci/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we 82362306a36Sopenharmony_ci should use 0xA0000 for the bwmap as well.. */ 82462306a36Sopenharmony_ci#define blackwmap 0xa0000 82562306a36Sopenharmony_ci#define cmapsz 8192 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic int vgacon_do_font_op(struct vgastate *state, char *arg, int set, 82862306a36Sopenharmony_ci bool ch512) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci unsigned short video_port_status = vga_video_port_reg + 6; 83162306a36Sopenharmony_ci int font_select = 0x00, beg, i; 83262306a36Sopenharmony_ci char *charmap; 83362306a36Sopenharmony_ci bool clear_attribs = false; 83462306a36Sopenharmony_ci if (vga_video_type != VIDEO_TYPE_EGAM) { 83562306a36Sopenharmony_ci charmap = (char *) VGA_MAP_MEM(colourmap, 0); 83662306a36Sopenharmony_ci beg = 0x0e; 83762306a36Sopenharmony_ci } else { 83862306a36Sopenharmony_ci charmap = (char *) VGA_MAP_MEM(blackwmap, 0); 83962306a36Sopenharmony_ci beg = 0x0a; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci /* 84362306a36Sopenharmony_ci * All fonts are loaded in slot 0 (0:1 for 512 ch) 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (!arg) 84762306a36Sopenharmony_ci return -EINVAL; /* Return to default font not supported */ 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci font_select = ch512 ? 0x04 : 0x00; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci raw_spin_lock_irq(&vga_lock); 85262306a36Sopenharmony_ci /* First, the Sequencer */ 85362306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); 85462306a36Sopenharmony_ci /* CPU writes only to map 2 */ 85562306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04); 85662306a36Sopenharmony_ci /* Sequential addressing */ 85762306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07); 85862306a36Sopenharmony_ci /* Clear synchronous reset */ 85962306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* Now, the graphics controller, select map 2 */ 86262306a36Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02); 86362306a36Sopenharmony_ci /* disable odd-even addressing */ 86462306a36Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00); 86562306a36Sopenharmony_ci /* map start at A000:0000 */ 86662306a36Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00); 86762306a36Sopenharmony_ci raw_spin_unlock_irq(&vga_lock); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (arg) { 87062306a36Sopenharmony_ci if (set) 87162306a36Sopenharmony_ci for (i = 0; i < cmapsz; i++) { 87262306a36Sopenharmony_ci vga_writeb(arg[i], charmap + i); 87362306a36Sopenharmony_ci cond_resched(); 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci else 87662306a36Sopenharmony_ci for (i = 0; i < cmapsz; i++) { 87762306a36Sopenharmony_ci arg[i] = vga_readb(charmap + i); 87862306a36Sopenharmony_ci cond_resched(); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci /* 88262306a36Sopenharmony_ci * In 512-character mode, the character map is not contiguous if 88362306a36Sopenharmony_ci * we want to remain EGA compatible -- which we do 88462306a36Sopenharmony_ci */ 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (ch512) { 88762306a36Sopenharmony_ci charmap += 2 * cmapsz; 88862306a36Sopenharmony_ci arg += cmapsz; 88962306a36Sopenharmony_ci if (set) 89062306a36Sopenharmony_ci for (i = 0; i < cmapsz; i++) { 89162306a36Sopenharmony_ci vga_writeb(arg[i], charmap + i); 89262306a36Sopenharmony_ci cond_resched(); 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci else 89562306a36Sopenharmony_ci for (i = 0; i < cmapsz; i++) { 89662306a36Sopenharmony_ci arg[i] = vga_readb(charmap + i); 89762306a36Sopenharmony_ci cond_resched(); 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci raw_spin_lock_irq(&vga_lock); 90362306a36Sopenharmony_ci /* First, the sequencer, Synchronous reset */ 90462306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01); 90562306a36Sopenharmony_ci /* CPU writes to maps 0 and 1 */ 90662306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03); 90762306a36Sopenharmony_ci /* odd-even addressing */ 90862306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03); 90962306a36Sopenharmony_ci /* Character Map Select */ 91062306a36Sopenharmony_ci if (set) 91162306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select); 91262306a36Sopenharmony_ci /* clear synchronous reset */ 91362306a36Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci /* Now, the graphics controller, select map 0 for CPU */ 91662306a36Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00); 91762306a36Sopenharmony_ci /* enable even-odd addressing */ 91862306a36Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10); 91962306a36Sopenharmony_ci /* map starts at b800:0 or b000:0 */ 92062306a36Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, beg); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci /* if 512 char mode is already enabled don't re-enable it. */ 92362306a36Sopenharmony_ci if ((set) && (ch512 != vga_512_chars)) { 92462306a36Sopenharmony_ci vga_512_chars = ch512; 92562306a36Sopenharmony_ci /* 256-char: enable intensity bit 92662306a36Sopenharmony_ci 512-char: disable intensity bit */ 92762306a36Sopenharmony_ci inb_p(video_port_status); /* clear address flip-flop */ 92862306a36Sopenharmony_ci /* color plane enable register */ 92962306a36Sopenharmony_ci vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f); 93062306a36Sopenharmony_ci /* Wilton (1987) mentions the following; I don't know what 93162306a36Sopenharmony_ci it means, but it works, and it appears necessary */ 93262306a36Sopenharmony_ci inb_p(video_port_status); 93362306a36Sopenharmony_ci vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0); 93462306a36Sopenharmony_ci clear_attribs = true; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci raw_spin_unlock_irq(&vga_lock); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci if (clear_attribs) { 93962306a36Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) { 94062306a36Sopenharmony_ci struct vc_data *c = vc_cons[i].d; 94162306a36Sopenharmony_ci if (c && c->vc_sw == &vga_con) { 94262306a36Sopenharmony_ci /* force hi font mask to 0, so we always clear 94362306a36Sopenharmony_ci the bit on either transition */ 94462306a36Sopenharmony_ci c->vc_hi_font_mask = 0x00; 94562306a36Sopenharmony_ci clear_buffer_attributes(c); 94662306a36Sopenharmony_ci c->vc_hi_font_mask = ch512 ? 0x0800 : 0; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci return 0; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci/* 95462306a36Sopenharmony_ci * Adjust the screen to fit a font of a certain height 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_cistatic int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci unsigned char ovr, vde, fsr; 95962306a36Sopenharmony_ci int rows, maxscan, i; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci rows = vc->vc_scan_lines / fontheight; /* Number of video rows we end up with */ 96262306a36Sopenharmony_ci maxscan = rows * fontheight - 1; /* Scan lines to actually display-1 */ 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* Reprogram the CRTC for the new font size 96562306a36Sopenharmony_ci Note: the attempt to read the overflow register will fail 96662306a36Sopenharmony_ci on an EGA, but using 0xff for the previous value appears to 96762306a36Sopenharmony_ci be OK for EGA text modes in the range 257-512 scan lines, so I 96862306a36Sopenharmony_ci guess we don't need to worry about it. 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci The same applies for the spill bits in the font size and cursor 97162306a36Sopenharmony_ci registers; they are write-only on EGA, but it appears that they 97262306a36Sopenharmony_ci are all don't care bits on EGA, so I guess it doesn't matter. */ 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci raw_spin_lock_irq(&vga_lock); 97562306a36Sopenharmony_ci outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */ 97662306a36Sopenharmony_ci ovr = inb_p(vga_video_port_val); 97762306a36Sopenharmony_ci outb_p(0x09, vga_video_port_reg); /* Font size register */ 97862306a36Sopenharmony_ci fsr = inb_p(vga_video_port_val); 97962306a36Sopenharmony_ci raw_spin_unlock_irq(&vga_lock); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci vde = maxscan & 0xff; /* Vertical display end reg */ 98262306a36Sopenharmony_ci ovr = (ovr & 0xbd) + /* Overflow register */ 98362306a36Sopenharmony_ci ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3); 98462306a36Sopenharmony_ci fsr = (fsr & 0xe0) + (fontheight - 1); /* Font size register */ 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci raw_spin_lock_irq(&vga_lock); 98762306a36Sopenharmony_ci outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */ 98862306a36Sopenharmony_ci outb_p(ovr, vga_video_port_val); 98962306a36Sopenharmony_ci outb_p(0x09, vga_video_port_reg); /* Font size */ 99062306a36Sopenharmony_ci outb_p(fsr, vga_video_port_val); 99162306a36Sopenharmony_ci outb_p(0x12, vga_video_port_reg); /* Vertical display limit */ 99262306a36Sopenharmony_ci outb_p(vde, vga_video_port_val); 99362306a36Sopenharmony_ci raw_spin_unlock_irq(&vga_lock); 99462306a36Sopenharmony_ci vga_video_font_height = fontheight; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) { 99762306a36Sopenharmony_ci struct vc_data *c = vc_cons[i].d; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci if (c && c->vc_sw == &vga_con) { 100062306a36Sopenharmony_ci if (con_is_visible(c)) { 100162306a36Sopenharmony_ci /* void size to cause regs to be rewritten */ 100262306a36Sopenharmony_ci cursor_size_lastfrom = 0; 100362306a36Sopenharmony_ci cursor_size_lastto = 0; 100462306a36Sopenharmony_ci c->vc_sw->con_cursor(c, CM_DRAW); 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci c->vc_font.height = c->vc_cell_height = fontheight; 100762306a36Sopenharmony_ci vc_resize(c, 0, rows); /* Adjust console size */ 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci return 0; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic int vgacon_font_set(struct vc_data *c, struct console_font *font, 101462306a36Sopenharmony_ci unsigned int vpitch, unsigned int flags) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci unsigned charcount = font->charcount; 101762306a36Sopenharmony_ci int rc; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if (vga_video_type < VIDEO_TYPE_EGAM) 102062306a36Sopenharmony_ci return -EINVAL; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (font->width != VGA_FONTWIDTH || font->height > 32 || vpitch != 32 || 102362306a36Sopenharmony_ci (charcount != 256 && charcount != 512)) 102462306a36Sopenharmony_ci return -EINVAL; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512); 102762306a36Sopenharmony_ci if (rc) 102862306a36Sopenharmony_ci return rc; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (!(flags & KD_FONT_FLAG_DONT_RECALC)) 103162306a36Sopenharmony_ci rc = vgacon_adjust_height(c, font->height); 103262306a36Sopenharmony_ci return rc; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigned int vpitch) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci if (vga_video_type < VIDEO_TYPE_EGAM || vpitch != 32) 103862306a36Sopenharmony_ci return -EINVAL; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci font->width = VGA_FONTWIDTH; 104162306a36Sopenharmony_ci font->height = c->vc_font.height; 104262306a36Sopenharmony_ci font->charcount = vga_512_chars ? 512 : 256; 104362306a36Sopenharmony_ci if (!font->data) 104462306a36Sopenharmony_ci return 0; 104562306a36Sopenharmony_ci return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars); 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic int vgacon_resize(struct vc_data *c, unsigned int width, 104962306a36Sopenharmony_ci unsigned int height, unsigned int user) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci if ((width << 1) * height > vga_vram_size) 105262306a36Sopenharmony_ci return -EINVAL; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (user) { 105562306a36Sopenharmony_ci /* 105662306a36Sopenharmony_ci * Ho ho! Someone (svgatextmode, eh?) may have reprogrammed 105762306a36Sopenharmony_ci * the video mode! Set the new defaults then and go away. 105862306a36Sopenharmony_ci */ 105962306a36Sopenharmony_ci screen_info.orig_video_cols = width; 106062306a36Sopenharmony_ci screen_info.orig_video_lines = height; 106162306a36Sopenharmony_ci vga_default_font_height = c->vc_cell_height; 106262306a36Sopenharmony_ci return 0; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci if (width % 2 || width > screen_info.orig_video_cols || 106562306a36Sopenharmony_ci height > (screen_info.orig_video_lines * vga_default_font_height)/ 106662306a36Sopenharmony_ci c->vc_cell_height) 106762306a36Sopenharmony_ci return -EINVAL; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (con_is_visible(c) && !vga_is_gfx) /* who knows */ 107062306a36Sopenharmony_ci vgacon_doresize(c, width, height); 107162306a36Sopenharmony_ci return 0; 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic int vgacon_set_origin(struct vc_data *c) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci if (vga_is_gfx || /* We don't play origin tricks in graphic modes */ 107762306a36Sopenharmony_ci (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */ 107862306a36Sopenharmony_ci return 0; 107962306a36Sopenharmony_ci c->vc_origin = c->vc_visible_origin = vga_vram_base; 108062306a36Sopenharmony_ci vga_set_mem_top(c); 108162306a36Sopenharmony_ci vga_rolled_over = 0; 108262306a36Sopenharmony_ci return 1; 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic void vgacon_save_screen(struct vc_data *c) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci static int vga_bootup_console = 0; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (!vga_bootup_console) { 109062306a36Sopenharmony_ci /* This is a gross hack, but here is the only place we can 109162306a36Sopenharmony_ci * set bootup console parameters without messing up generic 109262306a36Sopenharmony_ci * console initialization routines. 109362306a36Sopenharmony_ci */ 109462306a36Sopenharmony_ci vga_bootup_console = 1; 109562306a36Sopenharmony_ci c->state.x = screen_info.orig_x; 109662306a36Sopenharmony_ci c->state.y = screen_info.orig_y; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci /* We can't copy in more than the size of the video buffer, 110062306a36Sopenharmony_ci * or we'll be copying in VGA BIOS */ 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (!vga_is_gfx) 110362306a36Sopenharmony_ci scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin, 110462306a36Sopenharmony_ci c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b, 110862306a36Sopenharmony_ci enum con_scroll dir, unsigned int lines) 110962306a36Sopenharmony_ci{ 111062306a36Sopenharmony_ci unsigned long oldo; 111162306a36Sopenharmony_ci unsigned int delta; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT) 111462306a36Sopenharmony_ci return false; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2) 111762306a36Sopenharmony_ci return false; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci vgacon_restore_screen(c); 112062306a36Sopenharmony_ci oldo = c->vc_origin; 112162306a36Sopenharmony_ci delta = lines * c->vc_size_row; 112262306a36Sopenharmony_ci if (dir == SM_UP) { 112362306a36Sopenharmony_ci if (c->vc_scr_end + delta >= vga_vram_end) { 112462306a36Sopenharmony_ci scr_memcpyw((u16 *) vga_vram_base, 112562306a36Sopenharmony_ci (u16 *) (oldo + delta), 112662306a36Sopenharmony_ci c->vc_screenbuf_size - delta); 112762306a36Sopenharmony_ci c->vc_origin = vga_vram_base; 112862306a36Sopenharmony_ci vga_rolled_over = oldo - vga_vram_base; 112962306a36Sopenharmony_ci } else 113062306a36Sopenharmony_ci c->vc_origin += delta; 113162306a36Sopenharmony_ci scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size - 113262306a36Sopenharmony_ci delta), c->vc_video_erase_char, 113362306a36Sopenharmony_ci delta); 113462306a36Sopenharmony_ci } else { 113562306a36Sopenharmony_ci if (oldo - delta < vga_vram_base) { 113662306a36Sopenharmony_ci scr_memmovew((u16 *) (vga_vram_end - 113762306a36Sopenharmony_ci c->vc_screenbuf_size + 113862306a36Sopenharmony_ci delta), (u16 *) oldo, 113962306a36Sopenharmony_ci c->vc_screenbuf_size - delta); 114062306a36Sopenharmony_ci c->vc_origin = vga_vram_end - c->vc_screenbuf_size; 114162306a36Sopenharmony_ci vga_rolled_over = 0; 114262306a36Sopenharmony_ci } else 114362306a36Sopenharmony_ci c->vc_origin -= delta; 114462306a36Sopenharmony_ci c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; 114562306a36Sopenharmony_ci scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char, 114662306a36Sopenharmony_ci delta); 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; 114962306a36Sopenharmony_ci c->vc_visible_origin = c->vc_origin; 115062306a36Sopenharmony_ci vga_set_mem_top(c); 115162306a36Sopenharmony_ci c->vc_pos = (c->vc_pos - oldo) + c->vc_origin; 115262306a36Sopenharmony_ci return true; 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci/* 115662306a36Sopenharmony_ci * The console `switch' structure for the VGA based console 115762306a36Sopenharmony_ci */ 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic void vgacon_clear(struct vc_data *vc, int sy, int sx, int height, 116062306a36Sopenharmony_ci int width) { } 116162306a36Sopenharmony_cistatic void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } 116262306a36Sopenharmony_cistatic void vgacon_putcs(struct vc_data *vc, const unsigned short *s, 116362306a36Sopenharmony_ci int count, int ypos, int xpos) { } 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ciconst struct consw vga_con = { 116662306a36Sopenharmony_ci .owner = THIS_MODULE, 116762306a36Sopenharmony_ci .con_startup = vgacon_startup, 116862306a36Sopenharmony_ci .con_init = vgacon_init, 116962306a36Sopenharmony_ci .con_deinit = vgacon_deinit, 117062306a36Sopenharmony_ci .con_clear = vgacon_clear, 117162306a36Sopenharmony_ci .con_putc = vgacon_putc, 117262306a36Sopenharmony_ci .con_putcs = vgacon_putcs, 117362306a36Sopenharmony_ci .con_cursor = vgacon_cursor, 117462306a36Sopenharmony_ci .con_scroll = vgacon_scroll, 117562306a36Sopenharmony_ci .con_switch = vgacon_switch, 117662306a36Sopenharmony_ci .con_blank = vgacon_blank, 117762306a36Sopenharmony_ci .con_font_set = vgacon_font_set, 117862306a36Sopenharmony_ci .con_font_get = vgacon_font_get, 117962306a36Sopenharmony_ci .con_resize = vgacon_resize, 118062306a36Sopenharmony_ci .con_set_palette = vgacon_set_palette, 118162306a36Sopenharmony_ci .con_scrolldelta = vgacon_scrolldelta, 118262306a36Sopenharmony_ci .con_set_origin = vgacon_set_origin, 118362306a36Sopenharmony_ci .con_save_screen = vgacon_save_screen, 118462306a36Sopenharmony_ci .con_build_attr = vgacon_build_attr, 118562306a36Sopenharmony_ci .con_invert_region = vgacon_invert_region, 118662306a36Sopenharmony_ci}; 118762306a36Sopenharmony_ciEXPORT_SYMBOL(vga_con); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1190