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