1e44b7b75SPavel Machek /* -*- linux-c -*- ------------------------------------------------------- * 2e44b7b75SPavel Machek * 3e44b7b75SPavel Machek * Copyright (C) 1991, 1992 Linus Torvalds 4e44b7b75SPavel Machek * Copyright 2007-2008 rPath, Inc. - All Rights Reserved 5e44b7b75SPavel Machek * 6e44b7b75SPavel Machek * This file is part of the Linux kernel, and is made available under 7e44b7b75SPavel Machek * the terms of the GNU General Public License version 2. 8e44b7b75SPavel Machek * 9e44b7b75SPavel Machek * ----------------------------------------------------------------------- */ 10e44b7b75SPavel Machek 11e44b7b75SPavel Machek /* 12e44b7b75SPavel Machek * arch/i386/boot/video-mode.c 13e44b7b75SPavel Machek * 14e44b7b75SPavel Machek * Set the video mode. This is separated out into a different 15e44b7b75SPavel Machek * file in order to be shared with the ACPI wakeup code. 16e44b7b75SPavel Machek */ 17e44b7b75SPavel Machek 18e44b7b75SPavel Machek #include "boot.h" 19e44b7b75SPavel Machek #include "video.h" 20e44b7b75SPavel Machek #include "vesa.h" 21e44b7b75SPavel Machek 22*70f15287SKirill A. Shutemov #include <uapi/asm/boot.h> 23*70f15287SKirill A. Shutemov 24e44b7b75SPavel Machek /* 25e44b7b75SPavel Machek * Common variables 26e44b7b75SPavel Machek */ 27e44b7b75SPavel Machek int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */ 28e44b7b75SPavel Machek int force_x, force_y; /* Don't query the BIOS for cols/rows */ 29e44b7b75SPavel Machek int do_restore; /* Screen contents changed during mode flip */ 30e44b7b75SPavel Machek int graphic_mode; /* Graphic mode with linear frame buffer */ 31e44b7b75SPavel Machek 32e44b7b75SPavel Machek /* Probe the video drivers and have them generate their mode lists. */ 33e44b7b75SPavel Machek void probe_cards(int unsafe) 34e44b7b75SPavel Machek { 35e44b7b75SPavel Machek struct card_info *card; 36e44b7b75SPavel Machek static u8 probed[2]; 37e44b7b75SPavel Machek 38e44b7b75SPavel Machek if (probed[unsafe]) 39e44b7b75SPavel Machek return; 40e44b7b75SPavel Machek 41e44b7b75SPavel Machek probed[unsafe] = 1; 42e44b7b75SPavel Machek 43e44b7b75SPavel Machek for (card = video_cards; card < video_cards_end; card++) { 44e44b7b75SPavel Machek if (card->unsafe == unsafe) { 45e44b7b75SPavel Machek if (card->probe) 46e44b7b75SPavel Machek card->nmodes = card->probe(); 47e44b7b75SPavel Machek else 48e44b7b75SPavel Machek card->nmodes = 0; 49e44b7b75SPavel Machek } 50e44b7b75SPavel Machek } 51e44b7b75SPavel Machek } 52e44b7b75SPavel Machek 53e44b7b75SPavel Machek /* Test if a mode is defined */ 54e44b7b75SPavel Machek int mode_defined(u16 mode) 55e44b7b75SPavel Machek { 56e44b7b75SPavel Machek struct card_info *card; 57e44b7b75SPavel Machek struct mode_info *mi; 58e44b7b75SPavel Machek int i; 59e44b7b75SPavel Machek 60e44b7b75SPavel Machek for (card = video_cards; card < video_cards_end; card++) { 61e44b7b75SPavel Machek mi = card->modes; 62e44b7b75SPavel Machek for (i = 0; i < card->nmodes; i++, mi++) { 63e44b7b75SPavel Machek if (mi->mode == mode) 64e44b7b75SPavel Machek return 1; 65e44b7b75SPavel Machek } 66e44b7b75SPavel Machek } 67e44b7b75SPavel Machek 68e44b7b75SPavel Machek return 0; 69e44b7b75SPavel Machek } 70e44b7b75SPavel Machek 71e44b7b75SPavel Machek /* Set mode (without recalc) */ 72e44b7b75SPavel Machek static int raw_set_mode(u16 mode, u16 *real_mode) 73e44b7b75SPavel Machek { 74e44b7b75SPavel Machek int nmode, i; 75e44b7b75SPavel Machek struct card_info *card; 76e44b7b75SPavel Machek struct mode_info *mi; 77e44b7b75SPavel Machek 78e44b7b75SPavel Machek /* Drop the recalc bit if set */ 79e44b7b75SPavel Machek mode &= ~VIDEO_RECALC; 80e44b7b75SPavel Machek 81e44b7b75SPavel Machek /* Scan for mode based on fixed ID, position, or resolution */ 82e44b7b75SPavel Machek nmode = 0; 83e44b7b75SPavel Machek for (card = video_cards; card < video_cards_end; card++) { 84e44b7b75SPavel Machek mi = card->modes; 85e44b7b75SPavel Machek for (i = 0; i < card->nmodes; i++, mi++) { 86e44b7b75SPavel Machek int visible = mi->x || mi->y; 87e44b7b75SPavel Machek 88e44b7b75SPavel Machek if ((mode == nmode && visible) || 89e44b7b75SPavel Machek mode == mi->mode || 90e44b7b75SPavel Machek mode == (mi->y << 8)+mi->x) { 91e44b7b75SPavel Machek *real_mode = mi->mode; 92e44b7b75SPavel Machek return card->set_mode(mi); 93e44b7b75SPavel Machek } 94e44b7b75SPavel Machek 95e44b7b75SPavel Machek if (visible) 96e44b7b75SPavel Machek nmode++; 97e44b7b75SPavel Machek } 98e44b7b75SPavel Machek } 99e44b7b75SPavel Machek 100e44b7b75SPavel Machek /* Nothing found? Is it an "exceptional" (unprobed) mode? */ 101e44b7b75SPavel Machek for (card = video_cards; card < video_cards_end; card++) { 102e44b7b75SPavel Machek if (mode >= card->xmode_first && 103e44b7b75SPavel Machek mode < card->xmode_first+card->xmode_n) { 104e44b7b75SPavel Machek struct mode_info mix; 105e44b7b75SPavel Machek *real_mode = mix.mode = mode; 106e44b7b75SPavel Machek mix.x = mix.y = 0; 107e44b7b75SPavel Machek return card->set_mode(&mix); 108e44b7b75SPavel Machek } 109e44b7b75SPavel Machek } 110e44b7b75SPavel Machek 111e44b7b75SPavel Machek /* Otherwise, failure... */ 112e44b7b75SPavel Machek return -1; 113e44b7b75SPavel Machek } 114e44b7b75SPavel Machek 115e44b7b75SPavel Machek /* 116e44b7b75SPavel Machek * Recalculate the vertical video cutoff (hack!) 117e44b7b75SPavel Machek */ 118e44b7b75SPavel Machek static void vga_recalc_vertical(void) 119e44b7b75SPavel Machek { 120e44b7b75SPavel Machek unsigned int font_size, rows; 121e44b7b75SPavel Machek u16 crtc; 122e44b7b75SPavel Machek u8 pt, ov; 123e44b7b75SPavel Machek 124e44b7b75SPavel Machek set_fs(0); 125e44b7b75SPavel Machek font_size = rdfs8(0x485); /* BIOS: font size (pixels) */ 126e44b7b75SPavel Machek rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */ 127e44b7b75SPavel Machek 128e44b7b75SPavel Machek rows *= font_size; /* Visible scan lines */ 129e44b7b75SPavel Machek rows--; /* ... minus one */ 130e44b7b75SPavel Machek 131e44b7b75SPavel Machek crtc = vga_crtc(); 132e44b7b75SPavel Machek 133e44b7b75SPavel Machek pt = in_idx(crtc, 0x11); 134e44b7b75SPavel Machek pt &= ~0x80; /* Unlock CR0-7 */ 135e44b7b75SPavel Machek out_idx(pt, crtc, 0x11); 136e44b7b75SPavel Machek 137e44b7b75SPavel Machek out_idx((u8)rows, crtc, 0x12); /* Lower height register */ 138e44b7b75SPavel Machek 139e44b7b75SPavel Machek ov = in_idx(crtc, 0x07); /* Overflow register */ 140e44b7b75SPavel Machek ov &= 0xbd; 141e44b7b75SPavel Machek ov |= (rows >> (8-1)) & 0x02; 142e44b7b75SPavel Machek ov |= (rows >> (9-6)) & 0x40; 143e44b7b75SPavel Machek out_idx(ov, crtc, 0x07); 144e44b7b75SPavel Machek } 145e44b7b75SPavel Machek 146e44b7b75SPavel Machek /* Set mode (with recalc if specified) */ 147e44b7b75SPavel Machek int set_mode(u16 mode) 148e44b7b75SPavel Machek { 149e44b7b75SPavel Machek int rv; 150e44b7b75SPavel Machek u16 real_mode; 151e44b7b75SPavel Machek 152e44b7b75SPavel Machek /* Very special mode numbers... */ 153e44b7b75SPavel Machek if (mode == VIDEO_CURRENT_MODE) 154e44b7b75SPavel Machek return 0; /* Nothing to do... */ 155e44b7b75SPavel Machek else if (mode == NORMAL_VGA) 156e44b7b75SPavel Machek mode = VIDEO_80x25; 157e44b7b75SPavel Machek else if (mode == EXTENDED_VGA) 158e44b7b75SPavel Machek mode = VIDEO_8POINT; 159e44b7b75SPavel Machek 160e44b7b75SPavel Machek rv = raw_set_mode(mode, &real_mode); 161e44b7b75SPavel Machek if (rv) 162e44b7b75SPavel Machek return rv; 163e44b7b75SPavel Machek 164e44b7b75SPavel Machek if (mode & VIDEO_RECALC) 165e44b7b75SPavel Machek vga_recalc_vertical(); 166e44b7b75SPavel Machek 167e44b7b75SPavel Machek /* Save the canonical mode number for the kernel, not 168e44b7b75SPavel Machek an alias, size specification or menu position */ 169e44b7b75SPavel Machek #ifndef _WAKEUP 170e44b7b75SPavel Machek boot_params.hdr.vid_mode = real_mode; 171e44b7b75SPavel Machek #endif 172e44b7b75SPavel Machek return 0; 173e44b7b75SPavel Machek } 174