1 /* 2 * `Soft' font definitions 3 * 4 * Created 1995 by Geert Uytterhoeven 5 * Rewritten 1998 by Martin Mares <mj@ucw.cz> 6 * 7 * 2001 - Documented with DocBook 8 * - Brad Douglas <brad@neruo.com> 9 * 10 * This file is subject to the terms and conditions of the GNU General Public 11 * License. See the file COPYING in the main directory of this archive 12 * for more details. 13 */ 14 15 #include <linux/container_of.h> 16 #include <linux/kd.h> 17 #include <linux/module.h> 18 #include <linux/overflow.h> 19 #include <linux/slab.h> 20 #include <linux/string.h> 21 #include <linux/types.h> 22 23 #if defined(__mc68000__) 24 #include <asm/setup.h> 25 #endif 26 27 #include "font.h" 28 29 #define console_font_pitch(font) font_glyph_pitch((font)->width) 30 31 /* 32 * Helpers for font_data_t 33 */ 34 35 /* Extra word getters */ 36 #define REFCOUNT(fd) (((int *)(fd))[-1]) 37 #define FNTSIZE(fd) (((int *)(fd))[-2]) 38 #define FNTSUM(fd) (((int *)(fd))[-4]) 39 40 static struct font_data *to_font_data_struct(font_data_t *fd) 41 { 42 return container_of(fd, struct font_data, data[0]); 43 } 44 45 static bool font_data_is_internal(font_data_t *fd) 46 { 47 return !REFCOUNT(fd); /* internal fonts have no reference counting */ 48 } 49 50 static void font_data_free(font_data_t *fd) 51 { 52 kfree(to_font_data_struct(fd)); 53 } 54 55 /** 56 * font_data_import - Allocates and initializes font data from user space 57 * @font: A font from user space 58 * @vpitch: The size of a single glyph in @font in bytes 59 * @calc_csum: An optional helper to calculate a chechsum 60 * 61 * Font data from user space must be translated to the kernel's format. The 62 * font's glyph geometry and data is provided in @font. The parameter @vpitch 63 * gives the number of bytes per glyph, including trailing bytes. 64 * 65 * The parameter @calc_csum is optional. Fbcon passes crc32() to calculate the 66 * font data's checksum. 67 * 68 * Returns: 69 * Newly initialized font data on success, or a pointer-encoded errno value otherwise. 70 */ 71 font_data_t *font_data_import(const struct console_font *font, unsigned int vpitch, 72 u32 (*calc_csum)(u32, const void *, size_t)) 73 { 74 unsigned int pitch = console_font_pitch(font); 75 unsigned int h = font->height; 76 unsigned int charcount = font->charcount; 77 const unsigned char *data = font->data; 78 u32 csum = 0; 79 struct font_data *font_data; 80 int size, alloc_size; 81 unsigned int i; 82 font_data_t *fd; 83 84 /* Check for integer overflow in font-size calculation */ 85 if (check_mul_overflow(h, pitch, &size) || 86 check_mul_overflow(size, charcount, &size)) 87 return ERR_PTR(-EINVAL); 88 89 /* Check for overflow in allocation size calculation */ 90 if (check_add_overflow(sizeof(*font_data), size, &alloc_size)) 91 return ERR_PTR(-EINVAL); 92 93 font_data = kmalloc(alloc_size, GFP_USER); 94 if (!font_data) 95 return ERR_PTR(-ENOMEM); 96 memset(font_data->extra, 0, sizeof(font_data->extra)); 97 98 for (i = 0; i < charcount; ++i) 99 memcpy(font_data->data + i * h * pitch, data + i * vpitch * pitch, h * pitch); 100 101 if (calc_csum) 102 csum = calc_csum(0, font_data->data, size); 103 104 fd = font_data->data; 105 REFCOUNT(fd) = 1; /* start with reference acquired */ 106 FNTSIZE(fd) = size; 107 FNTSUM(fd) = csum; 108 109 return fd; 110 } 111 EXPORT_SYMBOL_GPL(font_data_import); 112 113 /** 114 * font_data_get - Acquires a reference on font data 115 * @fd: Font data 116 * 117 * Font data from user space is reference counted. The helper 118 * font_data_get() increases the reference counter by one. Invoke 119 * font_data_put() to release the reference. 120 * 121 * Internal font data is located in read-only memory. In this case 122 * the helper returns success without modifying the counter field. 123 * It is still required to call font_data_put() on internal font data. 124 */ 125 void font_data_get(font_data_t *fd) 126 { 127 if (font_data_is_internal(fd)) 128 return; /* never ref static data */ 129 130 if (WARN_ON(!REFCOUNT(fd))) 131 return; /* should never be 0 */ 132 ++REFCOUNT(fd); 133 } 134 EXPORT_SYMBOL_GPL(font_data_get); 135 136 /** 137 * font_data_put - Release a reference on font data 138 * @fd: Font data 139 * 140 * Font data from user space is reference counted. The helper 141 * font_data_put() decreases the reference counter by one. If this was 142 * the final reference, it frees the allocated memory. 143 * 144 * Internal font data is located in read-only memory. In this case 145 * the helper returns success without modifying the counter field. 146 * 147 * Returns: 148 * True if the font data's memory buffer has been freed, false otherwise. 149 */ 150 bool font_data_put(font_data_t *fd) 151 { 152 unsigned int count; 153 154 if (font_data_is_internal(fd)) 155 return false; /* never unref static data */ 156 157 if (WARN_ON(!REFCOUNT(fd))) 158 return false; /* should never be 0 */ 159 160 count = --REFCOUNT(fd); 161 if (!count) 162 font_data_free(fd); 163 164 return !count; 165 } 166 EXPORT_SYMBOL_GPL(font_data_put); 167 168 /** 169 * font_data_size - Return size of the font data in bytes 170 * @fd: Font data 171 * 172 * Returns: 173 * The number of bytes in the given font data. 174 */ 175 unsigned int font_data_size(font_data_t *fd) 176 { 177 return FNTSIZE(fd); 178 } 179 EXPORT_SYMBOL_GPL(font_data_size); 180 181 /** 182 * font_data_is_equal - Compares font data for equality 183 * @lhs: Left-hand side font data 184 * @rhs: Right-hand-size font data 185 * 186 * Font data is equal if is constain the same sequence of values. The 187 * helper also use the checksum, if both arguments contain it. Font data 188 * coming from different origins, internal or from user space, is never 189 * equal. Allowing this would break reference counting. 190 * 191 * Returns: 192 * True if the given font data is equal, false otherwise. 193 */ 194 bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs) 195 { 196 if (font_data_is_internal(lhs) != font_data_is_internal(rhs)) 197 return false; 198 if (font_data_size(lhs) != font_data_size(rhs)) 199 return false; 200 if (FNTSUM(lhs) && FNTSUM(rhs) && FNTSUM(lhs) != FNTSUM(rhs)) 201 return false; 202 203 return !memcmp(lhs, rhs, FNTSIZE(lhs)); 204 } 205 EXPORT_SYMBOL_GPL(font_data_is_equal); 206 207 /** 208 * font_data_export - Stores font data for user space 209 * @fd: Font data 210 * @font: A font for user space 211 * @vpitch: The size of a single glyph in @font in bytes 212 * 213 * Store the font data given in @fd to the font in @font. Values and 214 * pointers in @font are pre-initialized. This helper mostly checks some 215 * corner cases and translates glyph sizes according to the value given 216 * @vpitch. 217 * 218 * Returns: 219 * 0 on success, or a negative errno code otherwise. 220 */ 221 int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch) 222 { 223 const unsigned char *font_data = font_data_buf(fd); 224 unsigned char *data = font->data; 225 unsigned int pitch = console_font_pitch(font); 226 unsigned int glyphsize, i; 227 228 if (!font->width || !font->height || !font->charcount || !font->data) 229 return 0; 230 231 glyphsize = font->height * pitch; 232 233 if (font->charcount * glyphsize > font_data_size(fd)) 234 return -EINVAL; 235 236 for (i = 0; i < font->charcount; i++) { 237 memcpy(data, font_data, glyphsize); 238 memset(data + glyphsize, 0, pitch * vpitch - glyphsize); 239 data += pitch * vpitch; 240 font_data += glyphsize; 241 } 242 243 return 0; 244 } 245 EXPORT_SYMBOL_GPL(font_data_export); 246 247 /* 248 * Font lookup 249 */ 250 251 static const struct font_desc *fonts[] = { 252 #ifdef CONFIG_FONT_8x8 253 &font_vga_8x8, 254 #endif 255 #ifdef CONFIG_FONT_8x16 256 &font_vga_8x16, 257 #endif 258 #ifdef CONFIG_FONT_6x11 259 &font_vga_6x11, 260 #endif 261 #ifdef CONFIG_FONT_7x14 262 &font_7x14, 263 #endif 264 #ifdef CONFIG_FONT_SUN8x16 265 &font_sun_8x16, 266 #endif 267 #ifdef CONFIG_FONT_SUN12x22 268 &font_sun_12x22, 269 #endif 270 #ifdef CONFIG_FONT_10x18 271 &font_10x18, 272 #endif 273 #ifdef CONFIG_FONT_ACORN_8x8 274 &font_acorn_8x8, 275 #endif 276 #ifdef CONFIG_FONT_PEARL_8x8 277 &font_pearl_8x8, 278 #endif 279 #ifdef CONFIG_FONT_MINI_4x6 280 &font_mini_4x6, 281 #endif 282 #ifdef CONFIG_FONT_6x10 283 &font_6x10, 284 #endif 285 #ifdef CONFIG_FONT_TER10x18 286 &font_ter_10x18, 287 #endif 288 #ifdef CONFIG_FONT_TER16x32 289 &font_ter_16x32, 290 #endif 291 #ifdef CONFIG_FONT_6x8 292 &font_6x8, 293 #endif 294 }; 295 296 #define num_fonts ARRAY_SIZE(fonts) 297 298 #ifdef NO_FONTS 299 #error No fonts configured. 300 #endif 301 302 303 /** 304 * find_font - find a font 305 * @name: string name of a font 306 * 307 * Find a specified font with string name @name. 308 * 309 * Returns %NULL if no font found, or a pointer to the 310 * specified font. 311 * 312 */ 313 const struct font_desc *find_font(const char *name) 314 { 315 unsigned int i; 316 317 BUILD_BUG_ON(!num_fonts); 318 for (i = 0; i < num_fonts; i++) 319 if (!strcmp(fonts[i]->name, name)) 320 return fonts[i]; 321 return NULL; 322 } 323 EXPORT_SYMBOL(find_font); 324 325 326 /** 327 * get_default_font - get default font 328 * @xres: screen size of X 329 * @yres: screen size of Y 330 * @font_w: bit array of supported widths (1 - FB_MAX_BLIT_WIDTH) 331 * @font_h: bit array of supported heights (1 - FB_MAX_BLIT_HEIGHT) 332 * 333 * Get the default font for a specified screen size. 334 * Dimensions are in pixels. 335 * 336 * font_w or font_h being NULL means all values are supported. 337 * 338 * Returns %NULL if no font is found, or a pointer to the 339 * chosen font. 340 * 341 */ 342 const struct font_desc *get_default_font(int xres, int yres, 343 unsigned long *font_w, 344 unsigned long *font_h) 345 { 346 int i, c, cc, res; 347 const struct font_desc *f, *g; 348 349 g = NULL; 350 cc = -10000; 351 for (i = 0; i < num_fonts; i++) { 352 f = fonts[i]; 353 c = f->pref; 354 #if defined(__mc68000__) 355 #ifdef CONFIG_FONT_PEARL_8x8 356 if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX) 357 c = 100; 358 #endif 359 #ifdef CONFIG_FONT_6x11 360 if (MACH_IS_MAC && xres < 640 && f->idx == VGA6x11_IDX) 361 c = 100; 362 #endif 363 #endif 364 if ((yres < 400) == (f->height <= 8)) 365 c += 1000; 366 367 /* prefer a bigger font for high resolution */ 368 res = (xres / f->width) * (yres / f->height) / 1000; 369 if (res > 20) 370 c += 20 - res; 371 372 if ((!font_w || test_bit(f->width - 1, font_w)) && 373 (!font_h || test_bit(f->height - 1, font_h))) 374 c += 1000; 375 376 if (c > cc) { 377 cc = c; 378 g = f; 379 } 380 } 381 return g; 382 } 383 EXPORT_SYMBOL(get_default_font); 384 385 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); 386 MODULE_DESCRIPTION("Console Fonts"); 387 MODULE_LICENSE("GPL"); 388