0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <uapi/asm/boot.h>
0015
0016 #include "boot.h"
0017 #include "video.h"
0018 #include "vesa.h"
0019
0020 static u16 video_segment;
0021
0022 static void store_cursor_position(void)
0023 {
0024 struct biosregs ireg, oreg;
0025
0026 initregs(&ireg);
0027 ireg.ah = 0x03;
0028 intcall(0x10, &ireg, &oreg);
0029
0030 boot_params.screen_info.orig_x = oreg.dl;
0031 boot_params.screen_info.orig_y = oreg.dh;
0032
0033 if (oreg.ch & 0x20)
0034 boot_params.screen_info.flags |= VIDEO_FLAGS_NOCURSOR;
0035
0036 if ((oreg.ch & 0x1f) > (oreg.cl & 0x1f))
0037 boot_params.screen_info.flags |= VIDEO_FLAGS_NOCURSOR;
0038 }
0039
0040 static void store_video_mode(void)
0041 {
0042 struct biosregs ireg, oreg;
0043
0044
0045
0046 initregs(&ireg);
0047 ireg.ah = 0x0f;
0048 intcall(0x10, &ireg, &oreg);
0049
0050
0051 boot_params.screen_info.orig_video_mode = oreg.al & 0x7f;
0052 boot_params.screen_info.orig_video_page = oreg.bh;
0053 }
0054
0055
0056
0057
0058
0059
0060
0061 static void store_mode_params(void)
0062 {
0063 u16 font_size;
0064 int x, y;
0065
0066
0067
0068 if (graphic_mode)
0069 return;
0070
0071 store_cursor_position();
0072 store_video_mode();
0073
0074 if (boot_params.screen_info.orig_video_mode == 0x07) {
0075
0076 video_segment = 0xb000;
0077 } else {
0078
0079 video_segment = 0xb800;
0080 }
0081
0082 set_fs(0);
0083 font_size = rdfs16(0x485);
0084 boot_params.screen_info.orig_video_points = font_size;
0085
0086 x = rdfs16(0x44a);
0087 y = (adapter == ADAPTER_CGA) ? 25 : rdfs8(0x484)+1;
0088
0089 if (force_x)
0090 x = force_x;
0091 if (force_y)
0092 y = force_y;
0093
0094 boot_params.screen_info.orig_video_cols = x;
0095 boot_params.screen_info.orig_video_lines = y;
0096 }
0097
0098 static unsigned int get_entry(void)
0099 {
0100 char entry_buf[4];
0101 int i, len = 0;
0102 int key;
0103 unsigned int v;
0104
0105 do {
0106 key = getchar();
0107
0108 if (key == '\b') {
0109 if (len > 0) {
0110 puts("\b \b");
0111 len--;
0112 }
0113 } else if ((key >= '0' && key <= '9') ||
0114 (key >= 'A' && key <= 'Z') ||
0115 (key >= 'a' && key <= 'z')) {
0116 if (len < sizeof(entry_buf)) {
0117 entry_buf[len++] = key;
0118 putchar(key);
0119 }
0120 }
0121 } while (key != '\r');
0122 putchar('\n');
0123
0124 if (len == 0)
0125 return VIDEO_CURRENT_MODE;
0126
0127 v = 0;
0128 for (i = 0; i < len; i++) {
0129 v <<= 4;
0130 key = entry_buf[i] | 0x20;
0131 v += (key > '9') ? key-'a'+10 : key-'0';
0132 }
0133
0134 return v;
0135 }
0136
0137 static void display_menu(void)
0138 {
0139 struct card_info *card;
0140 struct mode_info *mi;
0141 char ch;
0142 int i;
0143 int nmodes;
0144 int modes_per_line;
0145 int col;
0146
0147 nmodes = 0;
0148 for (card = video_cards; card < video_cards_end; card++)
0149 nmodes += card->nmodes;
0150
0151 modes_per_line = 1;
0152 if (nmodes >= 20)
0153 modes_per_line = 3;
0154
0155 for (col = 0; col < modes_per_line; col++)
0156 puts("Mode: Resolution: Type: ");
0157 putchar('\n');
0158
0159 col = 0;
0160 ch = '0';
0161 for (card = video_cards; card < video_cards_end; card++) {
0162 mi = card->modes;
0163 for (i = 0; i < card->nmodes; i++, mi++) {
0164 char resbuf[32];
0165 int visible = mi->x && mi->y;
0166 u16 mode_id = mi->mode ? mi->mode :
0167 (mi->y << 8)+mi->x;
0168
0169 if (!visible)
0170 continue;
0171
0172 if (mi->depth)
0173 sprintf(resbuf, "%dx%d", mi->y, mi->depth);
0174 else
0175 sprintf(resbuf, "%d", mi->y);
0176
0177 printf("%c %03X %4dx%-7s %-6s",
0178 ch, mode_id, mi->x, resbuf, card->card_name);
0179 col++;
0180 if (col >= modes_per_line) {
0181 putchar('\n');
0182 col = 0;
0183 }
0184
0185 if (ch == '9')
0186 ch = 'a';
0187 else if (ch == 'z' || ch == ' ')
0188 ch = ' ';
0189 else
0190 ch++;
0191 }
0192 }
0193 if (col)
0194 putchar('\n');
0195 }
0196
0197 #define H(x) ((x)-'a'+10)
0198 #define SCAN ((H('s')<<12)+(H('c')<<8)+(H('a')<<4)+H('n'))
0199
0200 static unsigned int mode_menu(void)
0201 {
0202 int key;
0203 unsigned int sel;
0204
0205 puts("Press <ENTER> to see video modes available, "
0206 "<SPACE> to continue, or wait 30 sec\n");
0207
0208 kbd_flush();
0209 while (1) {
0210 key = getchar_timeout();
0211 if (key == ' ' || key == 0)
0212 return VIDEO_CURRENT_MODE;
0213 if (key == '\r')
0214 break;
0215 putchar('\a');
0216 }
0217
0218
0219 for (;;) {
0220 display_menu();
0221
0222 puts("Enter a video mode or \"scan\" to scan for "
0223 "additional modes: ");
0224 sel = get_entry();
0225 if (sel != SCAN)
0226 return sel;
0227
0228 probe_cards(1);
0229 }
0230 }
0231
0232
0233 static struct saved_screen {
0234 int x, y;
0235 int curx, cury;
0236 u16 *data;
0237 } saved;
0238
0239 static void save_screen(void)
0240 {
0241
0242 saved.x = boot_params.screen_info.orig_video_cols;
0243 saved.y = boot_params.screen_info.orig_video_lines;
0244 saved.curx = boot_params.screen_info.orig_x;
0245 saved.cury = boot_params.screen_info.orig_y;
0246
0247 if (!heap_free(saved.x*saved.y*sizeof(u16)+512))
0248 return;
0249
0250 saved.data = GET_HEAP(u16, saved.x*saved.y);
0251
0252 set_fs(video_segment);
0253 copy_from_fs(saved.data, 0, saved.x*saved.y*sizeof(u16));
0254 }
0255
0256 static void restore_screen(void)
0257 {
0258
0259 int xs = boot_params.screen_info.orig_video_cols;
0260 int ys = boot_params.screen_info.orig_video_lines;
0261 int y;
0262 addr_t dst = 0;
0263 u16 *src = saved.data;
0264 struct biosregs ireg;
0265
0266 if (graphic_mode)
0267 return;
0268
0269 if (!src)
0270 return;
0271
0272
0273
0274 set_fs(video_segment);
0275 for (y = 0; y < ys; y++) {
0276 int npad;
0277
0278 if (y < saved.y) {
0279 int copy = (xs < saved.x) ? xs : saved.x;
0280 copy_to_fs(dst, src, copy*sizeof(u16));
0281 dst += copy*sizeof(u16);
0282 src += saved.x;
0283 npad = (xs < saved.x) ? 0 : xs-saved.x;
0284 } else {
0285 npad = xs;
0286 }
0287
0288
0289
0290 asm volatile("pushw %%es ; "
0291 "movw %2,%%es ; "
0292 "shrw %%cx ; "
0293 "jnc 1f ; "
0294 "stosw \n\t"
0295 "1: rep;stosl ; "
0296 "popw %%es"
0297 : "+D" (dst), "+c" (npad)
0298 : "bdS" (video_segment),
0299 "a" (0x07200720));
0300 }
0301
0302
0303 if (saved.curx >= xs)
0304 saved.curx = xs-1;
0305 if (saved.cury >= ys)
0306 saved.cury = ys-1;
0307
0308 initregs(&ireg);
0309 ireg.ah = 0x02;
0310 ireg.dh = saved.cury;
0311 ireg.dl = saved.curx;
0312 intcall(0x10, &ireg, NULL);
0313
0314 store_cursor_position();
0315 }
0316
0317 void set_video(void)
0318 {
0319 u16 mode = boot_params.hdr.vid_mode;
0320
0321 RESET_HEAP();
0322
0323 store_mode_params();
0324 save_screen();
0325 probe_cards(0);
0326
0327 for (;;) {
0328 if (mode == ASK_VGA)
0329 mode = mode_menu();
0330
0331 if (!set_mode(mode))
0332 break;
0333
0334 printf("Undefined video mode number: %x\n", mode);
0335 mode = ASK_VGA;
0336 }
0337 boot_params.hdr.vid_mode = mode;
0338 vesa_store_edid();
0339 store_mode_params();
0340
0341 if (do_restore)
0342 restore_screen();
0343 }