/* -*- linux-c -*- ------------------------------------------------------- * * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. * * ----------------------------------------------------------------------- */ /* * Select video mode */ #include "boot.h" #include "video.h" #include "vesa.h" static u16 video_segment; static void store_cursor_position(void) { struct biosregs ireg, oreg; initregs(&ireg); ireg.ah = 0x03; intcall(0x10, &ireg, &oreg); boot_params.screen_info.orig_x = oreg.dl; boot_params.screen_info.orig_y = oreg.dh; if (oreg.ch & 0x20) boot_params.screen_info.flags |= VIDEO_FLAGS_NOCURSOR; if ((oreg.ch & 0x1f) > (oreg.cl & 0x1f)) boot_params.screen_info.flags |= VIDEO_FLAGS_NOCURSOR; } static void store_video_mode(void) { struct biosregs ireg, oreg; /* N.B.: the saving of the video page here is a bit silly, since we pretty much assume page 0 everywhere. */ initregs(&ireg); ireg.ah = 0x0f; intcall(0x10, &ireg, &oreg); /* Not all BIOSes are clean with respect to the top bit */ boot_params.screen_info.orig_video_mode = oreg.al & 0x7f; boot_params.screen_info.orig_video_page = oreg.bh; } /* * Store the video mode parameters for later usage by the kernel. * This is done by asking the BIOS except for the rows/columns * parameters in the default 80x25 mode -- these are set directly, * because some very obscure BIOSes supply insane values. */ static void store_mode_params(void) { u16 font_size; int x, y; /* For graphics mode, it is up to the mode-setting driver (currently only video-vesa.c) to store the parameters */ if (graphic_mode) return; store_cursor_position(); store_video_mode(); if (boot_params.screen_info.orig_video_mode == 0x07) { /* MDA, HGC, or VGA in monochrome mode */ video_segment = 0xb000; } else { /* CGA, EGA, VGA and so forth */ video_segment = 0xb800; } set_fs(0); font_size = rdfs16(0x485); /* Font size, BIOS area */ boot_params.screen_info.orig_video_points = font_size; x = rdfs16(0x44a); y = (adapter == ADAPTER_CGA) ? 25 : rdfs8(0x484)+1; if (force_x) x = force_x; if (force_y) y = force_y; boot_params.screen_info.orig_video_cols = x; boot_params.screen_info.orig_video_lines = y; } static unsigned int get_entry(void) { char entry_buf[4]; int i, len = 0; int key; unsigned int v; do { key = getchar(); if (key == '\b') { if (len > 0) { puts("\b \b"); len--; } } else if ((key >= '0' && key <= '9') || (key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z')) { if (len < sizeof entry_buf) { entry_buf[len++] = key; putchar(key); } } } while (key != '\r'); putchar('\n'); if (len == 0) return VIDEO_CURRENT_MODE; /* Default */ v = 0; for (i = 0; i < len; i++) { v <<= 4; key = entry_buf[i] | 0x20; v += (key > '9') ? key-'a'+10 : key-'0'; } return v; } static void display_menu(void) { struct card_info *card; struct mode_info *mi; char ch; int i; int nmodes; int modes_per_line; int col; nmodes = 0; for (card = video_cards; card < video_cards_end; card++) nmodes += card->nmodes; modes_per_line = 1; if (nmodes >= 20) modes_per_line = 3; for (col = 0; col < modes_per_line; col++) puts("Mode: Resolution: Type: "); putchar('\n'); col = 0; ch = '0'; for (card = video_cards; card < video_cards_end; card++) { mi = card->modes; for (i = 0; i < card->nmodes; i++, mi++) { char resbuf[32]; int visible = mi->x && mi->y; u16 mode_id = mi->mode ? mi->mode : (mi->y << 8)+mi->x; if (!visible) continue; /* Hidden mode */ if (mi->depth) sprintf(resbuf, "%dx%d", mi->y, mi->depth); else sprintf(resbuf, "%d", mi->y); printf("%c %03X %4dx%-7s %-6s", ch, mode_id, mi->x, resbuf, card->card_name); col++; if (col >= modes_per_line) { putchar('\n'); col = 0; } if (ch == '9') ch = 'a'; else if (ch == 'z' || ch == ' ') ch = ' '; /* Out of keys... */ else ch++; } } if (col) putchar('\n'); } #define H(x) ((x)-'a'+10) #define SCAN ((H('s')<<12)+(H('c')<<8)+(H('a')<<4)+H('n')) static unsigned int mode_menu(void) { int key; unsigned int sel; puts("Press to see video modes available, " " to continue, or wait 30 sec\n"); kbd_flush(); while (1) { key = getchar_timeout(); if (key == ' ' || key == 0) return VIDEO_CURRENT_MODE; /* Default */ if (key == '\r') break; putchar('\a'); /* Beep! */ } for (;;) { display_menu(); puts("Enter a video mode or \"scan\" to scan for " "additional modes: "); sel = get_entry(); if (sel != SCAN) return sel; probe_cards(1); } } /* Save screen content to the heap */ static struct saved_screen {