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 */ 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 */ 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 */ 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 178 void adjust_screen(void) 179 { 180 if (firmware->adjust_screen) 181 firmware->adjust_screen(); 182 } 183 184 void pm_adjust_screen(com32sys_t *regs __unused) 185 { 186 adjust_screen(); 187 } 188 189 void pm_userfont(com32sys_t *regs) 190 { 191 regs->es = SEG(fontbuf); 192 regs->ebx.w[0] = OFFS(fontbuf); 193 } 194