vbe.c revision 1.4 1 /* $NetBSD: vbe.c,v 1.4 2009/09/14 11:56:27 jmcneill 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 int vbeverbose = 1;
42
43 static struct _vbestate {
44 int available;
45 int modenum;
46 } vbestate;
47
48 static void
49 vbe_dump(struct vbeinfoblock *vbe)
50 {
51 int mem = (int)vbe->TotalMemory * 64;
52
53 if (!vbeverbose)
54 return;
55
56 printf(">> VESA VBE Version %d.%d %d k\n",
57 vbe->VbeVersion >> 8, vbe->VbeVersion & 0xff, mem);
58 }
59
60 static int
61 vbe_mode_is_supported(struct modeinfoblock *mi)
62 {
63 if ((mi->ModeAttributes & 0x01) == 0)
64 return 0; /* mode not supported by hardware */
65 if ((mi->ModeAttributes & 0x08) == 0)
66 return 0; /* linear fb not available */
67 if ((mi->ModeAttributes & 0x10) == 0)
68 return 0; /* text mode */
69 if (mi->NumberOfPlanes != 1)
70 return 0; /* planar mode not supported */
71 if (mi->MemoryModel != 0x04 /* Packed pixel */ &&
72 mi->MemoryModel != 0x06 /* Direct Color */)
73 return 0; /* unsupported pixel format */
74 return 1;
75 }
76
77 void
78 vbe_init(void)
79 {
80 struct vbeinfoblock vbe;
81
82 memset(&vbe, 0, sizeof(vbe));
83 memcpy(vbe.VbeSignature, "VBE2", 4);
84 if (biosvbe_info(&vbe) != 0x004f)
85 return;
86 if (memcmp(vbe.VbeSignature, "VESA", 4) != 0) {
87 printf("VESA VBE: bad signature %c%c%c%c\n",
88 vbe.VbeSignature[0], vbe.VbeSignature[1],
89 vbe.VbeSignature[2], vbe.VbeSignature[3]);
90 return;
91 }
92
93 vbe_dump(&vbe);
94 vbestate.available = 1;
95 vbestate.modenum = 0;
96 }
97
98 int
99 vbe_available(void)
100 {
101 return vbestate.available;
102 }
103
104 int
105 vbe_set_palette(const uint8_t *cmap, int slot)
106 {
107 struct paletteentry pe;
108 int ret;
109
110 if (!vbestate.available) {
111 printf("VESA BIOS extensions not available\n");
112 return 1;
113 }
114
115 pe.Blue = cmap[2] >> 2;
116 pe.Green = cmap[1] >> 2;
117 pe.Red = cmap[0] >> 2;
118 pe.Alignment = 0;
119
120 ret = biosvbe_palette_data(0x0600, slot, &pe);
121
122 return ret == 0x004f ? 0 : 1;
123 }
124
125 int
126 vbe_set_mode(int modenum)
127 {
128 struct modeinfoblock mi;
129 struct btinfo_framebuffer fb;
130 int ret, i;
131
132 if (!vbestate.available) {
133 printf("VESA BIOS extensions not available\n");
134 return 1;
135 }
136
137 ret = biosvbe_get_mode_info(modenum, &mi);
138 if (ret != 0x004f) {
139 printf("VESA VBE mode 0x%x is invalid.\n", modenum);
140 return 1;
141 }
142
143 if (!vbe_mode_is_supported(&mi)) {
144 printf("VESA VBE mode 0x%x is not supported.\n", modenum);
145 return 1;
146 }
147
148 ret = biosvbe_set_mode(modenum);
149 if (ret != 0x004f) {
150 printf("VESA VBE mode 0x%x could not be set.\n", modenum);
151 return 1;
152 }
153
154 /* Setup palette for packed pixel mode */
155 if (mi.MemoryModel == 0x04)
156 for (i = 0; i < 256; i++)
157 vbe_set_palette(&rasops_cmap[i * 3], i);
158
159 fb.physaddr = (uint64_t)mi.PhysBasePtr & 0xffffffff;
160 fb.width = mi.XResolution;
161 fb.height = mi.YResolution;
162 fb.stride = mi.BytesPerScanLine;
163 fb.depth = mi.BitsPerPixel;
164 fb.flags = 0;
165 fb.rnum = mi.RedMaskSize;
166 fb.rpos = mi.RedFieldPosition;
167 fb.gnum = mi.GreenMaskSize;
168 fb.gpos = mi.GreenFieldPosition;
169 fb.bnum = mi.BlueMaskSize;
170 fb.bpos = mi.BlueFieldPosition;
171 fb.vbemode = modenum;
172
173 framebuffer_configure(&fb);
174
175 return 0;
176 }
177
178 int
179 vbe_commit(void)
180 {
181 int ret = 1;
182
183 if (vbestate.modenum > 0) {
184 ret = vbe_set_mode(vbestate.modenum);
185 if (ret) {
186 printf("WARNING: failed to set VESA VBE mode 0x%x\n",
187 vbestate.modenum);
188 delay(5000000);
189 }
190 }
191 return ret;
192 }
193
194 static void *
195 vbe_farptr(uint32_t farptr)
196 {
197 return VBEPHYPTR((((farptr & 0xffff0000) >> 12) + (farptr & 0xffff)));
198 }
199
200 static int
201 vbe_parse_mode_str(char *str, int *x, int *y, int *bpp)
202 {
203 char *p;
204
205 p = str;
206 *x = strtoul(p, NULL, 0);
207 if (*x == 0)
208 return 0;
209 p = strchr(p, 'x');
210 if (!p)
211 return 0;
212 ++p;
213 *y = strtoul(p, NULL, 0);
214 if (*y == 0)
215 return 0;
216 p = strchr(p, 'x');
217 if (!p)
218 *bpp = 8;
219 else {
220 ++p;
221 *bpp = strtoul(p, NULL, 0);
222 if (*bpp == 0)
223 return 0;
224 }
225
226 return 1;
227 }
228
229 static int
230 vbe_find_mode(char *str)
231 {
232 struct vbeinfoblock vbe;
233 struct modeinfoblock mi;
234 uint32_t farptr;
235 uint16_t mode;
236 int x, y, bpp;
237 int safety = 0;
238
239 if (!vbe_parse_mode_str(str, &x, &y, &bpp))
240 return 0;
241
242 memset(&vbe, 0, sizeof(vbe));
243 memcpy(vbe.VbeSignature, "VBE2", 4);
244 if (biosvbe_info(&vbe) != 0x004f)
245 return 0;
246 if (memcmp(vbe.VbeSignature, "VESA", 4) != 0)
247 return 0;
248 farptr = vbe.VideoModePtr;
249 if (farptr == 0)
250 return 0;
251
252 while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
253 safety++;
254 farptr += 2;
255 if (safety == 100)
256 return 0;
257 if (biosvbe_get_mode_info(mode, &mi) != 0x004f)
258 continue;
259 /* we only care about linear modes here */
260 if (vbe_mode_is_supported(&mi) == 0)
261 continue;
262 safety = 0;
263 if (mi.XResolution == x &&
264 mi.YResolution == y &&
265 mi.BitsPerPixel == bpp)
266 return mode;
267 }
268
269 printf("VESA VBE BIOS does not support %s\n", str);
270 return 0;
271 }
272
273 static void
274 vbe_dump_mode(int modenum, struct modeinfoblock *mi)
275 {
276 printf("0x%x=%dx%dx%d", modenum,
277 mi->XResolution, mi->YResolution, mi->BitsPerPixel);
278 }
279
280 void
281 vbe_modelist(void)
282 {
283 struct vbeinfoblock vbe;
284 struct modeinfoblock mi;
285 uint32_t farptr;
286 uint16_t mode;
287 int nmodes = 0, safety = 0;
288
289 if (!vbestate.available) {
290 printf("VESA BIOS extensions not available\n");
291 return;
292 }
293
294 printf("Modes: ");
295 memset(&vbe, 0, sizeof(vbe));
296 memcpy(vbe.VbeSignature, "VBE2", 4);
297 if (biosvbe_info(&vbe) != 0x004f)
298 goto done;
299 if (memcmp(vbe.VbeSignature, "VESA", 4) != 0)
300 goto done;
301 farptr = vbe.VideoModePtr;
302 if (farptr == 0)
303 goto done;
304
305 while ((mode = *(uint16_t *)vbe_farptr(farptr)) != 0xffff) {
306 safety++;
307 farptr += 2;
308 if (safety == 100) {
309 printf("[garbage] ");
310 break;
311 }
312 if (biosvbe_get_mode_info(mode, &mi) != 0x004f)
313 continue;
314 /* we only care about linear modes here */
315 if (vbe_mode_is_supported(&mi) == 0)
316 continue;
317 safety = 0;
318 if (nmodes % 4 == 0)
319 printf("\n");
320 else
321 printf(" ");
322 vbe_dump_mode(mode, &mi);
323 nmodes++;
324 }
325
326 done:
327 if (nmodes == 0)
328 printf("none found");
329 printf("\n");
330 }
331
332 void
333 command_vesa(char *cmd)
334 {
335 char arg[20];
336 int modenum;
337
338 if (!vbe_available()) {
339 printf("VESA VBE not available\n");
340 return;
341 }
342
343 strlcpy(arg, cmd, sizeof(arg));
344
345 if (strcmp(arg, "list") == 0) {
346 vbe_modelist();
347 return;
348 }
349
350 if (strcmp(arg, "disabled") == 0 || strcmp(arg, "off") == 0) {
351 vbestate.modenum = 0;
352 return;
353 }
354
355 if (strcmp(arg, "enabled") == 0 || strcmp(arg, "on") == 0)
356 modenum = VBE_DEFAULT_MODE;
357 else if (strncmp(arg, "0x", 2) == 0)
358 modenum = strtoul(arg, NULL, 0);
359 else if (strchr(arg, 'x') != NULL) {
360 modenum = vbe_find_mode(arg);
361 if (modenum == 0) {
362 printf("mode %s not supported by firmware\n", arg);
363 return;
364 }
365 } else
366 modenum = 0;
367
368 if (modenum >= 0x100) {
369 vbestate.modenum = modenum;
370 return;
371 }
372
373 printf("invalid flag, must be 'enabled', 'disabled', "
374 "a display mode, or a valid VESA VBE mode number.\n");
375 }
376