Default background; skip background if VESA is uninitialized
[syslinux.git] / com32 / lib / sys / vesa / initvesa.c
blob7394c9d1d63aca130bfb61f4c03aeaf0ccbf7e88
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1999-2006 H. Peter Anvin - All Rights Reserved
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
12 * conditions:
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
26 * ----------------------------------------------------------------------- */
29 * initvesa.c
31 * Query the VESA BIOS and select a 640x480x32 mode with local mapping
32 * support, if one exists.
35 #include <inttypes.h>
36 #include <com32.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <stdio.h>
41 #include <sys/fpu.h>
42 #include "vesa.h"
43 #include "video.h"
45 struct vesa_info __vesa_info;
47 struct vesa_char *__vesacon_text_display;
49 int __vesacon_font_height, __vesacon_text_rows;
50 enum vesa_pixel_format __vesacon_pixel_format = PXF_NONE;
51 unsigned int __vesacon_bytes_per_pixel;
52 uint8_t __vesacon_graphics_font[FONT_MAX_CHARS][FONT_MAX_HEIGHT];
54 uint32_t __vesacon_background[VIDEO_Y_SIZE][VIDEO_X_SIZE];
56 ssize_t __serial_write(void *fp, const void *buf, size_t count);
58 static inline void debug(const char *str, ...)
60 #if 0
61 va_list va;
62 char buf[65536];
63 size_t len;
65 va_start(va, str);
66 len = vsnprintf(buf, sizeof buf, str, va);
67 va_end(va);
69 if (len >= sizeof buf)
70 len = sizeof buf - 1;
72 __serial_write(NULL, buf, len);
73 #else
74 (void)str;
75 #endif
78 static void unpack_font(uint8_t *dst, uint8_t *src, int height)
80 int i;
82 for (i = 0; i < FONT_MAX_CHARS; i++) {
83 memcpy(dst, src, height);
84 memset(dst+height, 0, FONT_MAX_HEIGHT-height);
86 dst += FONT_MAX_HEIGHT;
87 src += height;
91 static int vesacon_set_mode(void)
93 com32sys_t rm;
94 uint8_t *rom_font;
95 uint16_t mode, bestmode, *mode_ptr;
96 struct vesa_general_info *gi;
97 struct vesa_mode_info *mi;
98 enum vesa_pixel_format pxf, bestpxf;
100 /* Allocate space in the bounce buffer for these structures */
101 gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
102 mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
104 debug("Hello, World!\r\n");
106 memset(&rm, 0, sizeof rm);
108 gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
109 rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
110 rm.edi.w[0] = OFFS(gi);
111 rm.es = SEG(gi);
112 __intcall(0x10, &rm, &rm);
114 if ( rm.eax.w[0] != 0x004F )
115 return 1; /* Function call failed */
116 if ( gi->signature != VESA_MAGIC )
117 return 2; /* No magic */
118 if ( gi->version < 0x0200 ) {
119 return 3; /* VESA 2.0 not supported */
122 /* Copy general info */
123 memcpy(&__vesa_info.gi, gi, sizeof *gi);
125 /* Search for a 640x480 32-bit linear frame buffer mode */
126 mode_ptr = GET_PTR(gi->video_mode_ptr);
127 bestmode = 0;
128 bestpxf = PXF_NONE;
130 while ((mode = *mode_ptr++) != 0xFFFF) {
131 debug("Found mode: 0x%04x\r\n", mode);
133 rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */
134 rm.ecx.w[0] = mode;
135 rm.edi.w[0] = OFFS(mi);
136 rm.es = SEG(mi);
137 __intcall(0x10, &rm, &rm);
139 /* Must be a supported mode */
140 if ( rm.eax.w[0] != 0x004f )
141 continue;
143 debug("mode_attr 0x%04x, h_res = %4d, v_res = %4d, bpp = %2d, layout = %d (%d,%d,%d)\r\n",
144 mi->mode_attr, mi->h_res, mi->v_res, mi->bpp, mi->memory_layout,
145 mi->rpos, mi->gpos, mi->bpos);
147 /* Must be an LFB color graphics mode supported by the hardware */
148 if ( (mi->mode_attr & 0x0099) != 0x0099 )
149 continue;
151 /* Must be 640x480, 32 bpp */
152 if ( mi->h_res != VIDEO_X_SIZE || mi->v_res != VIDEO_Y_SIZE )
153 continue;
155 /* Must either be a packed-pixel mode or a direct color mode
156 (depending on VESA version ) */
157 pxf = PXF_NONE; /* Not usable */
159 if (mi->bpp == 32 &&
160 (mi->memory_layout == 4 ||
161 (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
162 mi->bpos == 0)))
163 pxf = PXF_BGRA32;
164 else if (mi->bpp == 24 &&
165 (mi->memory_layout == 4 ||
166 (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
167 mi->bpos == 0)))
168 pxf = PXF_BGR24;
169 else if (mi->bpp == 16 &&
170 (mi->memory_layout == 4 ||
171 (mi->memory_layout == 6 && mi->rpos == 11 && mi->gpos == 5 &&
172 mi->bpos == 0)))
173 pxf = PXF_LE_RGB16_565;
175 if (pxf < bestpxf) {
176 debug("Best mode so far, pxf = %d\n", pxf);
178 /* Best mode so far... */
179 bestmode = mode;
180 bestpxf = pxf;
182 /* Copy mode info */
183 memcpy(&__vesa_info.mi, mi, sizeof *mi);
187 if (bestpxf == PXF_NONE)
188 return 4; /* No mode found */
190 mi = &__vesa_info.mi;
191 mode = bestmode;
192 __vesacon_bytes_per_pixel = mi->bpp >> 3;
194 /* Download the SYSLINUX- or BIOS-provided font */
195 rm.eax.w[0] = 0x0018; /* Query custom font */
196 __intcall(0x22, &rm, &rm);
197 if (!(rm.eflags.l & EFLAGS_CF) && rm.eax.b[0]) {
198 __vesacon_font_height = rm.eax.b[0];
199 rom_font = MK_PTR(rm.es, rm.ebx.w[0]);
200 } else {
201 rm.eax.w[0] = 0x1130; /* Get Font Information */
202 rm.ebx.w[0] = 0x0600; /* Get 8x16 ROM font */
203 __intcall(0x10, &rm, &rm);
204 rom_font = MK_PTR(rm.es, rm.ebp.w[0]);
205 __vesacon_font_height = 16;
207 unpack_font((uint8_t *)__vesacon_graphics_font, rom_font,
208 __vesacon_font_height);
209 __vesacon_text_rows = (VIDEO_Y_SIZE-2*VIDEO_BORDER)/__vesacon_font_height;
210 __vesacon_init_cursor(__vesacon_font_height);
212 /* Now set video mode */
213 rm.eax.w[0] = 0x4F02; /* Set SVGA video mode */
214 rm.ebx.w[0] = mode | 0x4000; /* Clear video RAM, use linear fb */
215 __intcall(0x10, &rm, &rm);
216 if ( rm.eax.w[0] != 0x004F )
217 return 9; /* Failed to set mode */
219 /* Tell syslinux we changed video mode */
220 rm.eax.w[0] = 0x0017; /* Report video mode change */
221 /* In theory this should be:
223 rm.ebx.w[0] = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
225 However, that would assume all systems that claim to handle text
226 output in VESA modes actually do that... */
227 rm.ebx.w[0] = 0x000f;
228 rm.ecx.w[0] = VIDEO_X_SIZE;
229 rm.edx.w[0] = VIDEO_Y_SIZE;
230 __intcall(0x22, &rm, NULL);
232 __vesacon_pixel_format = bestpxf;
234 return 0;
238 static int init_text_display(void)
240 size_t nchars;
241 struct vesa_char *ptr;
243 nchars = (TEXT_PIXEL_ROWS/__vesacon_font_height+2)*
244 (TEXT_PIXEL_COLS/FONT_WIDTH+2);
246 __vesacon_text_display = ptr = malloc(nchars*sizeof(struct vesa_char));
248 if (!ptr)
249 return -1;
251 /* I really which C had a memset() for larger-than-bytes objects... */
252 asm volatile("cld; rep; stosl"
253 : "+D" (ptr), "+c" (nchars)
254 : "a" (' '+(0 << 8)+(SHADOW_NORMAL << 16))
255 : "memory");
257 return 0;
260 int __vesacon_init(void)
262 int rv;
264 /* We need the FPU for graphics, at least libpng et al will need it... */
265 if (x86_init_fpu())
266 return 10;
268 rv = vesacon_set_mode();
269 if (rv)
270 return rv;
272 init_text_display();
274 debug("Mode set, now drawing at %#p\n", __vesa_info.mi.lfb_ptr);
276 __vesacon_init_background();
278 debug("Ready!\r\n");
279 return 0;