Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | /* -*- linux-c -*- ------------------------------------------------------- * * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007-2008 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-mode.c * * Set the video mode. This is separated out into a different * file in order to be shared with the ACPI wakeup code. */ #include "boot.h" #include "video.h" #include "vesa.h" #include <uapi/asm/boot.h> /* * Common variables */ int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */ int force_x, force_y; /* Don't query the BIOS for cols/rows */ int do_restore; /* Screen contents changed during mode flip */ int graphic_mode; /* Graphic mode with linear frame buffer */ /* Probe the video drivers and have them generate their mode lists. */ 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) */ 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 */ #ifndef _WAKEUP boot_params.hdr.vid_mode = real_mode; #endif return 0; } |