| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 1 | /* -*- linux-c -*- ------------------------------------------------------- * | 
 | 2 |  * | 
 | 3 |  *   Copyright (C) 1991, 1992 Linus Torvalds | 
 | 4 |  *   Copyright 2007 rPath, Inc. - All Rights Reserved | 
| H. Peter Anvin | cf06de7 | 2009-04-01 18:20:11 -0700 | [diff] [blame] | 5 |  *   Copyright 2009 Intel Corporation; author H. Peter Anvin | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 6 |  * | 
 | 7 |  *   This file is part of the Linux kernel, and is made available under | 
 | 8 |  *   the terms of the GNU General Public License version 2. | 
 | 9 |  * | 
 | 10 |  * ----------------------------------------------------------------------- */ | 
 | 11 |  | 
 | 12 | /* | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 13 |  * Standard video BIOS modes | 
 | 14 |  * | 
 | 15 |  * We have two options for this; silent and scanned. | 
 | 16 |  */ | 
 | 17 |  | 
 | 18 | #include "boot.h" | 
 | 19 | #include "video.h" | 
 | 20 |  | 
| roel kluin | 8bcad30 | 2008-10-21 19:49:09 -0400 | [diff] [blame] | 21 | static __videocard video_bios; | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 22 |  | 
 | 23 | /* Set a conventional BIOS mode */ | 
 | 24 | static int set_bios_mode(u8 mode); | 
 | 25 |  | 
 | 26 | static int bios_set_mode(struct mode_info *mi) | 
 | 27 | { | 
 | 28 | 	return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS); | 
 | 29 | } | 
 | 30 |  | 
 | 31 | static int set_bios_mode(u8 mode) | 
 | 32 | { | 
| H. Peter Anvin | cf06de7 | 2009-04-01 18:20:11 -0700 | [diff] [blame] | 33 | 	struct biosregs ireg, oreg; | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 34 | 	u8 new_mode; | 
 | 35 |  | 
| H. Peter Anvin | cf06de7 | 2009-04-01 18:20:11 -0700 | [diff] [blame] | 36 | 	initregs(&ireg); | 
 | 37 | 	ireg.al = mode;		/* AH=0x00 Set Video Mode */ | 
 | 38 | 	intcall(0x10, &ireg, NULL); | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 39 |  | 
| H. Peter Anvin | cf06de7 | 2009-04-01 18:20:11 -0700 | [diff] [blame] | 40 | 	ireg.ah = 0x0f;		/* Get Current Video Mode */ | 
 | 41 | 	intcall(0x10, &ireg, &oreg); | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 42 |  | 
| Randy Dunlap | 8218d02 | 2007-07-26 10:10:35 -0700 | [diff] [blame] | 43 | 	do_restore = 1;		/* Assume video contents were lost */ | 
| H. Peter Anvin | cf06de7 | 2009-04-01 18:20:11 -0700 | [diff] [blame] | 44 |  | 
 | 45 | 	/* Not all BIOSes are clean with the top bit */ | 
| Akinobu Mita | febe04d | 2009-07-01 11:13:07 +0900 | [diff] [blame] | 46 | 	new_mode = oreg.al & 0x7f; | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 47 |  | 
 | 48 | 	if (new_mode == mode) | 
 | 49 | 		return 0;	/* Mode change OK */ | 
 | 50 |  | 
| Pavel Machek | e44b7b7 | 2008-04-10 23:28:10 +0200 | [diff] [blame] | 51 | #ifndef _WAKEUP | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 52 | 	if (new_mode != boot_params.screen_info.orig_video_mode) { | 
 | 53 | 		/* Mode setting failed, but we didn't end up where we | 
 | 54 | 		   started.  That's bad.  Try to revert to the original | 
 | 55 | 		   video mode. */ | 
| H. Peter Anvin | cf06de7 | 2009-04-01 18:20:11 -0700 | [diff] [blame] | 56 | 		ireg.ax = boot_params.screen_info.orig_video_mode; | 
 | 57 | 		intcall(0x10, &ireg, NULL); | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 58 | 	} | 
| Pavel Machek | e44b7b7 | 2008-04-10 23:28:10 +0200 | [diff] [blame] | 59 | #endif | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 60 | 	return -1; | 
 | 61 | } | 
 | 62 |  | 
 | 63 | static int bios_probe(void) | 
 | 64 | { | 
 | 65 | 	u8 mode; | 
| Pavel Machek | e44b7b7 | 2008-04-10 23:28:10 +0200 | [diff] [blame] | 66 | #ifdef _WAKEUP | 
 | 67 | 	u8 saved_mode = 0x03; | 
 | 68 | #else | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 69 | 	u8 saved_mode = boot_params.screen_info.orig_video_mode; | 
| Pavel Machek | e44b7b7 | 2008-04-10 23:28:10 +0200 | [diff] [blame] | 70 | #endif | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 71 | 	u16 crtc; | 
 | 72 | 	struct mode_info *mi; | 
 | 73 | 	int nmodes = 0; | 
 | 74 |  | 
 | 75 | 	if (adapter != ADAPTER_EGA && adapter != ADAPTER_VGA) | 
 | 76 | 		return 0; | 
 | 77 |  | 
 | 78 | 	set_fs(0); | 
 | 79 | 	crtc = vga_crtc(); | 
 | 80 |  | 
 | 81 | 	video_bios.modes = GET_HEAP(struct mode_info, 0); | 
 | 82 |  | 
 | 83 | 	for (mode = 0x14; mode <= 0x7f; mode++) { | 
| H. Peter Anvin | e6e1ace | 2007-10-25 16:09:38 -0700 | [diff] [blame] | 84 | 		if (!heap_free(sizeof(struct mode_info))) | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 85 | 			break; | 
 | 86 |  | 
 | 87 | 		if (mode_defined(VIDEO_FIRST_BIOS+mode)) | 
 | 88 | 			continue; | 
 | 89 |  | 
 | 90 | 		if (set_bios_mode(mode)) | 
 | 91 | 			continue; | 
 | 92 |  | 
 | 93 | 		/* Try to verify that it's a text mode. */ | 
 | 94 |  | 
 | 95 | 		/* Attribute Controller: make graphics controller disabled */ | 
 | 96 | 		if (in_idx(0x3c0, 0x10) & 0x01) | 
 | 97 | 			continue; | 
 | 98 |  | 
 | 99 | 		/* Graphics Controller: verify Alpha addressing enabled */ | 
 | 100 | 		if (in_idx(0x3ce, 0x06) & 0x01) | 
 | 101 | 			continue; | 
 | 102 |  | 
 | 103 | 		/* CRTC cursor location low should be zero(?) */ | 
 | 104 | 		if (in_idx(crtc, 0x0f)) | 
 | 105 | 			continue; | 
 | 106 |  | 
 | 107 | 		mi = GET_HEAP(struct mode_info, 1); | 
 | 108 | 		mi->mode = VIDEO_FIRST_BIOS+mode; | 
| H. Peter Anvin | 1cac500 | 2008-01-30 13:33:02 +0100 | [diff] [blame] | 109 | 		mi->depth = 0;	/* text */ | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 110 | 		mi->x = rdfs16(0x44a); | 
 | 111 | 		mi->y = rdfs8(0x484)+1; | 
 | 112 | 		nmodes++; | 
 | 113 | 	} | 
 | 114 |  | 
 | 115 | 	set_bios_mode(saved_mode); | 
 | 116 |  | 
 | 117 | 	return nmodes; | 
 | 118 | } | 
 | 119 |  | 
| roel kluin | 8bcad30 | 2008-10-21 19:49:09 -0400 | [diff] [blame] | 120 | static __videocard video_bios = | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 121 | { | 
| H. Peter Anvin | 1cac500 | 2008-01-30 13:33:02 +0100 | [diff] [blame] | 122 | 	.card_name	= "BIOS", | 
| H. Peter Anvin | 5e8ddcbe | 2007-07-11 12:18:52 -0700 | [diff] [blame] | 123 | 	.probe		= bios_probe, | 
 | 124 | 	.set_mode	= bios_set_mode, | 
 | 125 | 	.unsafe		= 1, | 
 | 126 | 	.xmode_first	= VIDEO_FIRST_BIOS, | 
 | 127 | 	.xmode_n	= 0x80, | 
 | 128 | }; |