1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
4 * Copyright 2013 Intel Corporation
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 *
16 * font.c
17 *
18 * VGA font handling code
19 *
20 */
21
22 #include <syslinux/firmware.h>
23 #include <syslinux/video.h>
24 #include <sys/io.h>
25 #include <stdio.h>
26 #include <fs.h>
27
28 #include "bios.h"
29 #include "graphics.h"
30 #include "core.h"
31
32 __export uint8_t UserFont = 0; /* Using a user-specified font */
33
34 __export __lowmem char fontbuf[8192];
35
36 uint16_t GXPixCols = 1; /* Graphics mode pixel columns */
37 uint16_t GXPixRows = 1; /* Graphics mode pixel rows */
38
39 /*
40 * loadfont: Load a .psf font file and install it onto the VGA console
41 * (if we're not on a VGA screen then ignore.)
42 */
loadfont(const char * filename)43 __export void loadfont(const char *filename)
44 {
45 struct psfheader {
46 uint16_t magic;
47 uint8_t mode;
48 uint8_t height;
49 } hdr;
50 FILE *f;
51
52 f = fopen(filename, "r");
53 if (!f)
54 return;
55
56 /* Read header */
57 if (_fread(&hdr, sizeof hdr, f) != sizeof hdr)
58 goto fail;
59
60 /* Magic number */
61 if (hdr.magic != 0x0436)
62 goto fail;
63
64 /* File mode: font modes 0-5 supported */
65 if (hdr.mode > 5)
66 goto fail;
67
68 /* VGA minimum/maximum */
69 if (hdr.height < 2 || hdr.height > 32)
70 goto fail;
71
72 /* Load the actual font into the font buffer. */
73 memset(fontbuf, 0, 256*32);
74 if (_fread(fontbuf, 256*hdr.height, f) != 256*hdr.height)
75 goto fail;
76
77 /* Loaded OK */
78 VGAFontSize = hdr.height;
79 UserFont = 1; /* Set font flag */
80 use_font();
81
82 fail:
83 fclose(f);
84 }
85
86 /*
87 * use_font:
88 * This routine activates whatever font happens to be in the
89 * vgafontbuf, and updates the bios_adjust_screen data.
90 * Must be called with CS = DS
91 */
use_font(void)92 void use_font(void)
93 {
94 com32sys_t ireg, oreg;
95 uint8_t bytes = VGAFontSize;
96
97 /* Nonstandard mode? */
98 if (UsingVGA & ~0x3)
99 syslinux_force_text_mode();
100
101 memset(&ireg, 0, sizeof(ireg));
102
103 ireg.es = SEG(fontbuf);
104 ireg.ebp.w[0] = OFFS(fontbuf); /* ES:BP -> font */
105
106 /* Are we using a user-specified font? */
107 if (UserFont & 0x1) {
108 /* Are we in graphics mode? */
109 if (UsingVGA & 0x1) {
110 uint8_t rows;
111
112 rows = GXPixRows / bytes;
113 VidRows = rows - 1;
114
115 /* Set user character table */
116 ireg.eax.w[0] = 0x1121;
117 ireg.ebx.b[0] = 0;
118 ireg.ecx.b[0] = bytes; /* bytes/character */
119 ireg.edx.b[0] = rows;
120
121 __intcall(0x10, &ireg, &oreg);
122
123 /* 8 pixels/character */
124 VidCols = ((GXPixCols >> 3) - 1);
125
126 /* No need to call bios_adjust_screen */
127 return;
128 } else {
129 ireg.eax.w[0] = 0x1110; /* Load into VGA RAM */
130 ireg.ebx.b[0] = 0;
131 ireg.ebx.b[1] = bytes; /* bytes/character */
132 ireg.ecx.w[0] = 256;
133 ireg.edx.w[0] = 0;
134
135 __intcall(0x10, &ireg, &oreg);
136
137 memset(&ireg, 0, sizeof(ireg));
138 ireg.ebx.b[0] = 0;
139 ireg.eax.w[0] = 0x1103; /* Select page 0 */
140 __intcall(0x10, &ireg, NULL);
141 }
142
143 }
144
145 bios_adjust_screen();
146 }
147
148 /*
149 * bios_adjust_screen: Set the internal variables associated with the screen size.
150 * This is a subroutine in case we're loading a custom font.
151 */
bios_adjust_screen(void)152 void bios_adjust_screen(void)
153 {
154 com32sys_t ireg, oreg;
155 volatile uint8_t *vidrows = (volatile uint8_t *)BIOS_vidrows;
156 uint8_t rows, cols;
157
158 memset(&ireg, 0, sizeof(ireg));
159
160 rows = *vidrows;
161 if (!rows) {
162 /*
163 * No vidrows in BIOS, assume 25.
164 * (Remember: vidrows == rows-1)
165 */
166 rows = 24;
167 }
168
169 VidRows = rows;
170
171 ireg.eax.b[1] = 0x0f; /* Read video state */
172 __intcall(0x10, &ireg, &oreg);
173 cols = oreg.eax.b[1];
174
175 VidCols = --cols; /* Store count-1 (same as rows) */
176 }
177
adjust_screen(void)178 void adjust_screen(void)
179 {
180 if (firmware->adjust_screen)
181 firmware->adjust_screen();
182 }
183
pm_adjust_screen(com32sys_t * regs __unused)184 void pm_adjust_screen(com32sys_t *regs __unused)
185 {
186 adjust_screen();
187 }
188
pm_userfont(com32sys_t * regs)189 void pm_userfont(com32sys_t *regs)
190 {
191 regs->es = SEG(fontbuf);
192 regs->ebx.w[0] = OFFS(fontbuf);
193 }
194