Home | History | Annotate | Line # | Download | only in lib
vbe.c revision 1.5.4.1
      1 /* $NetBSD: vbe.c,v 1.5.4.1 2010/07/03 01:19:20 rmind Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2009 Jared D. McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /*
     30  * VESA BIOS Extensions routines
     31  */
     32 
     33 #include <lib/libsa/stand.h>
     34 #include <lib/libkern/libkern.h>
     35 #include <machine/bootinfo.h>
     36 #include "libi386.h"
     37 #include "vbe.h"
     38 
     39 extern const uint8_t rasops_cmap[];
     40 
     41 static struct _vbestate {
     42 	int		available;
     43 	int		modenum;
     44 } vbestate;
     45 
     46 static int
     47 vbe_mode_is_supported(struct modeinfoblock *mi)
     48 {
     49 	if ((mi->ModeAttributes & 0x01) == 0)
     50 		return 0;	/* mode not supported by hardware */
     51 	if ((mi->ModeAttributes & 0x08) == 0)
     52 		return 0;	/* linear fb not available */
     53 	if ((mi->ModeAttributes & 0x10) == 0)
     54 		return 0;	/* text mode */
     55 	if (mi->NumberOfPlanes != 1)
     56 		return 0;	/* planar mode not supported */
     57 	if (mi->MemoryModel != 0x04 /* Packed pixel */ &&
     58 	    mi->MemoryModel != 0x06 /* Direct Color */)
     59 		return 0;	/* unsupported pixel format */
     60 	return 1;
     61 }
     62 
     63 static bool
     64 vbe_check(void)
     65 {
     66 	if (!vbestate.available) {
     67 		printf("VBE not available\n");
     68 		return false;
     69 	}
     70 	return true;
     71 }
     72 
     73 void
     74 vbe_init(void)
     75 {
     76 	struct vbeinfoblock vbe;
     77 
     78 	memset(&vbe, 0, sizeof(vbe));
     79 	memcpy(vbe.VbeSignature, "VBE2", 4);
     80 	if (biosvbe_info(&vbe) != 0x004f)
     81 		return;
     82 	if (memcmp(vbe.VbeSignature, "VESA", 4) != 0)
     83 		return;
     84 
     85 	vbestate.available = 1;
     86 	vbestate.modenum = 0;
     87 }
     88 
     89 int
     90 vbe_available(void)
     91 {
     92 	return vbestate.available;
     93 }
     94 
     95 int
     96 vbe_set_palette(const uint8_t *cmap, int slot)
     97 {
     98 	struct paletteentry pe;
     99 	int ret;
    100 
    101 	if (!vbe_check())
    102 		return 1;
    103 
    104 	pe.Blue = cmap[2] >> 2;
    105 	pe.Green = cmap[1] >> 2;
    106 	pe.Red = cmap[0] >> 2;
    107 	pe.Alignment = 0;
    108 
    109 	ret = biosvbe_palette_data(0x0600, slot, &pe);
    110 
    111 	return ret == 0x004f ? 0 : 1;
    112 }
    113 
    114 int
    115 vbe_set_mode(int modenum)
    116 {
    117 	struct modeinfoblock mi;
    118 	struct btinfo_framebuffer fb;
    119 	int ret, i;
    120 
    121 	if (!vbe_check())
    122 		return 1;
    123 
    124 	ret = biosvbe_get_mode_info(modenum, &mi);
    125 	if (ret != 0x004f) {
    126 		printf("mode 0x%x invalid\n", modenum);
    127 		return 1;
    128 	}
    129 
    130 	if (!vbe_mode_is_supported(&mi)) {
    131 		printf("mode 0x%x not supported\n", modenum);
    132 		return 1;
    133 	}
    134 
    135 	ret = biosvbe_set_mode(modenum);
    136 	if (ret != 0x004f) {
    137 		printf("mode 0x%x could not be set\n", modenum);
    138 		return 1;
    139 	}
    140 
    141 	/* Setup palette for packed pixel mode */
    142 	if (mi.MemoryModel == 0x04)
    143 		for (i = 0; i < 256; i++)
    144 			vbe_set_palette(&rasops_cmap[i * 3], i);
    145 
    146 	fb.physaddr = (uint64_t)mi.PhysBasePtr & 0xffffffff;
    147 	fb.width = mi.XResolution;
    148 	fb.height = mi.YResolution;
    149 	fb.stride = mi.BytesPerScanLine;
    150 	fb.depth = mi.BitsPerPixel;
    151 	fb.flags = 0;
    152 	fb.rnum = mi.RedMaskSize;
    153 	fb.rpos = mi.RedFieldPosition;
    154 	fb.gnum = mi.GreenMaskSize;
    155 	fb.gpos = mi.GreenFieldPosition;
    156 	fb.bnum = mi.BlueMaskSize;
    157 	fb.bpos = mi.BlueFieldPosition;
    158 	fb.vbemode = modenum;
    159 
    160 	framebuffer_configure(&fb);
    161 
    162 	return 0;
    163 }
    164 
    165 int
    166 vbe_commit(void)
    167 {
    168 	int ret = 1;
    169 
    170 	if (vbestate.modenum > 0) {
    171 		ret = vbe_set_mode(vbestate.modenum);
    172 		if (ret) {
    173 			printf("WARNING: failed to set VBE mode 0x%x\n",
    174 			    vbestate.modenum);
    175 			wait_sec(5);
    176 		}
    177 	}
    178 	return ret;
    179 }
    180 
    181 static void *
    182 vbe_farptr(uint32_t farptr)
    183 {
    184 	return VBEPHYPTR((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff)));
    185 }
    186 
    187 static int
    188 vbe_parse_mode_str(char *str, int *x, int *y, int *bpp)
    189 {
    190 	char *p;
    191 
    192 	p = str;
    193 	*x = strtoul(p, NULL, 0);
    194 	if (*x == 0)
    195 		return 0;
    196 	p = strchr(p, 'x');
    197 	if (!p)
    198 		return 0;
    199 	++p;
    200 	*y = strtoul(p, NULL, 0);
    201 	if (*y == 0)
    202 		return 0;
    203 	p = strchr(p, 'x');
    204 	if (!p)
    205 		*bpp = 8;
    206 	else {
    207 		++p;
    208 		*bpp = strtoul(p, NULL, 0);
    209 		if (*bpp == 0)
    210 			return 0;
    211 	}
    212 
    213 	return 1;
    214 }
    215 
    216 static int
    217 vbe_find_mode(char *str)
    218 {
    219 	struct vbeinfoblock vbe;
    220 	struct modeinfoblock mi;
    221 	uint32_t farptr;
    222 	uint16_t mode;
    223 	int x, y, bpp;
    224 	int safety = 0;
    225 
    226 	if (!vbe_parse_mode_str(str, &x, &y, &bpp))
    227 		return 0;
    228 
    229 	memset(&vbe, 0, sizeof(vbe));
    230 	memcpy(vbe.VbeSignature, "VBE2", 4);
    231 	if (biosvbe_info(&vbe) != 0x004f)
    232 		return 0;
    233 	if (memcmp(vbe.VbeSignature, "VESA", 4) != 0)
    234 		return 0;
    235 	farptr = vbe.VideoModePtr;
    236 	if (farptr == 0)
    237 		return 0;
    238 
    239 	while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
    240 		safety++;
    241 		farptr += 2;
    242 		if (safety == 100)
    243 			return 0;
    244 		if (biosvbe_get_mode_info(mode, &mi) != 0x004f)
    245 			continue;
    246 		/* we only care about linear modes here */
    247 		if (vbe_mode_is_supported(&mi) == 0)
    248 			continue;
    249 		safety = 0;
    250 		if (mi.XResolution == x &&
    251 		    mi.YResolution == y &&
    252 		    mi.BitsPerPixel == bpp)
    253 			return mode;
    254 	}
    255 
    256 	return 0;
    257 }
    258 
    259 static void
    260 vbe_dump_mode(int modenum, struct modeinfoblock *mi)
    261 {
    262 	printf("0x%x=%dx%dx%d", modenum,
    263 	    mi->XResolution, mi->YResolution, mi->BitsPerPixel);
    264 }
    265 
    266 void
    267 vbe_modelist(void)
    268 {
    269 	struct vbeinfoblock vbe;
    270 	struct modeinfoblock mi;
    271 	uint32_t farptr;
    272 	uint16_t mode;
    273 	int nmodes = 0, safety = 0;
    274 
    275 	if (!vbe_check())
    276 		return;
    277 
    278 	printf("Modes: ");
    279 	memset(&vbe, 0, sizeof(vbe));
    280 	memcpy(vbe.VbeSignature, "VBE2", 4);
    281 	if (biosvbe_info(&vbe) != 0x004f)
    282 		goto done;
    283 	if (memcmp(vbe.VbeSignature, "VESA", 4) != 0)
    284 		goto done;
    285 	farptr = vbe.VideoModePtr;
    286 	if (farptr == 0)
    287 		goto done;
    288 
    289 	while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
    290 		safety++;
    291 		farptr += 2;
    292 		if (safety == 100) {
    293 			printf("[?] ");
    294 			break;
    295 		}
    296 		if (biosvbe_get_mode_info(mode, &mi) != 0x004f)
    297 			continue;
    298 		/* we only care about linear modes here */
    299 		if (vbe_mode_is_supported(&mi) == 0)
    300 			continue;
    301 		safety = 0;
    302 		if (nmodes % 4 == 0)
    303 			printf("\n");
    304 		else
    305 			printf("  ");
    306 		vbe_dump_mode(mode, &mi);
    307 		nmodes++;
    308 	}
    309 
    310 done:
    311 	if (nmodes == 0)
    312 		printf("none found");
    313 	printf("\n");
    314 }
    315 
    316 void
    317 command_vesa(char *cmd)
    318 {
    319 	char arg[20];
    320 	int modenum;
    321 
    322 	if (!vbe_check())
    323 		return;
    324 
    325 	strlcpy(arg, cmd, sizeof(arg));
    326 
    327 	if (strcmp(arg, "list") == 0) {
    328 		vbe_modelist();
    329 		return;
    330 	}
    331 
    332 	if (strcmp(arg, "disabled") == 0 || strcmp(arg, "off") == 0) {
    333 		vbestate.modenum = 0;
    334 		return;
    335 	}
    336 
    337 	if (strcmp(arg, "enabled") == 0 || strcmp(arg, "on") == 0)
    338 		modenum = VBE_DEFAULT_MODE;
    339 	else if (strncmp(arg, "0x", 2) == 0)
    340 		modenum = strtoul(arg, NULL, 0);
    341 	else if (strchr(arg, 'x') != NULL) {
    342 		modenum = vbe_find_mode(arg);
    343 		if (modenum == 0) {
    344 			printf("mode %s not supported by firmware\n", arg);
    345 			return;
    346 		}
    347 	} else
    348 		modenum = 0;
    349 
    350 	if (modenum >= 0x100) {
    351 		vbestate.modenum = modenum;
    352 		return;
    353 	}
    354 
    355 	printf("invalid flag, must be 'on', 'off', "
    356 	    "a display mode, or a VBE mode number\n");
    357 }
    358