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