1 /* $NetBSD: vbe.c,v 1.6 2010/06/25 15:35:08 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Jared D. McNeill <jmcneill@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