1 /* -*- linux-c -*- ------------------------------------------------------- * 2 * 3 * Copyright (C) 1991, 1992 Linus Torvalds 4 * Copyright 2007 rPath, Inc. - All Rights Reserved 5 * Copyright 2009 Intel Corporation; author H. Peter Anvin 6 * 7 * This file is part of the Linux kernel, and is made available under 8 * the terms of the GNU General Public License version 2. 9 * 10 * ----------------------------------------------------------------------- */ 11 12 /* 13 * Common all-VGA modes 14 */ 15 16 #include "boot.h" 17 #include "video.h" 18 19 static struct mode_info vga_modes[] = { 20 { VIDEO_80x25, 80, 25, 0 }, 21 { VIDEO_8POINT, 80, 50, 0 }, 22 { VIDEO_80x43, 80, 43, 0 }, 23 { VIDEO_80x28, 80, 28, 0 }, 24 { VIDEO_80x30, 80, 30, 0 }, 25 { VIDEO_80x34, 80, 34, 0 }, 26 { VIDEO_80x60, 80, 60, 0 }, 27 }; 28 29 static struct mode_info ega_modes[] = { 30 { VIDEO_80x25, 80, 25, 0 }, 31 { VIDEO_8POINT, 80, 43, 0 }, 32 }; 33 34 static struct mode_info cga_modes[] = { 35 { VIDEO_80x25, 80, 25, 0 }, 36 }; 37 38 static __videocard video_vga; 39 40 /* Set basic 80x25 mode */ 41 static u8 vga_set_basic_mode(void) 42 { 43 struct biosregs ireg, oreg; 44 u16 ax; 45 u8 rows; 46 u8 mode; 47 48 initregs(&ireg); 49 50 ax = 0x0f00; 51 intcall(0x10, &ireg, &oreg); 52 mode = oreg.al; 53 54 set_fs(0); 55 rows = rdfs8(0x484); /* rows minus one */ 56 57 if ((oreg.ax == 0x5003 || oreg.ax == 0x5007) && 58 (rows == 0 || rows == 24)) 59 return mode; 60 61 if (mode != 3 && mode != 7) 62 mode = 3; 63 64 /* Set the mode */ 65 ireg.ax = mode; /* AH=0: set mode */ 66 intcall(0x10, &ireg, NULL); 67 do_restore = 1; 68 return mode; 69 } 70 71 static void vga_set_8font(void) 72 { 73 /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */ 74 struct biosregs ireg; 75 76 initregs(&ireg); 77 78 /* Set 8x8 font */ 79 ireg.ax = 0x1112; 80 /* ireg.bl = 0; */ 81 intcall(0x10, &ireg, NULL); 82 83 /* Use alternate print screen */ 84 ireg.ax = 0x1200; 85 ireg.bl = 0x20; 86 intcall(0x10, &ireg, NULL); 87 88 /* Turn off cursor emulation */ 89 ireg.ax = 0x1201; 90 ireg.bl = 0x34; 91 intcall(0x10, &ireg, NULL); 92 93 /* Cursor is scan lines 6-7 */ 94 ireg.ax = 0x0100; 95 ireg.cx = 0x0607; 96 intcall(0x10, &ireg, NULL); 97 } 98 99 static void vga_set_14font(void) 100 { 101 /* Set 9x14 font - 80x28 on VGA */ 102 struct biosregs ireg; 103 104 initregs(&ireg); 105 106 /* Set 9x14 font */ 107 ireg.ax = 0x1111; 108 /* ireg.bl = 0; */ 109 intcall(0x10, &ireg, NULL); 110 111 /* Turn off cursor emulation */ 112 ireg.ax = 0x1201; 113 ireg.bl = 0x34; 114 intcall(0x10, &ireg, NULL); 115 116 /* Cursor is scan lines 11-12 */ 117 ireg.ax = 0x0100; 118 ireg.cx = 0x0b0c; 119 intcall(0x10, &ireg, NULL); 120 } 121 122 static void vga_set_80x43(void) 123 { 124 /* Set 80x43 mode on VGA (not EGA) */ 125 struct biosregs ireg; 126 127 initregs(&ireg); 128 129 /* Set 350 scans */ 130 ireg.ax = 0x1201; 131 ireg.bl = 0x30; 132 intcall(0x10, &ireg, NULL); 133 134 /* Reset video mode */ 135 ireg.ax = 0x0003; 136 intcall(0x10, &ireg, NULL); 137 138 vga_set_8font(); 139 } 140 141 /* I/O address of the VGA CRTC */ 142 u16 vga_crtc(void) 143 { 144 return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4; 145 } 146 147 static void vga_set_480_scanlines(void) 148 { 149 u16 crtc; /* CRTC base address */ 150 u8 csel; /* CRTC miscellaneous output register */ 151 152 crtc = vga_crtc(); 153 154 out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */ 155 out_idx(0x0b, crtc, 0x06); /* Vertical total */ 156 out_idx(0x3e, crtc, 0x07); /* Vertical overflow */ 157 out_idx(0xea, crtc, 0x10); /* Vertical sync start */ 158 out_idx(0xdf, crtc, 0x12); /* Vertical display end */ 159 out_idx(0xe7, crtc, 0x15); /* Vertical blank start */ 160 out_idx(0x04, crtc, 0x16); /* Vertical blank end */ 161 csel = inb(0x3cc); 162 csel &= 0x0d; 163 csel |= 0xe2; 164 outb(csel, 0x3c2); 165 } 166 167 static void vga_set_vertical_end(int lines) 168 { 169 u16 crtc; /* CRTC base address */ 170 u8 ovfw; /* CRTC overflow register */ 171 int end = lines-1; 172 173 crtc = vga_crtc(); 174 175 ovfw = 0x3c | ((end >> (8-1)) & 0x02) | ((end >> (9-6)) & 0x40); 176 177 out_idx(ovfw, crtc, 0x07); /* Vertical overflow */ 178 out_idx(end, crtc, 0x12); /* Vertical display end */ 179 } 180 181 static void vga_set_80x30(void) 182 { 183 vga_set_480_scanlines(); 184 vga_set_vertical_end(30*16); 185 } 186 187 static void vga_set_80x34(void) 188 { 189 vga_set_480_scanlines(); 190 vga_set_14font(); 191 vga_set_vertical_end(34*14); 192 } 193 194 static void vga_set_80x60(void) 195 { 196 vga_set_480_scanlines(); 197 vga_set_8font(); 198 vga_set_vertical_end(60*8); 199 } 200 201 static int vga_set_mode(struct mode_info *mode) 202 { 203 /* Set the basic mode */ 204 vga_set_basic_mode(); 205 206 /* Override a possibly broken BIOS */ 207 force_x = mode->x; 208 force_y = mode->y; 209 210 switch (mode->mode) { 211 case VIDEO_80x25: 212 break; 213 case VIDEO_8POINT: 214 vga_set_8font(); 215 break; 216 case VIDEO_80x43: 217 vga_set_80x43(); 218 break; 219 case VIDEO_80x28: 220 vga_set_14font(); 221 break; 222 case VIDEO_80x30: 223 vga_set_80x30(); 224 break; 225 case VIDEO_80x34: 226 vga_set_80x34(); 227 break; 228 case VIDEO_80x60: 229 vga_set_80x60(); 230 break; 231 } 232 233 return 0; 234 } 235 236 /* 237 * Note: this probe includes basic information required by all 238 * systems. It should be executed first, by making sure 239 * video-vga.c is listed first in the Makefile. 240 */ 241 static int vga_probe(void) 242 { 243 static const char *card_name[] = { 244 "CGA/MDA/HGC", "EGA", "VGA" 245 }; 246 static struct mode_info *mode_lists[] = { 247 cga_modes, 248 ega_modes, 249 vga_modes, 250 }; 251 static int mode_count[] = { 252 sizeof(cga_modes)/sizeof(struct mode_info), 253 sizeof(ega_modes)/sizeof(struct mode_info), 254 sizeof(vga_modes)/sizeof(struct mode_info), 255 }; 256 257 struct biosregs ireg, oreg; 258 259 initregs(&ireg); 260 261 ireg.ax = 0x1200; 262 ireg.bl = 0x10; /* Check EGA/VGA */ 263 intcall(0x10, &ireg, &oreg); 264 265 #ifndef _WAKEUP 266 boot_params.screen_info.orig_video_ega_bx = oreg.bx; 267 #endif 268 269 /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ 270 if (oreg.bl != 0x10) { 271 /* EGA/VGA */ 272 ireg.ax = 0x1a00; 273 intcall(0x10, &ireg, &oreg); 274 275 if (oreg.al == 0x1a) { 276 adapter = ADAPTER_VGA; 277 #ifndef _WAKEUP 278 boot_params.screen_info.orig_video_isVGA = 1; 279 #endif 280 } else { 281 adapter = ADAPTER_EGA; 282 } 283 } else { 284 adapter = ADAPTER_CGA; 285 } 286 287 video_vga.modes = mode_lists[adapter]; 288 video_vga.card_name = card_name[adapter]; 289 return mode_count[adapter]; 290 } 291 292 static __videocard video_vga = { 293 .card_name = "VGA", 294 .probe = vga_probe, 295 .set_mode = vga_set_mode, 296 }; 297