1 /* 2 * linux/drivers/video/vgastate.c -- VGA state save/restore 3 * 4 * Copyright 2002 James Simmons 5 * 6 * Copyright history from vga16fb.c: 7 * Copyright 1999 Ben Pfaff and Petr Vandrovec 8 * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm 9 * Based on VESA framebuffer (c) 1998 Gerd Knorr 10 * 11 * This file is subject to the terms and conditions of the GNU General 12 * Public License. See the file COPYING in the main directory of this 13 * archive for more details. 14 * 15 */ 16 #include <linux/config.h> 17 #include <linux/module.h> 18 #include <linux/slab.h> 19 #include <linux/fb.h> 20 #include <linux/vmalloc.h> 21 #include <video/vga.h> 22 23 struct regstate { 24 __u8 *vga_font0; 25 __u8 *vga_font1; 26 __u8 *vga_text; 27 __u8 *vga_cmap; 28 __u8 *attr; 29 __u8 *crtc; 30 __u8 *gfx; 31 __u8 *seq; 32 __u8 misc; 33 }; 34 35 static inline unsigned char vga_rcrtcs(void __iomem *regbase, unsigned short iobase, 36 unsigned char reg) 37 { 38 vga_w(regbase, iobase + 0x4, reg); 39 return vga_r(regbase, iobase + 0x5); 40 } 41 42 static inline void vga_wcrtcs(void __iomem *regbase, unsigned short iobase, 43 unsigned char reg, unsigned char val) 44 { 45 vga_w(regbase, iobase + 0x4, reg); 46 vga_w(regbase, iobase + 0x5, val); 47 } 48 49 static void save_vga_text(struct vgastate *state, void __iomem *fbbase) 50 { 51 struct regstate *saved = (struct regstate *) state->vidstate; 52 int i; 53 u8 misc, attr10, gr4, gr5, gr6, seq1, seq2, seq4; 54 55 /* if in graphics mode, no need to save */ 56 attr10 = vga_rattr(state->vgabase, 0x10); 57 if (attr10 & 1) 58 return; 59 60 /* save regs */ 61 misc = vga_r(state->vgabase, VGA_MIS_R); 62 gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ); 63 gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE); 64 gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC); 65 seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE); 66 seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE); 67 68 /* force graphics mode */ 69 vga_w(state->vgabase, VGA_MIS_W, misc | 1); 70 71 /* blank screen */ 72 seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE); 73 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); 74 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5); 75 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); 76 77 /* save font at plane 2 */ 78 if (state->flags & VGA_SAVE_FONT0) { 79 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4); 80 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 81 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2); 82 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 83 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 84 for (i = 0; i < 4 * 8192; i++) 85 saved->vga_font0[i] = vga_r(fbbase, i); 86 } 87 88 /* save font at plane 3 */ 89 if (state->flags & VGA_SAVE_FONT1) { 90 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8); 91 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 92 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3); 93 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 94 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 95 for (i = 0; i < state->memsize; i++) 96 saved->vga_font1[i] = vga_r(fbbase, i); 97 } 98 99 /* save font at plane 0/1 */ 100 if (state->flags & VGA_SAVE_TEXT) { 101 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1); 102 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 103 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0); 104 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 105 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 106 for (i = 0; i < 8192; i++) 107 saved->vga_text[i] = vga_r(fbbase, i); 108 109 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2); 110 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 111 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1); 112 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 113 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 114 for (i = 0; i < 8192; i++) 115 saved->vga_text[8192+i] = vga_r(fbbase + 2 * 8192, i); 116 } 117 118 /* restore regs */ 119 vga_wattr(state->vgabase, 0x10, attr10); 120 121 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2); 122 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4); 123 124 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4); 125 vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5); 126 vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6); 127 vga_w(state->vgabase, VGA_MIS_W, misc); 128 129 /* unblank screen */ 130 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); 131 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5)); 132 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); 133 134 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1); 135 } 136 137 static void restore_vga_text(struct vgastate *state, void __iomem *fbbase) 138 { 139 struct regstate *saved = (struct regstate *) state->vidstate; 140 int i; 141 u8 misc, gr1, gr3, gr4, gr5, gr6, gr8; 142 u8 seq1, seq2, seq4; 143 144 /* save regs */ 145 misc = vga_r(state->vgabase, VGA_MIS_R); 146 gr1 = vga_rgfx(state->vgabase, VGA_GFX_SR_ENABLE); 147 gr3 = vga_rgfx(state->vgabase, VGA_GFX_DATA_ROTATE); 148 gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ); 149 gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE); 150 gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC); 151 gr8 = vga_rgfx(state->vgabase, VGA_GFX_BIT_MASK); 152 seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE); 153 seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE); 154 155 /* force graphics mode */ 156 vga_w(state->vgabase, VGA_MIS_W, misc | 1); 157 158 /* blank screen */ 159 seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE); 160 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); 161 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5); 162 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); 163 164 if (state->depth == 4) { 165 vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, 0x0); 166 vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, 0xff); 167 vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, 0x00); 168 } 169 170 /* restore font at plane 2 */ 171 if (state->flags & VGA_SAVE_FONT0) { 172 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4); 173 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 174 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2); 175 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 176 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 177 for (i = 0; i < 4 * 8192; i++) 178 vga_w(fbbase, i, saved->vga_font0[i]); 179 } 180 181 /* restore font at plane 3 */ 182 if (state->flags & VGA_SAVE_FONT1) { 183 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8); 184 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 185 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3); 186 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 187 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 188 for (i = 0; i < state->memsize; i++) 189 vga_w(fbbase, i, saved->vga_font1[i]); 190 } 191 192 /* restore font at plane 0/1 */ 193 if (state->flags & VGA_SAVE_TEXT) { 194 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1); 195 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 196 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0); 197 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 198 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 199 for (i = 0; i < 8192; i++) 200 vga_w(fbbase, i, saved->vga_text[i]); 201 202 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2); 203 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 204 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1); 205 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 206 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 207 for (i = 0; i < 8192; i++) 208 vga_w(fbbase, i, saved->vga_text[8192+i]); 209 } 210 211 /* unblank screen */ 212 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); 213 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5)); 214 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); 215 216 /* restore regs */ 217 vga_w(state->vgabase, VGA_MIS_W, misc); 218 219 vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, gr1); 220 vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, gr3); 221 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4); 222 vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5); 223 vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6); 224 vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, gr8); 225 226 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1); 227 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2); 228 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4); 229 } 230 231 static void save_vga_mode(struct vgastate *state) 232 { 233 struct regstate *saved = (struct regstate *) state->vidstate; 234 unsigned short iobase; 235 int i; 236 237 saved->misc = vga_r(state->vgabase, VGA_MIS_R); 238 if (saved->misc & 1) 239 iobase = 0x3d0; 240 else 241 iobase = 0x3b0; 242 243 for (i = 0; i < state->num_crtc; i++) 244 saved->crtc[i] = vga_rcrtcs(state->vgabase, iobase, i); 245 246 vga_r(state->vgabase, iobase + 0xa); 247 vga_w(state->vgabase, VGA_ATT_W, 0x00); 248 for (i = 0; i < state->num_attr; i++) { 249 vga_r(state->vgabase, iobase + 0xa); 250 saved->attr[i] = vga_rattr(state->vgabase, i); 251 } 252 vga_r(state->vgabase, iobase + 0xa); 253 vga_w(state->vgabase, VGA_ATT_W, 0x20); 254 255 for (i = 0; i < state->num_gfx; i++) 256 saved->gfx[i] = vga_rgfx(state->vgabase, i); 257 258 for (i = 0; i < state->num_seq; i++) 259 saved->seq[i] = vga_rseq(state->vgabase, i); 260 } 261 262 static void restore_vga_mode(struct vgastate *state) 263 { 264 struct regstate *saved = (struct regstate *) state->vidstate; 265 unsigned short iobase; 266 int i; 267 268 vga_w(state->vgabase, VGA_MIS_W, saved->misc); 269 270 if (saved->misc & 1) 271 iobase = 0x3d0; 272 else 273 iobase = 0x3b0; 274 275 /* turn off display */ 276 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, 277 saved->seq[VGA_SEQ_CLOCK_MODE] | 0x20); 278 279 /* disable sequencer */ 280 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01); 281 282 /* enable palette addressing */ 283 vga_r(state->vgabase, iobase + 0xa); 284 vga_w(state->vgabase, VGA_ATT_W, 0x00); 285 286 for (i = 2; i < state->num_seq; i++) 287 vga_wseq(state->vgabase, i, saved->seq[i]); 288 289 290 /* unprotect vga regs */ 291 vga_wcrtcs(state->vgabase, iobase, 17, saved->crtc[17] & ~0x80); 292 for (i = 0; i < state->num_crtc; i++) 293 vga_wcrtcs(state->vgabase, iobase, i, saved->crtc[i]); 294 295 for (i = 0; i < state->num_gfx; i++) 296 vga_wgfx(state->vgabase, i, saved->gfx[i]); 297 298 for (i = 0; i < state->num_attr; i++) { 299 vga_r(state->vgabase, iobase + 0xa); 300 vga_wattr(state->vgabase, i, saved->attr[i]); 301 } 302 303 /* reenable sequencer */ 304 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); 305 /* turn display on */ 306 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, 307 saved->seq[VGA_SEQ_CLOCK_MODE] & ~(1 << 5)); 308 309 /* disable video/palette source */ 310 vga_r(state->vgabase, iobase + 0xa); 311 vga_w(state->vgabase, VGA_ATT_W, 0x20); 312 } 313 314 static void save_vga_cmap(struct vgastate *state) 315 { 316 struct regstate *saved = (struct regstate *) state->vidstate; 317 int i; 318 319 vga_w(state->vgabase, VGA_PEL_MSK, 0xff); 320 321 /* assumes DAC is readable and writable */ 322 vga_w(state->vgabase, VGA_PEL_IR, 0x00); 323 for (i = 0; i < 768; i++) 324 saved->vga_cmap[i] = vga_r(state->vgabase, VGA_PEL_D); 325 } 326 327 static void restore_vga_cmap(struct vgastate *state) 328 { 329 struct regstate *saved = (struct regstate *) state->vidstate; 330 int i; 331 332 vga_w(state->vgabase, VGA_PEL_MSK, 0xff); 333 334 /* assumes DAC is readable and writable */ 335 vga_w(state->vgabase, VGA_PEL_IW, 0x00); 336 for (i = 0; i < 768; i++) 337 vga_w(state->vgabase, VGA_PEL_D, saved->vga_cmap[i]); 338 } 339 340 static void vga_cleanup(struct vgastate *state) 341 { 342 if (state->vidstate != NULL) { 343 struct regstate *saved = (struct regstate *) state->vidstate; 344 345 if (saved->vga_font0) 346 vfree(saved->vga_font0); 347 if (saved->vga_font1) 348 vfree(saved->vga_font1); 349 if (saved->vga_text) 350 vfree(saved->vga_text); 351 if (saved->vga_cmap) 352 vfree(saved->vga_cmap); 353 if (saved->attr) 354 vfree(saved->attr); 355 kfree(saved); 356 state->vidstate = NULL; 357 } 358 } 359 360 int save_vga(struct vgastate *state) 361 { 362 struct regstate *saved; 363 364 saved = kmalloc(sizeof(struct regstate), GFP_KERNEL); 365 if (saved == NULL) 366 return 1; 367 memset (saved, 0, sizeof(struct regstate)); 368 state->vidstate = (void *)saved; 369 370 if (state->flags & VGA_SAVE_CMAP) { 371 saved->vga_cmap = vmalloc(768); 372 if (!saved->vga_cmap) { 373 vga_cleanup(state); 374 return 1; 375 } 376 save_vga_cmap(state); 377 } 378 379 if (state->flags & VGA_SAVE_MODE) { 380 int total; 381 382 if (state->num_attr < 21) 383 state->num_attr = 21; 384 if (state->num_crtc < 25) 385 state->num_crtc = 25; 386 if (state->num_gfx < 9) 387 state->num_gfx = 9; 388 if (state->num_seq < 5) 389 state->num_seq = 5; 390 total = state->num_attr + state->num_crtc + 391 state->num_gfx + state->num_seq; 392 393 saved->attr = vmalloc(total); 394 if (!saved->attr) { 395 vga_cleanup(state); 396 return 1; 397 } 398 saved->crtc = saved->attr + state->num_attr; 399 saved->gfx = saved->crtc + state->num_crtc; 400 saved->seq = saved->gfx + state->num_gfx; 401 402 save_vga_mode(state); 403 } 404 405 if (state->flags & VGA_SAVE_FONTS) { 406 void __iomem *fbbase; 407 408 /* exit if window is less than 32K */ 409 if (state->memsize && state->memsize < 4 * 8192) { 410 vga_cleanup(state); 411 return 1; 412 } 413 if (!state->memsize) 414 state->memsize = 8 * 8192; 415 416 if (!state->membase) 417 state->membase = 0xA0000; 418 419 fbbase = ioremap(state->membase, state->memsize); 420 421 if (!fbbase) { 422 vga_cleanup(state); 423 return 1; 424 } 425 426 /* 427 * save only first 32K used by vgacon 428 */ 429 if (state->flags & VGA_SAVE_FONT0) { 430 saved->vga_font0 = vmalloc(4 * 8192); 431 if (!saved->vga_font0) { 432 iounmap(fbbase); 433 vga_cleanup(state); 434 return 1; 435 } 436 } 437 /* 438 * largely unused, but if required by the caller 439 * we'll just save everything. 440 */ 441 if (state->flags & VGA_SAVE_FONT1) { 442 saved->vga_font1 = vmalloc(state->memsize); 443 if (!saved->vga_font1) { 444 iounmap(fbbase); 445 vga_cleanup(state); 446 return 1; 447 } 448 } 449 /* 450 * Save 8K at plane0[0], and 8K at plane1[16K] 451 */ 452 if (state->flags & VGA_SAVE_TEXT) { 453 saved->vga_text = vmalloc(8192 * 2); 454 if (!saved->vga_text) { 455 iounmap(fbbase); 456 vga_cleanup(state); 457 return 1; 458 } 459 } 460 461 save_vga_text(state, fbbase); 462 iounmap(fbbase); 463 } 464 return 0; 465 } 466 467 int restore_vga (struct vgastate *state) 468 { 469 if (state->vidstate == NULL) 470 return 1; 471 472 if (state->flags & VGA_SAVE_MODE) 473 restore_vga_mode(state); 474 475 if (state->flags & VGA_SAVE_FONTS) { 476 void __iomem *fbbase = ioremap(state->membase, state->memsize); 477 478 if (!fbbase) { 479 vga_cleanup(state); 480 return 1; 481 } 482 restore_vga_text(state, fbbase); 483 iounmap(fbbase); 484 } 485 486 if (state->flags & VGA_SAVE_CMAP) 487 restore_vga_cmap(state); 488 489 vga_cleanup(state); 490 return 0; 491 } 492 493 #ifdef MODULE 494 int init_module(void) { return 0; }; 495 void cleanup_module(void) {}; 496 #endif 497 498 EXPORT_SYMBOL(save_vga); 499 EXPORT_SYMBOL(restore_vga); 500 501 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); 502 MODULE_DESCRIPTION("VGA State Save/Restore"); 503 MODULE_LICENSE("GPL"); 504 505