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