18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/video/vgastate.c -- VGA state save/restore 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2002 James Simmons 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright history from vga16fb.c: 78c2ecf20Sopenharmony_ci * Copyright 1999 Ben Pfaff and Petr Vandrovec 88c2ecf20Sopenharmony_ci * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm 98c2ecf20Sopenharmony_ci * Based on VESA framebuffer (c) 1998 Gerd Knorr 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General 128c2ecf20Sopenharmony_ci * Public License. See the file COPYING in the main directory of this 138c2ecf20Sopenharmony_ci * archive for more details. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/fb.h> 198c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 208c2ecf20Sopenharmony_ci#include <video/vga.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct regstate { 238c2ecf20Sopenharmony_ci __u8 *vga_font0; 248c2ecf20Sopenharmony_ci __u8 *vga_font1; 258c2ecf20Sopenharmony_ci __u8 *vga_text; 268c2ecf20Sopenharmony_ci __u8 *vga_cmap; 278c2ecf20Sopenharmony_ci __u8 *attr; 288c2ecf20Sopenharmony_ci __u8 *crtc; 298c2ecf20Sopenharmony_ci __u8 *gfx; 308c2ecf20Sopenharmony_ci __u8 *seq; 318c2ecf20Sopenharmony_ci __u8 misc; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic inline unsigned char vga_rcrtcs(void __iomem *regbase, unsigned short iobase, 358c2ecf20Sopenharmony_ci unsigned char reg) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci vga_w(regbase, iobase + 0x4, reg); 388c2ecf20Sopenharmony_ci return vga_r(regbase, iobase + 0x5); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic inline void vga_wcrtcs(void __iomem *regbase, unsigned short iobase, 428c2ecf20Sopenharmony_ci unsigned char reg, unsigned char val) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci vga_w(regbase, iobase + 0x4, reg); 458c2ecf20Sopenharmony_ci vga_w(regbase, iobase + 0x5, val); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void save_vga_text(struct vgastate *state, void __iomem *fbbase) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct regstate *saved = (struct regstate *) state->vidstate; 518c2ecf20Sopenharmony_ci int i; 528c2ecf20Sopenharmony_ci u8 misc, attr10, gr4, gr5, gr6, seq1, seq2, seq4; 538c2ecf20Sopenharmony_ci unsigned short iobase; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* if in graphics mode, no need to save */ 568c2ecf20Sopenharmony_ci misc = vga_r(state->vgabase, VGA_MIS_R); 578c2ecf20Sopenharmony_ci iobase = (misc & 1) ? 0x3d0 : 0x3b0; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci vga_r(state->vgabase, iobase + 0xa); 608c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_ATT_W, 0x00); 618c2ecf20Sopenharmony_ci attr10 = vga_rattr(state->vgabase, 0x10); 628c2ecf20Sopenharmony_ci vga_r(state->vgabase, iobase + 0xa); 638c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_ATT_W, 0x20); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (attr10 & 1) 668c2ecf20Sopenharmony_ci return; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* save regs */ 698c2ecf20Sopenharmony_ci gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ); 708c2ecf20Sopenharmony_ci gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE); 718c2ecf20Sopenharmony_ci gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC); 728c2ecf20Sopenharmony_ci seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE); 738c2ecf20Sopenharmony_ci seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* blank screen */ 768c2ecf20Sopenharmony_ci seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE); 778c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); 788c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5); 798c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* save font at plane 2 */ 828c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_FONT0) { 838c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4); 848c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 858c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2); 868c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 878c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 888c2ecf20Sopenharmony_ci for (i = 0; i < 4 * 8192; i++) 898c2ecf20Sopenharmony_ci saved->vga_font0[i] = vga_r(fbbase, i); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* save font at plane 3 */ 938c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_FONT1) { 948c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8); 958c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 968c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3); 978c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 988c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 998c2ecf20Sopenharmony_ci for (i = 0; i < state->memsize; i++) 1008c2ecf20Sopenharmony_ci saved->vga_font1[i] = vga_r(fbbase, i); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* save font at plane 0/1 */ 1048c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_TEXT) { 1058c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1); 1068c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 1078c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0); 1088c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 1098c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 1108c2ecf20Sopenharmony_ci for (i = 0; i < 8192; i++) 1118c2ecf20Sopenharmony_ci saved->vga_text[i] = vga_r(fbbase, i); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2); 1148c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 1158c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1); 1168c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 1178c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 1188c2ecf20Sopenharmony_ci for (i = 0; i < 8192; i++) 1198c2ecf20Sopenharmony_ci saved->vga_text[8192+i] = vga_r(fbbase + 2 * 8192, i); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* restore regs */ 1238c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2); 1248c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4); 1278c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5); 1288c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* unblank screen */ 1318c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); 1328c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5)); 1338c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void restore_vga_text(struct vgastate *state, void __iomem *fbbase) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct regstate *saved = (struct regstate *) state->vidstate; 1418c2ecf20Sopenharmony_ci int i; 1428c2ecf20Sopenharmony_ci u8 gr1, gr3, gr4, gr5, gr6, gr8; 1438c2ecf20Sopenharmony_ci u8 seq1, seq2, seq4; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* save regs */ 1468c2ecf20Sopenharmony_ci gr1 = vga_rgfx(state->vgabase, VGA_GFX_SR_ENABLE); 1478c2ecf20Sopenharmony_ci gr3 = vga_rgfx(state->vgabase, VGA_GFX_DATA_ROTATE); 1488c2ecf20Sopenharmony_ci gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ); 1498c2ecf20Sopenharmony_ci gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE); 1508c2ecf20Sopenharmony_ci gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC); 1518c2ecf20Sopenharmony_ci gr8 = vga_rgfx(state->vgabase, VGA_GFX_BIT_MASK); 1528c2ecf20Sopenharmony_ci seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE); 1538c2ecf20Sopenharmony_ci seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* blank screen */ 1568c2ecf20Sopenharmony_ci seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE); 1578c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); 1588c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 | 1 << 5); 1598c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (state->depth == 4) { 1628c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, 0x0); 1638c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, 0xff); 1648c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, 0x00); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* restore font at plane 2 */ 1688c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_FONT0) { 1698c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4); 1708c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 1718c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2); 1728c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 1738c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 1748c2ecf20Sopenharmony_ci for (i = 0; i < 4 * 8192; i++) 1758c2ecf20Sopenharmony_ci vga_w(fbbase, i, saved->vga_font0[i]); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* restore font at plane 3 */ 1798c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_FONT1) { 1808c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x8); 1818c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 1828c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3); 1838c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 1848c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 1858c2ecf20Sopenharmony_ci for (i = 0; i < state->memsize; i++) 1868c2ecf20Sopenharmony_ci vga_w(fbbase, i, saved->vga_font1[i]); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* restore font at plane 0/1 */ 1908c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_TEXT) { 1918c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1); 1928c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 1938c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0); 1948c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 1958c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 1968c2ecf20Sopenharmony_ci for (i = 0; i < 8192; i++) 1978c2ecf20Sopenharmony_ci vga_w(fbbase, i, saved->vga_text[i]); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2); 2008c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6); 2018c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1); 2028c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0); 2038c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5); 2048c2ecf20Sopenharmony_ci for (i = 0; i < 8192; i++) 2058c2ecf20Sopenharmony_ci vga_w(fbbase, i, saved->vga_text[8192+i]); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* unblank screen */ 2098c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1); 2108c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1 & ~(1 << 5)); 2118c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* restore regs */ 2148c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, gr1); 2158c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, gr3); 2168c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4); 2178c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5); 2188c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6); 2198c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, gr8); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, seq1); 2228c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2); 2238c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic void save_vga_mode(struct vgastate *state) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct regstate *saved = (struct regstate *) state->vidstate; 2298c2ecf20Sopenharmony_ci unsigned short iobase; 2308c2ecf20Sopenharmony_ci int i; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci saved->misc = vga_r(state->vgabase, VGA_MIS_R); 2338c2ecf20Sopenharmony_ci if (saved->misc & 1) 2348c2ecf20Sopenharmony_ci iobase = 0x3d0; 2358c2ecf20Sopenharmony_ci else 2368c2ecf20Sopenharmony_ci iobase = 0x3b0; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci for (i = 0; i < state->num_crtc; i++) 2398c2ecf20Sopenharmony_ci saved->crtc[i] = vga_rcrtcs(state->vgabase, iobase, i); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci vga_r(state->vgabase, iobase + 0xa); 2428c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_ATT_W, 0x00); 2438c2ecf20Sopenharmony_ci for (i = 0; i < state->num_attr; i++) { 2448c2ecf20Sopenharmony_ci vga_r(state->vgabase, iobase + 0xa); 2458c2ecf20Sopenharmony_ci saved->attr[i] = vga_rattr(state->vgabase, i); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci vga_r(state->vgabase, iobase + 0xa); 2488c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_ATT_W, 0x20); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci for (i = 0; i < state->num_gfx; i++) 2518c2ecf20Sopenharmony_ci saved->gfx[i] = vga_rgfx(state->vgabase, i); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci for (i = 0; i < state->num_seq; i++) 2548c2ecf20Sopenharmony_ci saved->seq[i] = vga_rseq(state->vgabase, i); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void restore_vga_mode(struct vgastate *state) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct regstate *saved = (struct regstate *) state->vidstate; 2608c2ecf20Sopenharmony_ci unsigned short iobase; 2618c2ecf20Sopenharmony_ci int i; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_MIS_W, saved->misc); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (saved->misc & 1) 2668c2ecf20Sopenharmony_ci iobase = 0x3d0; 2678c2ecf20Sopenharmony_ci else 2688c2ecf20Sopenharmony_ci iobase = 0x3b0; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* turn off display */ 2718c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, 2728c2ecf20Sopenharmony_ci saved->seq[VGA_SEQ_CLOCK_MODE] | 0x20); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* disable sequencer */ 2758c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* enable palette addressing */ 2788c2ecf20Sopenharmony_ci vga_r(state->vgabase, iobase + 0xa); 2798c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_ATT_W, 0x00); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci for (i = 2; i < state->num_seq; i++) 2828c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, i, saved->seq[i]); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* unprotect vga regs */ 2868c2ecf20Sopenharmony_ci vga_wcrtcs(state->vgabase, iobase, 17, saved->crtc[17] & ~0x80); 2878c2ecf20Sopenharmony_ci for (i = 0; i < state->num_crtc; i++) 2888c2ecf20Sopenharmony_ci vga_wcrtcs(state->vgabase, iobase, i, saved->crtc[i]); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci for (i = 0; i < state->num_gfx; i++) 2918c2ecf20Sopenharmony_ci vga_wgfx(state->vgabase, i, saved->gfx[i]); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci for (i = 0; i < state->num_attr; i++) { 2948c2ecf20Sopenharmony_ci vga_r(state->vgabase, iobase + 0xa); 2958c2ecf20Sopenharmony_ci vga_wattr(state->vgabase, i, saved->attr[i]); 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* reenable sequencer */ 2998c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03); 3008c2ecf20Sopenharmony_ci /* turn display on */ 3018c2ecf20Sopenharmony_ci vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, 3028c2ecf20Sopenharmony_ci saved->seq[VGA_SEQ_CLOCK_MODE] & ~(1 << 5)); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* disable video/palette source */ 3058c2ecf20Sopenharmony_ci vga_r(state->vgabase, iobase + 0xa); 3068c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_ATT_W, 0x20); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic void save_vga_cmap(struct vgastate *state) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct regstate *saved = (struct regstate *) state->vidstate; 3128c2ecf20Sopenharmony_ci int i; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_PEL_MSK, 0xff); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* assumes DAC is readable and writable */ 3178c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_PEL_IR, 0x00); 3188c2ecf20Sopenharmony_ci for (i = 0; i < 768; i++) 3198c2ecf20Sopenharmony_ci saved->vga_cmap[i] = vga_r(state->vgabase, VGA_PEL_D); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic void restore_vga_cmap(struct vgastate *state) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct regstate *saved = (struct regstate *) state->vidstate; 3258c2ecf20Sopenharmony_ci int i; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_PEL_MSK, 0xff); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* assumes DAC is readable and writable */ 3308c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_PEL_IW, 0x00); 3318c2ecf20Sopenharmony_ci for (i = 0; i < 768; i++) 3328c2ecf20Sopenharmony_ci vga_w(state->vgabase, VGA_PEL_D, saved->vga_cmap[i]); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic void vga_cleanup(struct vgastate *state) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci if (state->vidstate != NULL) { 3388c2ecf20Sopenharmony_ci struct regstate *saved = (struct regstate *) state->vidstate; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci vfree(saved->vga_font0); 3418c2ecf20Sopenharmony_ci vfree(saved->vga_font1); 3428c2ecf20Sopenharmony_ci vfree(saved->vga_text); 3438c2ecf20Sopenharmony_ci vfree(saved->vga_cmap); 3448c2ecf20Sopenharmony_ci vfree(saved->attr); 3458c2ecf20Sopenharmony_ci kfree(saved); 3468c2ecf20Sopenharmony_ci state->vidstate = NULL; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ciint save_vga(struct vgastate *state) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct regstate *saved; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci saved = kzalloc(sizeof(struct regstate), GFP_KERNEL); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (saved == NULL) 3578c2ecf20Sopenharmony_ci return 1; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci state->vidstate = (void *)saved; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_CMAP) { 3628c2ecf20Sopenharmony_ci saved->vga_cmap = vmalloc(768); 3638c2ecf20Sopenharmony_ci if (!saved->vga_cmap) { 3648c2ecf20Sopenharmony_ci vga_cleanup(state); 3658c2ecf20Sopenharmony_ci return 1; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci save_vga_cmap(state); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_MODE) { 3718c2ecf20Sopenharmony_ci int total; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (state->num_attr < 21) 3748c2ecf20Sopenharmony_ci state->num_attr = 21; 3758c2ecf20Sopenharmony_ci if (state->num_crtc < 25) 3768c2ecf20Sopenharmony_ci state->num_crtc = 25; 3778c2ecf20Sopenharmony_ci if (state->num_gfx < 9) 3788c2ecf20Sopenharmony_ci state->num_gfx = 9; 3798c2ecf20Sopenharmony_ci if (state->num_seq < 5) 3808c2ecf20Sopenharmony_ci state->num_seq = 5; 3818c2ecf20Sopenharmony_ci total = state->num_attr + state->num_crtc + 3828c2ecf20Sopenharmony_ci state->num_gfx + state->num_seq; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci saved->attr = vmalloc(total); 3858c2ecf20Sopenharmony_ci if (!saved->attr) { 3868c2ecf20Sopenharmony_ci vga_cleanup(state); 3878c2ecf20Sopenharmony_ci return 1; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci saved->crtc = saved->attr + state->num_attr; 3908c2ecf20Sopenharmony_ci saved->gfx = saved->crtc + state->num_crtc; 3918c2ecf20Sopenharmony_ci saved->seq = saved->gfx + state->num_gfx; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci save_vga_mode(state); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_FONTS) { 3978c2ecf20Sopenharmony_ci void __iomem *fbbase; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* exit if window is less than 32K */ 4008c2ecf20Sopenharmony_ci if (state->memsize && state->memsize < 4 * 8192) { 4018c2ecf20Sopenharmony_ci vga_cleanup(state); 4028c2ecf20Sopenharmony_ci return 1; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci if (!state->memsize) 4058c2ecf20Sopenharmony_ci state->memsize = 8 * 8192; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (!state->membase) 4088c2ecf20Sopenharmony_ci state->membase = 0xA0000; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci fbbase = ioremap(state->membase, state->memsize); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (!fbbase) { 4138c2ecf20Sopenharmony_ci vga_cleanup(state); 4148c2ecf20Sopenharmony_ci return 1; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* 4188c2ecf20Sopenharmony_ci * save only first 32K used by vgacon 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_FONT0) { 4218c2ecf20Sopenharmony_ci saved->vga_font0 = vmalloc(4 * 8192); 4228c2ecf20Sopenharmony_ci if (!saved->vga_font0) { 4238c2ecf20Sopenharmony_ci iounmap(fbbase); 4248c2ecf20Sopenharmony_ci vga_cleanup(state); 4258c2ecf20Sopenharmony_ci return 1; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci /* 4298c2ecf20Sopenharmony_ci * largely unused, but if required by the caller 4308c2ecf20Sopenharmony_ci * we'll just save everything. 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_FONT1) { 4338c2ecf20Sopenharmony_ci saved->vga_font1 = vmalloc(state->memsize); 4348c2ecf20Sopenharmony_ci if (!saved->vga_font1) { 4358c2ecf20Sopenharmony_ci iounmap(fbbase); 4368c2ecf20Sopenharmony_ci vga_cleanup(state); 4378c2ecf20Sopenharmony_ci return 1; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci /* 4418c2ecf20Sopenharmony_ci * Save 8K at plane0[0], and 8K at plane1[16K] 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_TEXT) { 4448c2ecf20Sopenharmony_ci saved->vga_text = vmalloc(8192 * 2); 4458c2ecf20Sopenharmony_ci if (!saved->vga_text) { 4468c2ecf20Sopenharmony_ci iounmap(fbbase); 4478c2ecf20Sopenharmony_ci vga_cleanup(state); 4488c2ecf20Sopenharmony_ci return 1; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci save_vga_text(state, fbbase); 4538c2ecf20Sopenharmony_ci iounmap(fbbase); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ciint restore_vga(struct vgastate *state) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci if (state->vidstate == NULL) 4618c2ecf20Sopenharmony_ci return 1; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_MODE) 4648c2ecf20Sopenharmony_ci restore_vga_mode(state); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_FONTS) { 4678c2ecf20Sopenharmony_ci void __iomem *fbbase = ioremap(state->membase, state->memsize); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (!fbbase) { 4708c2ecf20Sopenharmony_ci vga_cleanup(state); 4718c2ecf20Sopenharmony_ci return 1; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci restore_vga_text(state, fbbase); 4748c2ecf20Sopenharmony_ci iounmap(fbbase); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (state->flags & VGA_SAVE_CMAP) 4788c2ecf20Sopenharmony_ci restore_vga_cmap(state); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci vga_cleanup(state); 4818c2ecf20Sopenharmony_ci return 0; 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(save_vga); 4858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(restore_vga); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ciMODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); 4888c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("VGA State Save/Restore"); 4898c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4908c2ecf20Sopenharmony_ci 491