vgastate.c 13 KB

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