| 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 | }; |