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 __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(int end) 133 { 134 u16 crtc; 135 u8 csel; 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(end, 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, 0x3cc); 150 } 151 152 static void vga_set_80x30(void) 153 { 154 vga_set_480_scanlines(0xdf); 155 } 156 157 static void vga_set_80x34(void) 158 { 159 vga_set_14font(); 160 vga_set_480_scanlines(0xdb); 161 } 162 163 static void vga_set_80x60(void) 164 { 165 vga_set_8font(); 166 vga_set_480_scanlines(0xdf); 167 } 168 169 static int vga_set_mode(struct mode_info *mode) 170 { 171 /* Set the basic mode */ 172 vga_set_basic_mode(); 173 174 /* Override a possibly broken BIOS */ 175 force_x = mode->x; 176 force_y = mode->y; 177 178 switch (mode->mode) { 179 case VIDEO_80x25: 180 break; 181 case VIDEO_8POINT: 182 vga_set_8font(); 183 break; 184 case VIDEO_80x43: 185 vga_set_80x43(); 186 break; 187 case VIDEO_80x28: 188 vga_set_14font(); 189 break; 190 case VIDEO_80x30: 191 vga_set_80x30(); 192 break; 193 case VIDEO_80x34: 194 vga_set_80x34(); 195 break; 196 case VIDEO_80x60: 197 vga_set_80x60(); 198 break; 199 } 200 201 return 0; 202 } 203 204 /* 205 * Note: this probe includes basic information required by all 206 * systems. It should be executed first, by making sure 207 * video-vga.c is listed first in the Makefile. 208 */ 209 static int vga_probe(void) 210 { 211 u16 ega_bx; 212 213 static const char *card_name[] = { 214 "CGA/MDA/HGC", "EGA", "VGA" 215 }; 216 static struct mode_info *mode_lists[] = { 217 cga_modes, 218 ega_modes, 219 vga_modes, 220 }; 221 static int mode_count[] = { 222 sizeof(cga_modes)/sizeof(struct mode_info), 223 sizeof(ega_modes)/sizeof(struct mode_info), 224 sizeof(vga_modes)/sizeof(struct mode_info), 225 }; 226 u8 vga_flag; 227 228 asm(INT10 229 : "=b" (ega_bx) 230 : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */ 231 : "ecx", "edx", "esi", "edi"); 232 233 #ifndef _WAKEUP 234 boot_params.screen_info.orig_video_ega_bx = ega_bx; 235 #endif 236 237 /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ 238 if ((u8)ega_bx != 0x10) { 239 /* EGA/VGA */ 240 asm(INT10 241 : "=a" (vga_flag) 242 : "a" (0x1a00) 243 : "ebx", "ecx", "edx", "esi", "edi"); 244 245 if (vga_flag == 0x1a) { 246 adapter = ADAPTER_VGA; 247 #ifndef _WAKEUP 248 boot_params.screen_info.orig_video_isVGA = 1; 249 #endif 250 } else { 251 adapter = ADAPTER_EGA; 252 } 253 } else { 254 adapter = ADAPTER_CGA; 255 } 256 257 video_vga.modes = mode_lists[adapter]; 258 video_vga.card_name = card_name[adapter]; 259 return mode_count[adapter]; 260 } 261 262 __videocard video_vga = { 263 .card_name = "VGA", 264 .probe = vga_probe, 265 .set_mode = vga_set_mode, 266 }; 267