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