video-mode.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* -*- linux-c -*- ------------------------------------------------------- *
  3. *
  4. * Copyright (C) 1991, 1992 Linus Torvalds
  5. * Copyright 2007-2008 rPath, Inc. - All Rights Reserved
  6. *
  7. * ----------------------------------------------------------------------- */
  8. /*
  9. * arch/i386/boot/video-mode.c
  10. *
  11. * Set the video mode. This is separated out into a different
  12. * file in order to be shared with the ACPI wakeup code.
  13. */
  14. #include "boot.h"
  15. #include "video.h"
  16. #include "vesa.h"
  17. #include <uapi/asm/boot.h>
  18. /*
  19. * Common variables
  20. */
  21. int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */
  22. int force_x, force_y; /* Don't query the BIOS for cols/rows */
  23. int do_restore; /* Screen contents changed during mode flip */
  24. int graphic_mode; /* Graphic mode with linear frame buffer */
  25. /* Probe the video drivers and have them generate their mode lists. */
  26. void probe_cards(int unsafe)
  27. {
  28. struct card_info *card;
  29. static u8 probed[2];
  30. if (probed[unsafe])
  31. return;
  32. probed[unsafe] = 1;
  33. for (card = video_cards; card < video_cards_end; card++) {
  34. if (card->unsafe == unsafe) {
  35. if (card->probe)
  36. card->nmodes = card->probe();
  37. else
  38. card->nmodes = 0;
  39. }
  40. }
  41. }
  42. /* Test if a mode is defined */
  43. int mode_defined(u16 mode)
  44. {
  45. struct card_info *card;
  46. struct mode_info *mi;
  47. int i;
  48. for (card = video_cards; card < video_cards_end; card++) {
  49. mi = card->modes;
  50. for (i = 0; i < card->nmodes; i++, mi++) {
  51. if (mi->mode == mode)
  52. return 1;
  53. }
  54. }
  55. return 0;
  56. }
  57. /* Set mode (without recalc) */
  58. static int raw_set_mode(u16 mode, u16 *real_mode)
  59. {
  60. int nmode, i;
  61. struct card_info *card;
  62. struct mode_info *mi;
  63. /* Drop the recalc bit if set */
  64. mode &= ~VIDEO_RECALC;
  65. /* Scan for mode based on fixed ID, position, or resolution */
  66. nmode = 0;
  67. for (card = video_cards; card < video_cards_end; card++) {
  68. mi = card->modes;
  69. for (i = 0; i < card->nmodes; i++, mi++) {
  70. int visible = mi->x || mi->y;
  71. if ((mode == nmode && visible) ||
  72. mode == mi->mode ||
  73. mode == (mi->y << 8)+mi->x) {
  74. *real_mode = mi->mode;
  75. return card->set_mode(mi);
  76. }
  77. if (visible)
  78. nmode++;
  79. }
  80. }
  81. /* Nothing found? Is it an "exceptional" (unprobed) mode? */
  82. for (card = video_cards; card < video_cards_end; card++) {
  83. if (mode >= card->xmode_first &&
  84. mode < card->xmode_first+card->xmode_n) {
  85. struct mode_info mix;
  86. *real_mode = mix.mode = mode;
  87. mix.x = mix.y = 0;
  88. return card->set_mode(&mix);
  89. }
  90. }
  91. /* Otherwise, failure... */
  92. return -1;
  93. }
  94. /*
  95. * Recalculate the vertical video cutoff (hack!)
  96. */
  97. static void vga_recalc_vertical(void)
  98. {
  99. unsigned int font_size, rows;
  100. u16 crtc;
  101. u8 pt, ov;
  102. set_fs(0);
  103. font_size = rdfs8(0x485); /* BIOS: font size (pixels) */
  104. rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */
  105. rows *= font_size; /* Visible scan lines */
  106. rows--; /* ... minus one */
  107. crtc = vga_crtc();
  108. pt = in_idx(crtc, 0x11);
  109. pt &= ~0x80; /* Unlock CR0-7 */
  110. out_idx(pt, crtc, 0x11);
  111. out_idx((u8)rows, crtc, 0x12); /* Lower height register */
  112. ov = in_idx(crtc, 0x07); /* Overflow register */
  113. ov &= 0xbd;
  114. ov |= (rows >> (8-1)) & 0x02;
  115. ov |= (rows >> (9-6)) & 0x40;
  116. out_idx(ov, crtc, 0x07);
  117. }
  118. /* Set mode (with recalc if specified) */
  119. int set_mode(u16 mode)
  120. {
  121. int rv;
  122. u16 real_mode;
  123. /* Very special mode numbers... */
  124. if (mode == VIDEO_CURRENT_MODE)
  125. return 0; /* Nothing to do... */
  126. else if (mode == NORMAL_VGA)
  127. mode = VIDEO_80x25;
  128. else if (mode == EXTENDED_VGA)
  129. mode = VIDEO_8POINT;
  130. rv = raw_set_mode(mode, &real_mode);
  131. if (rv)
  132. return rv;
  133. if (mode & VIDEO_RECALC)
  134. vga_recalc_vertical();
  135. /* Save the canonical mode number for the kernel, not
  136. an alias, size specification or menu position */
  137. #ifndef _WAKEUP
  138. boot_params.hdr.vid_mode = real_mode;
  139. #endif
  140. return 0;
  141. }