source: bootcd/isolinux/syslinux-6.03/core/graphics.c @ dd1be7c

Last change on this file since dd1be7c was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/*
2 * -----------------------------------------------------------------------
3 *
4 *   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
5 *
6 *   This program is free software; you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 *   Boston MA 02111-1307, USA; either version 2 of the License, or
10 *   (at your option) any later version; incorporated herein by reference.
11 *
12 * -----------------------------------------------------------------------
13 *
14 * -----------------------------------------------------------------------
15 *  VGA splash screen code
16 * -----------------------------------------------------------------------
17 */
18
19#include <stddef.h>
20#include "core.h"
21#include <sys/io.h>
22#include <hw/vga.h>
23#include "fs.h"
24
25#include "bios.h"
26#include "graphics.h"
27#include <syslinux/video.h>
28
29__export uint8_t UsingVGA = 0;
30uint16_t VGAPos;                /* Pointer into VGA memory */
31__export uint16_t *VGAFilePtr;  /* Pointer into VGAFileBuf */
32__export uint16_t VGAFontSize = 16;     /* Defaults to 16 byte font */
33
34__export char VGAFileBuf[VGA_FILE_BUF_SIZE];    /* Unmangled VGA image name */
35__export char VGAFileMBuf[FILENAME_MAX];        /* Mangled VGA image name */
36
37static uint8_t VGARowBuffer[640 + 80];  /* Decompression buffer */
38static uint8_t VGAPlaneBuffer[(640/8) * 4]; /* Plane buffers */
39
40extern uint16_t GXPixCols;
41extern uint16_t GXPixRows;
42
43/* Maps colors to consecutive DAC registers */
44static uint8_t linear_color[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8,
45                                  9, 10, 11, 12, 13, 14, 15, 0 };
46
47static FILE *fd;
48
49typedef struct {
50        uint32_t LSSMagic;      /* Magic number */
51        uint16_t GraphXSize;    /* Width of splash screen file */
52        uint16_t GraphYSize;    /* Height of splash screen file */
53        uint8_t GraphColorMap[3*16];
54} lssheader_t;
55
56static lssheader_t LSSHeader;
57
58#define LSSMagic        LSSHeader.LSSMagic
59#define GraphXSize      LSSHeader.GraphXSize
60#define GraphYSize      LSSHeader.GraphYSize
61
62/*
63 * Enable VGA graphics, if possible. Return 0 on success.
64 */
65static int vgasetmode(void)
66{
67        com32sys_t ireg, oreg;
68
69        if (UsingVGA)
70                return 0;               /* Nothing to do... */
71
72        memset(&ireg, 0, sizeof(ireg));
73        memset(&oreg, 0, sizeof(oreg));
74
75        if (UsingVGA & 0x4) {
76                /*
77                 * We're in VESA mode, which means VGA; use VESA call
78                 * to revert the mode, and then call the conventional
79                 * mode-setting for good measure...
80                 */
81                ireg.eax.w[0] = 0x4F02;
82                ireg.ebx.w[0] = 0x0012;
83                __intcall(0x10, &ireg, &oreg);
84        } else {
85                /* Get video card and monitor */
86                ireg.eax.w[0] = 0x1A00;
87                __intcall(0x10, &ireg, &oreg);
88                oreg.ebx.b[0] -= 7; /* BL=07h and BL=08h OK */
89
90                if (oreg.ebx.b[0] > 1)
91                        return -1;
92        }
93
94        /*
95         * Set mode.
96         */
97        memset(&ireg, 0, sizeof(ireg));
98        ireg.eax.w[0] = 0x0012; /* Set mode = 640x480 VGA 16 colors */
99        __intcall(0x10, &ireg, &oreg);
100
101        memset(&ireg, 0, sizeof(ireg));
102        ireg.edx.w[0] = (uint32_t)linear_color;
103        ireg.eax.w[0] = 0x1002; /* Write color registers */
104        __intcall(0x10, &ireg, &oreg);
105
106        UsingVGA = 1;
107
108        /* Set GXPixCols and GXPixRows */
109        GXPixCols = 640;
110        GXPixRows = 480;
111
112        use_font();
113        ScrollAttribute = 0;
114
115        return 0;
116}
117
118static inline char getnybble(void)
119{
120        char data = getc(fd);
121
122        if (data & 0x10) {
123                data &= 0x0F;
124                return data;
125        }
126
127        data = getc(fd);
128        return (data & 0x0F);
129}
130
131/*
132 * rledecode:
133 *      Decode a pixel row in RLE16 format.
134 *
135 * 'in': input (RLE16 encoded) buffer
136 * 'out': output (decoded) buffer
137 * 'count': pixel count
138 */
139static void rledecode(uint8_t *out, size_t count)
140{
141        uint8_t prev_pixel = 0;
142        size_t size = count;
143        uint8_t data;
144        int i;
145
146again:
147        for (i = 0; i < size; i++) {
148
149                data = getnybble();
150                if (data == prev_pixel)
151                        break;
152
153                *out++ = data;
154                prev_pixel = data;
155        }
156
157        size -= i;
158        if (!size)
159                return;
160
161        /* Start of run sequence */
162        data = getnybble();
163        if (data == 0) {
164                /* long run */
165                uint8_t hi;
166
167                data = getnybble();
168                hi = getnybble();
169                hi <<= 4;
170                data |= hi;
171                data += 16;
172        }
173
174        /* dorun */
175        for (i = 0; i < data; i++)
176                *out++ = prev_pixel;
177
178        size -= i;
179        if (size)
180                goto again;
181}
182
183/*
184 * packedpixel2vga:
185 *      Convert packed-pixel to VGA bitplanes
186 *
187 * 'in': packed pixel string (640 pixels)
188 * 'out': output (four planes @ 640/8 = 80 bytes)
189 * 'count': pixel count (multiple of 8)
190 */
191static void packedpixel2vga(const uint8_t *in, uint8_t *out)
192{
193        int i, j, k;
194
195        for (i = 0; i < 4; i++) {
196                const uint8_t *ip = in;
197
198                for (j = 0; j < 640/8; j++) {
199                        uint8_t ob = 0;
200
201                        for (k = 0; k < 8; k++) {
202                                uint8_t px = *ip++;
203                                ob = (ob << 1) | ((px >> i) & 1);
204                        }
205
206                        *out++ = ob;
207                }
208        }
209}
210
211/*
212 * outputvga:
213 *      Output four subsequent lines of VGA data
214 *
215 * 'in': four planes @ 640/8=80 bytes
216 * 'out': pointer into VGA memory
217 */
218static void outputvga(const void *in, void *out)
219{
220        int i;
221
222        /* Select the sequencer mask */
223        outb(VGA_SEQ_IX_MAP_MASK, VGA_SEQ_ADDR);
224
225        for (i = 1; i <= 8; i <<= 1) {
226                /* Select the bit plane to write */
227                outb(i, VGA_SEQ_DATA);
228                memcpy(out, in, 640/8);
229                in = (const char *)in + 640/8;
230        }
231}
232
233/*
234 * Display a graphical splash screen.
235 */
236__export void vgadisplayfile(FILE *_fd)
237{
238        char *p;
239        int size;
240
241        fd = _fd;
242
243        /*
244         * This is a cheap and easy way to make sure the screen is
245         * cleared in case we were in graphics mode aready.
246         */
247        syslinux_force_text_mode();
248        vgasetmode();
249
250        size = 4+2*2+16*3;
251        p = (char *)&LSSHeader;
252
253        /* Load the header */
254        while (size--)
255                *p = getc(fd);
256
257        if (*p != EOF) {
258                com32sys_t ireg, oreg;
259                uint16_t rows;
260                int i;
261
262                /* The header WILL be in the first chunk. */
263                if (LSSMagic != 0x1413f33d)
264                        return;
265
266                memset(&ireg, 0, sizeof(ireg));
267
268                /* Color map offset */
269                ireg.edx.w[0] = offsetof(lssheader_t, GraphColorMap);
270
271                ireg.eax.w[0] = 0x1012;        /* Set RGB registers */
272                ireg.ebx.w[0] = 0;             /* First register number */
273                ireg.ecx.w[0] = 16;            /* 16 registers */
274                __intcall(0x10, &ireg, &oreg);
275
276                /* Number of pixel rows */
277                rows = (GraphYSize + VGAFontSize) - 1;
278                rows = rows / VGAFontSize;
279                if (rows >= VidRows)
280                        rows = VidRows - 1;
281
282                memset(&ireg, 0, sizeof(ireg));
283
284                ireg.edx.b[1] = rows;
285                ireg.eax.b[1] = 2;
286                ireg.ebx.w[0] = 0;
287
288                /* Set cursor below image */
289                __intcall(0x10, &ireg, &oreg);
290
291                rows = GraphYSize; /* Number of graphics rows */
292                VGAPos = 0;
293
294                for (i = 0; i < rows; i++) {
295                        /* Pre-clear the row buffer */
296                        memset(VGARowBuffer, 0, 640);
297
298                        /* Decode one row */
299                        rledecode(VGARowBuffer, GraphXSize);
300
301                        packedpixel2vga(VGARowBuffer, VGAPlaneBuffer);
302                        outputvga(VGAPlaneBuffer, MK_PTR(0xA000, VGAPos));
303                        VGAPos += 640/8;
304                }
305        }
306}
307
308/*
309 * Disable VGA graphics.
310 */
311__export void syslinux_force_text_mode(void)
312{
313        com32sys_t ireg, oreg;
314
315        /* Already in text mode? */
316        if (!UsingVGA)
317                return;
318
319        if (UsingVGA & 0x4) {
320                /* VESA return to normal video mode */
321                memset(&ireg, 0, sizeof(ireg));
322
323                ireg.eax.w[0] = 0x4F02; /* Set SuperVGA video mode */
324                ireg.ebx.w[0] = 0x0003;
325                __intcall(0x10, &ireg, &oreg);
326        }
327
328        /* Return to normal video mode */
329        memset(&ireg, 0, sizeof(ireg));
330        ireg.eax.w[0] = 0x0003;
331        __intcall(0x10, &ireg, &oreg);
332
333        UsingVGA = 0;
334
335        ScrollAttribute = 0x7;
336        /* Restore text font/data */
337        use_font();
338}
339
340static void vgacursorcommon(char data)
341{
342        if (UsingVGA) {
343                com32sys_t ireg;
344                memset(&ireg, 0, sizeof(ireg));
345
346                ireg.eax.b[0] = data;
347                ireg.eax.b[1] = 0x09;
348                ireg.ebx.w[0] = 0x0007;
349                ireg.ecx.w[0] = 1;
350                __intcall(0x10, &ireg, NULL);
351        }
352}
353
354void vgahidecursor(void)
355{
356        vgacursorcommon(' ');
357}
358
359void vgashowcursor(void)
360{
361        vgacursorcommon('_');
362}
363
364__export void using_vga(uint8_t vga, uint16_t pix_cols, uint16_t pix_rows)
365{
366    UsingVGA = vga;
367    GXPixCols = pix_cols;
368    GXPixRows = pix_rows;
369
370    if (!(UsingVGA & 0x08))
371        adjust_screen();
372}
373
374void pm_using_vga(com32sys_t *regs)
375{
376    using_vga(regs->eax.b[0], regs->ecx.w[0], regs->edx.w[0]);
377}
Note: See TracBrowser for help on using the repository browser.