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