⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 video.c

📁 linux 内核源代码
💻 C
字号:
/* -*- linux-c -*- ------------------------------------------------------- * * *   Copyright (C) 1991, 1992 Linus Torvalds *   Copyright 2007 rPath, Inc. - All Rights Reserved * *   This file is part of the Linux kernel, and is made available under *   the terms of the GNU General Public License version 2. * * ----------------------------------------------------------------------- *//* * arch/i386/boot/video.c * * Select video mode */#include "boot.h"#include "video.h"#include "vesa.h"/* * Mode list variables */static struct card_info cards[];    /* List of cards to probe for *//* * Common variables */int adapter;			/* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */u16 video_segment;int force_x, force_y;	/* Don't query the BIOS for cols/rows */int do_restore = 0;	/* Screen contents changed during mode flip */int graphic_mode;	/* Graphic mode with linear frame buffer */static void store_cursor_position(void){	u16 curpos;	u16 ax, bx;	ax = 0x0300;	bx = 0;	asm(INT10	    : "=d" (curpos), "+a" (ax), "+b" (bx)	    : : "ecx", "esi", "edi");	boot_params.screen_info.orig_x = curpos;	boot_params.screen_info.orig_y = curpos >> 8;}static void store_video_mode(void){	u16 ax, page;	/* N.B.: the saving of the video page here is a bit silly,	   since we pretty much assume page 0 everywhere. */	ax = 0x0f00;	asm(INT10	    : "+a" (ax), "=b" (page)	    : : "ecx", "edx", "esi", "edi");	/* Not all BIOSes are clean with respect to the top bit */	boot_params.screen_info.orig_video_mode = ax & 0x7f;	boot_params.screen_info.orig_video_page = page >> 8;}/* * 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;}/* Probe the video drivers and have them generate their mode lists. */static void probe_cards(int unsafe){	struct card_info *card;	static u8 probed[2];	if (probed[unsafe])		return;	probed[unsafe] = 1;	for (card = video_cards; card < video_cards_end; card++) {		if (card->unsafe == unsafe) {			if (card->probe)				card->nmodes = card->probe();			else				card->nmodes = 0;		}	}}/* Test if a mode is defined */int mode_defined(u16 mode){	struct card_info *card;	struct mode_info *mi;	int i;	for (card = video_cards; card < video_cards_end; card++) {		mi = card->modes;		for (i = 0; i < card->nmodes; i++, mi++) {			if (mi->mode == mode)				return 1;		}	}	return 0;}/* Set mode (without recalc) */static int raw_set_mode(u16 mode, u16 *real_mode){	int nmode, i;	struct card_info *card;	struct mode_info *mi;	/* Drop the recalc bit if set */	mode &= ~VIDEO_RECALC;	/* Scan for mode based on fixed ID, position, or resolution */	nmode = 0;	for (card = video_cards; card < video_cards_end; card++) {		mi = card->modes;		for (i = 0; i < card->nmodes; i++, mi++) {			int visible = mi->x || mi->y;			if ((mode == nmode && visible) ||			    mode == mi->mode ||			    mode == (mi->y << 8)+mi->x) {				*real_mode = mi->mode;				return card->set_mode(mi);			}			if (visible)				nmode++;		}	}	/* Nothing found?  Is it an "exceptional" (unprobed) mode? */	for (card = video_cards; card < video_cards_end; card++) {		if (mode >= card->xmode_first &&		    mode < card->xmode_first+card->xmode_n) {			struct mode_info mix;			*real_mode = mix.mode = mode;			mix.x = mix.y = 0;			return card->set_mode(&mix);		}	}	/* Otherwise, failure... */	return -1;}/* * Recalculate the vertical video cutoff (hack!) */static void vga_recalc_vertical(void){	unsigned int font_size, rows;	u16 crtc;	u8 pt, ov;	set_fs(0);	font_size = rdfs8(0x485); /* BIOS: font size (pixels) */	rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */	rows *= font_size;	/* Visible scan lines */	rows--;			/* ... minus one */	crtc = vga_crtc();	pt = in_idx(crtc, 0x11);	pt &= ~0x80;		/* Unlock CR0-7 */	out_idx(pt, crtc, 0x11);	out_idx((u8)rows, crtc, 0x12); /* Lower height register */	ov = in_idx(crtc, 0x07); /* Overflow register */	ov &= 0xbd;	ov |= (rows >> (8-1)) & 0x02;	ov |= (rows >> (9-6)) & 0x40;	out_idx(ov, crtc, 0x07);}/* Set mode (with recalc if specified) */static int set_mode(u16 mode){	int rv;	u16 real_mode;	/* Very special mode numbers... */	if (mode == VIDEO_CURRENT_MODE)		return 0;	/* Nothing to do... */	else if (mode == NORMAL_VGA)		mode = VIDEO_80x25;	else if (mode == EXTENDED_VGA)		mode = VIDEO_8POINT;	rv = raw_set_mode(mode, &real_mode);	if (rv)		return rv;	if (mode & VIDEO_RECALC)		vga_recalc_vertical();	/* Save the canonical mode number for the kernel, not	   an alias, size specification or menu position */	boot_params.hdr.vid_mode = real_mode;	return 0;}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;	puts("Mode:    COLSxROWS:\n");	ch = '0';	for (card = video_cards; card < video_cards_end; card++) {		mi = card->modes;		for (i = 0; i < card->nmodes; i++, mi++) {			int visible = mi->x && mi->y;			u16 mode_id = mi->mode ? mi->mode :				(mi->y << 8)+mi->x;			if (!visible)				continue; /* Hidden mode */			printf("%c  %04X  %3dx%-3d  %s\n",			       ch, mode_id, mi->x, mi->y, card->card_name);			if (ch == '9')				ch = 'a';			else if (ch == 'z' || ch == ' ')				ch = ' '; /* Out of keys... */			else				ch++;		}	}}#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 <ENTER> to see video modes available, "	     "<SPACE> 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);	}}#ifdef CONFIG_VIDEO_RETAIN/* Save screen content to the heap */struct saved_screen {	int x, y;	int curx, cury;	u16 *data;} saved;static void save_screen(void){	/* Should be called after store_mode_params() */	saved.x = boot_params.screen_info.orig_video_cols;	saved.y = boot_params.screen_info.orig_video_lines;	saved.curx = boot_params.screen_info.orig_x;	saved.cury = boot_params.screen_info.orig_y;	if (!heap_free(saved.x*saved.y*sizeof(u16)+512))		return;		/* Not enough heap to save the screen */	saved.data = GET_HEAP(u16, saved.x*saved.y);	set_fs(video_segment);	copy_from_fs(saved.data, 0, saved.x*saved.y*sizeof(u16));}static void restore_screen(void){	/* Should be called after store_mode_params() */	int xs = boot_params.screen_info.orig_video_cols;	int ys = boot_params.screen_info.orig_video_lines;	int y;	addr_t dst = 0;	u16 *src = saved.data;	u16 ax, bx, dx;	if (graphic_mode)		return;		/* Can't restore onto a graphic mode */	if (!src)		return;		/* No saved screen contents */	/* Restore screen contents */	set_fs(video_segment);	for (y = 0; y < ys; y++) {		int npad;		if (y < saved.y) {			int copy = (xs < saved.x) ? xs : saved.x;			copy_to_fs(dst, src, copy*sizeof(u16));			dst += copy*sizeof(u16);			src += saved.x;			npad = (xs < saved.x) ? 0 : xs-saved.x;		} else {			npad = xs;		}		/* Writes "npad" blank characters to		   video_segment:dst and advances dst */		asm volatile("pushw %%es ; "			     "movw %2,%%es ; "			     "shrw %%cx ; "			     "jnc 1f ; "			     "stosw \n\t"			     "1: rep;stosl ; "			     "popw %%es"			     : "+D" (dst), "+c" (npad)			     : "bdS" (video_segment),			       "a" (0x07200720));	}	/* Restore cursor position */	ax = 0x0200;		/* Set cursor position */	bx = 0;			/* Page number (<< 8) */	dx = (saved.cury << 8)+saved.curx;	asm volatile(INT10		     : "+a" (ax), "+b" (bx), "+d" (dx)		     : : "ecx", "esi", "edi");}#else#define save_screen()		((void)0)#define restore_screen()	((void)0)#endifvoid set_video(void){	u16 mode = boot_params.hdr.vid_mode;	RESET_HEAP();	store_mode_params();	save_screen();	probe_cards(0);	for (;;) {		if (mode == ASK_VGA)			mode = mode_menu();		if (!set_mode(mode))			break;		printf("Undefined video mode number: %x\n", mode);		mode = ASK_VGA;	}	vesa_store_edid();	store_mode_params();	if (do_restore)		restore_screen();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -