1 /*
2 psftools: Manipulate console fonts in the .PSF format
3 Copyright (C) 2005-6 John Elliott
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #include "cnvshell.h"
20 #include "psflib.h"
21 #include "dos.h"
22 #include "intrpt.h"
23
24 /* Set this to 1 to enable custom Herc mode settings (see Richard Wilton's
25 * "Programmer's Guide to PC & PS/2 Video Systems, p327) allowing character
26 * sizes other than 9x14
27 *
28 * This is turned off because when I tried it, it didn't work very well.
29 * Fonts 8 pixels wide (ie, nearly all of them) put the screen in a 90-column
30 * mode that went off the right-hand side; an 8x14 font selected a 90x25
31 * mode that was too big to fit in available video RAM; and the smaller
32 * sizes caused my MDA monitor to lose sync.
33 */
34 #define HERC_CUSTOM 0
35
36
37 /* XXX Add support for the 3270PC Programmed Symbols board if none of the
38 * other graphics cards is present */
39 char *herc_loadfont (psf_byte far *buffer, int count, int width, int height,
40 int map);
41 char *ega_loadfont (psf_byte far *buffer, int count, int height, int map);
42 char *conv_loadfont(psf_byte far *buffer, int count, int height, int map);
43 char *apricot_loadfont(psf_byte far *buffer, int count, int width, int height,
44 int slot);
45 char *wang_loadfont(psf_byte far *buffer, int count, int width, int height,
46 int slot);
47 static char *apricot_pc_loadfont(psf_byte far *buffer, int count,
48 int width, int height, int map);
49 static char *apricot_f_loadfont(psf_byte far *buffer, int count,
50 int height, int map);
51 static char *wang_mono_loadfont(psf_byte far *buffer, int count, int width,
52 int height);
53 static char *wang_colour_loadfont(psf_byte far *buffer, int count, int width,
54 int height);
55 /*
56 static char *wang_cgdc_loadfont(psf_byte far *buffer, int count, int width,
57 int height);
58 */
59 static int wang_active_display_type(void);
60
61 static int convertible = 0;
62 static int ega = 0;
63 static int herc = 0;
64 static int apricot = 0;
65 static int wang = 0;
66
67 static int herc_probe(void);
68
video_probe(void)69 char *video_probe(void)
70 {
71 struct SREGS sg;
72 union REGS rg;
73 unsigned char far *ptr;
74
75 /* Check for Apricot type PCs. This must be done first because
76 * the Apricot doesn't have to have an INT 10h */
77 ptr = MK_FP(0x40, 0);
78 if (ptr[4] == 0x34 && ptr[5] == 0x12 &&
79 ptr[6] == 0x78 && ptr[7] == 0x56 &&
80 ptr[1] < 3)
81 {
82 apricot = 1 + ptr[1];
83 return NULL;
84 }
85 /* Check for Wang type PCs, to which the same caveat applies.
86 * Unfortunately, I don't think there's a fixed signature for a
87 * Wang BIOS in the same way that there is for an Apricot BIOS, so
88 * the method is a little more arbitrary: see if there's a jump
89 * at 0040:0000, and check that the segment of the INT 7E handler
90 * is 0040h. */
91 ptr = MK_FP(0, 0);
92 if (ptr[0x400] == 0xEB && ptr[0x401] == 2 && ptr[0x404] == 0xFA &&
93 ptr[0x1FA] == 0x40 && ptr[0x1FB] == 0x00)
94 {
95 /* Now detect video type */
96 int slot;
97
98 for (wang = 0, slot = 1; slot < 15; slot++)
99 {
100 switch(inportb(0x10FE + 256 * slot) & 0x7F)
101 {
102 case 0x10: wang |= 1; break;
103 case 0x11:
104 case 0x15: wang |= 2; break;
105 // The CGDC display class is not supported yet
106 case 0x13:
107 case 0x17: /* wang |= 4; */ break;
108 }
109 }
110 if (!wang)
111 {
112 return "Wang MS-DOS detected, but no suitable "
113 "displays found.";
114 }
115 return NULL;
116 }
117
118
119 /* Check for IBM Convertible */
120 rg.h.ah = 0xC0;
121 int86x(0x15, &rg, &rg, &sg);
122 if (rg.h.ah == 0)
123 {
124 ptr = MK_FP(sg.es, rg.x.bx);
125 if (ptr[2] == 0xF9)
126 {
127 convertible = 1;
128 return 0;
129 }
130 if (ptr[2] == 0xFC) /* AT-class */
131 {
132 /* Check for Compaq portable III / 386 */
133 union REGS rg;
134
135 ptr = MK_FP(0xF000, 0xFFEA);
136 if (ptr[0] == 'C' && ptr[1] == 'O' && ptr[2] == 'M'
137 && ptr[3] == 'P' && ptr[4] == 'A' && ptr[5] == 'Q')
138 {
139 /* Get Compaq environment */
140 rg.x.ax = 0xbf03;
141 rg.x.bx = 0;
142 rg.x.cx = 0;
143 rg.x.dx = 0;
144 int86(0x10, &rg, &rg);
145 /* If Compaq environment present and internal monitor is a 640x400 flat panel,
146 * this is presumed to be a Compaq Portable III / 386 */
147 if (rg.x.bx != 0 && rg.h.dh == 4)
148 {
149 convertible = 2;
150 return 0;
151 }
152 }
153 }
154
155 }
156 /* Check for EGA/VGA */
157 rg.h.ah = 0x12;
158 rg.x.bx = 0xFF10;
159 int86(0x10, &rg, &rg);
160 if (rg.h.bh != 0xFF)
161 {
162 ega = 1;
163 return 0;
164 }
165 /* Check for Hercules Plus */
166 if (herc_probe())
167 {
168 herc = 1;
169 return 0;
170 }
171 //1...5...10...15...20...25...30...35...40...45...50...55
172 return "No supported video hardware detected. Must be one of:\n"
173 "* EGA/VGA\n"
174 "* IBM Convertible\n"
175 "* Hercules Plus\n"
176 "* Apricot PC, Xi or F-Series\n"
177 "* Wang Professional Computer\n";
178 }
179
valid_font(PSF_FILE * psf)180 char *valid_font(PSF_FILE *psf)
181 {
182 if (herc)
183 {
184 #ifdef HERC_CUSTOM
185 if (psf->psf_height < 4 || psf->psf_height > 16)
186 return "Hercules Plus only supports fonts "
187 "4-16 pixels high.";
188 if (psf->psf_width > 9)
189 return "Hardware does not support fonts wider than "
190 "9 pixels.";
191 #else
192 if (psf->psf_height != 14 || psf->psf_width != 8)
193 {
194 return "Fonts for Hercules Plus must be 8 pixels wide "
195 "and 14 high.";
196 }
197 #endif
198 }
199 else if (apricot)
200 {
201 unsigned char far *ptr = MK_FP(0x70, 0);
202 if (apricot == 1) /* PC/Xi */
203 {
204 if (psf->psf_width > 10 || psf->psf_height > 16)
205 return "Apricot PC/Xi fonts can be at most "
206 "10x16 in size";
207
208 }
209 else
210 {
211 unsigned allowed = 0;
212
213 if (psf->psf_width > 8)
214 return "Hardware does not support "
215 "fonts wider than 8 pixels.";
216 if (psf->psf_height == 8) allowed = 1;
217 if (psf->psf_height == 10 && ptr[0x11] >= 0x12)
218 allowed = 1;
219 if (!allowed)
220 {
221 if (ptr[0x11] < 0x12)
222 return "Only 8x8 fonts can be loaded";
223 return "Only 8x8 and 8x10 fonts can be loaded";
224 }
225 }
226 }
227 else if (wang)
228 {
229 if (wang & 2) /* Do we have a mono display? */
230 {
231 if (psf->psf_width > 10 || psf->psf_height > 12)
232 {
233 return "Hardware does not support fonts "
234 "larger than 10x12 pixels.";
235 }
236 }
237 else /* No, colour only */
238 {
239 if (psf->psf_width > 8 || psf->psf_height > 8)
240 {
241 return "Hardware does not support fonts "
242 "larger than 8x8 pixels.";
243 }
244 }
245 }
246 else
247 {
248 if (psf->psf_width > 8) return "Hardware does not support "
249 "fonts wider than 8 pixels.";
250 if (convertible == 1 && psf->psf_height != 8)
251 return "Convertible only supports fonts 8 pixels high.";
252 }
253 return NULL;
254 }
255
256
herc_probe(void)257 static int herc_probe(void)
258 {
259 unsigned n;
260 psf_byte y;
261 union REGS rg;
262
263 rg.h.ah = 0x0F;
264 /* Check that we're in mono mode */
265 int86(0x10, &rg, &rg);
266 if (rg.h.al != 7)
267 {
268 return 0;
269 }
270
271 di();
272 for (n = 0; n < 50000; n++)
273 {
274 y = inportb(0x3BA);
275 if ((y & 0x80) == 0)
276 {
277 /* OK, this is a Herc and not an MDA */
278 ei();
279 switch(y & 0x70)
280 {
281 case 0x50: return 2; /* InColor */
282 case 0x10: return 1; /* Herc Plus */
283 default: return 0; /* Herc */
284 }
285 }
286 }
287 ei();
288 return 0;
289 }
290
291
load_set(unsigned char far * data,int count,int width,int height,int slot)292 static char *load_set(unsigned char far *data, int count,
293 int width, int height, int slot)
294 {
295 char *s;
296
297 if (apricot) s = apricot_loadfont( data, count, width, height, slot);
298 else if (wang) s = wang_loadfont ( data, count, width, height, slot);
299 else if (convertible) s = conv_loadfont( data, count, height, slot);
300 else if (ega && slot < 8) s = ega_loadfont( data, count, height, slot);
301 else if (herc) s = herc_loadfont( data, count, width, height, slot);
302 else return "No supported video hardware present.";
303
304 if (s) return s;
305 if (slot == 1) /* Loading into slot 1. Use it for high-intensity */
306 { /* characters. */
307 union REGS rg;
308 if (convertible)
309 {
310 rg.x.ax = 0x1402;
311 rg.h.bl = 3; /* Use slot 1 for bold */
312 int86(0x10, &rg, &rg);
313 }
314 if (ega)
315 {
316 rg.x.ax = 0x1103;
317 rg.h.bl = 4; /* Use slot 1 for bold, slot 0 normal */
318 int86(0x10, &rg, &rg);
319 }
320 }
321 return NULL;
322 }
323
324
install_font(PSF_FILE * psf,int usealt,int unused)325 char *install_font(PSF_FILE *psf, int usealt, int unused)
326 {
327 char *s;
328 psf_byte far *base;
329 long remaining;
330 int count;
331 int slot;
332 int uslot;
333
334 base = psf->psf_data;
335 remaining = psf->psf_length;
336 slot = 0;
337
338 while (remaining > 0)
339 {
340 if (remaining < 256) count = remaining;
341 else count = 256;
342
343 uslot = slot;
344 /* usealt swaps the first two slots over */
345 if (slot < 2 && usealt) uslot ^= 1;
346 /* Load up to 256 chars into the current slot */
347 s = load_set(base, count, psf->psf_width, psf->psf_height,
348 uslot);
349 if (s) return s;
350 /* Move on to the next chunk */
351 slot++;
352 base += count * psf->psf_charlen;
353 remaining -= count;
354 }
355 return s;
356 }
357
358
conv_loadfont(psf_byte far * buffer,int count,int height,int slot)359 char *conv_loadfont(psf_byte far *buffer, int count, int height, int slot)
360 {
361 union REGS rg;
362 struct SREGS sg;
363
364 /* Convertible supports only 2 fonts */
365 if (slot >= 2) return NULL;
366
367 rg.x.ax = 0x1400;
368 rg.h.bh = height;
369 rg.h.bl = slot;
370 rg.x.cx = count;
371 rg.x.dx = 0;
372 rg.x.di = FP_OFF(buffer);
373 sg.es = FP_SEG(buffer);
374 int86x(0x10, &rg, &rg, &sg);
375 return NULL;
376 }
377
apricot_pc_loadfont(psf_byte far * buffer,int count,int width,int height,int slot)378 static char *apricot_pc_loadfont(psf_byte far *buffer, int count, int width,
379 int height, int slot)
380 {
381 int n, wb, x, y;
382 unsigned char far *src;
383 unsigned char far *dest;
384 /* unsigned short far *ptr = MK_FP(0x70, 0x0C);
385 unsigned char far *font = MK_FP(ptr[1], ptr[0]); */
386 unsigned char far *font = MK_FP(0x80, 0);
387 unsigned short w, mask, mk;
388
389 if (slot >= 1) return NULL;
390 if (count > 256) count = 256;
391 wb = (width + 7) / 8;
392 for (n = 0; n < count; n++)
393 {
394 dest = font + n * 32;
395 for (y = 0; y < 16; y++)
396 {
397 src = buffer + (n * height + y) * wb;
398 w = 0;
399 mask = 1;
400 mk = 0x80;
401 if (y < height) for (x = 0; x < 10; x++)
402 {
403 if (x < width && ((*src & mk))) w |= mask;
404 mask = mask << 1;
405 mk = mk >> 1;
406 if (mk == 0) { mk = 0x80; src++; }
407 }
408 dest[0] = (w & 0xFF);
409 dest[1] &= 0xFC;
410 dest[1] |= ((w >> 8) & 3);
411 dest += 2;
412 }
413 }
414 return NULL;
415 }
416
apricot_f_loadfont(psf_byte far * buffer,int count,int height,int slot)417 static char *apricot_f_loadfont(psf_byte far *buffer, int count,
418 int height, int slot)
419 {
420 int max, n;
421 unsigned short far *ptr = MK_FP(0x70, 0x0C);
422 unsigned char far *font = MK_FP(ptr[1], ptr[0]);
423
424 if (slot >= 1) return NULL;
425 if (height == 10) font += 0x800;
426 if (count > 256) count = 256;
427 max = count * height;
428 for (n = 0; n < max; n++)
429 {
430 font[n] = buffer[n];
431 }
432 return NULL;
433 }
434
435
apricot_loadfont(psf_byte far * buffer,int count,int width,int height,int map)436 char *apricot_loadfont(psf_byte far *buffer, int count, int width, int height,
437 int map)
438 {
439 if (apricot == 1) return apricot_pc_loadfont(buffer, count, width,
440 height, map);
441 return apricot_f_loadfont(buffer, count, height, map);
442 }
443
444
wang_loadfont(psf_byte far * buffer,int count,int width,int height,int slot)445 char *wang_loadfont(psf_byte far *buffer, int count, int width, int height,
446 int slot)
447 {
448 switch (wang)
449 {
450 case 1: /* Colour only */
451 if (slot == 0) return wang_colour_loadfont(buffer, count, width, height);
452 return NULL;
453 case 2: /* Mono only */
454 if (slot == 0) return wang_mono_loadfont(buffer, count, width, height);
455 return NULL;
456
457 /* When CGDC is present, we need to handle these cases as well. */
458 #if 0
459 case 4: /* CGDC only */
460 case 5: /* CGDC and colour */
461 case 6: /* CGDC and mono */
462 case 7: /* All three */
463 case 3: /* Mono & colour */
464 #endif
465 default:
466 switch (slot)
467 {
468 case 0: /* Load into active display */
469 if (wang_active_display_type() < 2) /* colour card? */
470 return wang_colour_loadfont(buffer, count, width, height);
471 else return wang_mono_loadfont(buffer, count, width, height);
472 case 1: /* Load into inactive display */
473 if (wang_active_display_type() < 2) /* colour card? */
474 return wang_mono_loadfont(buffer, count, width, height);
475 else return wang_colour_loadfont(buffer, count, width, height);
476 } /* end switch(slot) */
477 } /* end switch(wang) */
478 return NULL;
479 }
480
481 /* See which display is active, and what type it is */
wang_active_display_type(void)482 static int wang_active_display_type(void)
483 {
484 union REGS rg;
485 struct SREGS sg;
486 unsigned short far *ptr;
487 unsigned char far *scr;
488 unsigned card;
489
490 rg.x.ax = 1;
491 int86x(0x88, &rg, &rg, &sg); /* ES:BX -> BIOS config table */
492 rg.x.bx += 8; /* -> video cards section */
493 ptr = MK_FP(sg.es, rg.x.bx); /* ptr[0] = count of video cards, */
494 /* ptr[1], [2] etc -> descriptors */
495 for (card = 1; card <= ptr[0]; card++)
496 {
497 scr = MK_FP(sg.es, ptr[card]);
498 if (scr[0] & 0x80) /* Active display? */
499 {
500 return (scr[0] & 0x70) >> 4;
501 }
502 }
503 return 0;
504 }
505
506
wang_mono_loadfont(psf_byte far * buffer,int count,int width,int height)507 static char *wang_mono_loadfont(psf_byte far *buffer, int count, int width,
508 int height)
509 {
510 unsigned card, slot;
511 unsigned wb;
512 int y0;
513 union REGS rg;
514 struct SREGS sg;
515 unsigned short far *ptr;
516 unsigned char far *scr;
517 unsigned short bits;
518 unsigned short far *font = MK_FP(0xF200, 0);
519 int n, m;
520
521 if (count > 256) count = 256;
522
523 y0 = (12 - height) / 2;
524 wb = (width + 7) / 8;
525 if (y0 < 0) y0 = 0;
526
527 /* Find the BIOS data segment */
528 rg.x.ax = 1;
529 int86x(0x88, &rg, &rg, &sg); /* ES:BX -> BIOS config table */
530 rg.x.bx += 8; /* -> video cards section */
531 ptr = MK_FP(sg.es, rg.x.bx); /* ptr[0] = count of video cards, */
532 /* ptr[1], [2] etc -> descriptors */
533 for (card = 1; card <= ptr[0]; card++)
534 {
535 scr = MK_FP(sg.es, ptr[card]);
536
537 /* I do hope that having the slot number at offset 0x13 and the device class
538 * at offset 0x14 are contracts rather than implementation details. */
539
540 /* Is this card a class 0x11 or 0x15? */
541 if (scr[0x14] != 0x11 && scr[0x14] != 0x15) continue;
542
543 /* Page the card in */
544 slot = (scr[0x13] * 256);
545 di();
546 outportb(slot | 0x10, (scr[8] & 0x0C) | 1);
547
548 /* Load the font */
549 for (n = 0; n < count; n++)
550 {
551 for (m = 0; m < y0; m++)
552 {
553 font[16 * n + m] = 0;
554 }
555 for (m = 0; m < height; m++)
556 {
557 if (wb == 1) bits = buffer[n * height + m];
558 else
559 {
560 bits = buffer[n * height * wb + wb * m];
561 bits = bits << 2;
562 bits |= (buffer[n * height * wb + wb*m + 1] >> 6) & 3;
563 }
564 if ((m + y0) < 12)
565 {
566 font[16 * n + m + y0] = bits;
567 }
568 }
569 for (; m < 16; m++)
570 {
571 font[16 * n + m + y0] = 0;
572 }
573 }
574
575 /* Page the card out */
576 outportb(slot | 0x10, (scr[8] & 0x0C) );
577 ei();
578 }
579 return NULL;
580 }
581
wang_colour_loadfont(psf_byte far * buffer,int count,int width,int height)582 static char *wang_colour_loadfont(psf_byte far *buffer, int count, int width,
583 int height)
584 {
585 union REGS rg;
586 struct SREGS sg;
587 unsigned short far *ptr;
588 unsigned char far *font;
589 unsigned n, m, wb;
590
591 /* Find the BIOS data segment */
592 rg.x.ax = 1;
593 int86x(0x88, &rg, &rg, &sg); /* ES:BX -> BIOS config table */
594
595 if (count > 256) count = 256;
596 /* I have no idea if this is value is a contract or just some handy
597 * piece of BIOS internals. But the address of the colour screen font
598 * doesn't seem to be exposed anywhere else. */
599 ptr = MK_FP(sg.es, 6);
600 font = MK_FP(ptr[0], 0);
601
602 wb = (width + 7) / 8;
603 for (n = 0; n < count; n++)
604 {
605 for (m = 0; m < 8; m++)
606 {
607 if (m < height) font[n * 8 + m] = buffer[n * wb * height + m * wb];
608 else font[n * 8 + m] = 0;
609 }
610 }
611 return NULL;
612 }
613
614
615 #if HERC_CUSTOM
616 static psf_byte h_params[] =
617 {
618 0x6D, 0x5A, 0x5C, 0x0F, /* 8 pixels wide */
619 0x61, 0x50, 0x52, 0x0F /* 9 pixels wide */
620 };
621
622 static psf_byte v_params[] =
623 {
624 0x5C, 0x02, 0x58, 0x59, /* 4 lines high */
625 0x4A, 0x00, 0x46, 0x46, /* 5 lines high */
626 0x3D, 0x04, 0x3A, 0x3B, /* 6 lines high */
627 0x34, 0x06, 0x32, 0x33, /* 7 lines high */
628 0x2D, 0x02, 0x2B, 0x2C, /* 8 lines high */
629 0x28, 0x01, 0x26, 0x27, /* 9 lines high */
630 0x24, 0x00, 0x23, 0x23, /* 10 lines high */
631 0x20, 0x00, 0x1F, 0x20, /* 11 lines high */
632 0x1D, 0x0A, 0x1D, 0x1D, /* 12 lines high */
633 0x1B, 0x06, 0x1A, 0x1B, /* 13 lines high */
634 0x19, 0x06, 0x19, 0x19, /* 13 lines high */
635 0x17, 0x0A, 0x17, 0x17, /* 13 lines high */
636 0x16, 0x02, 0x15, 0x16, /* 13 lines high */
637 };
638 #endif
639
herc_loadfont(psf_byte far * buffer,int count,int width,int height,int slot)640 char *herc_loadfont(psf_byte far *buffer, int count,
641 int width, int height, int slot)
642 {
643 psf_byte far *dest;
644 psf_byte far *src;
645 psf_byte far *biosdata;
646 unsigned n, m;
647 int wb;
648 static psf_byte x_ramfont = 1;
649
650 if (slot >= 12) return NULL; /* Herc supports 12 fonts */
651 if (slot > 0) x_ramfont = 5; /* 48k RAMfont mode */
652
653 if (width < 8) width = 8;
654 wb = (width + 7) / 8;
655 biosdata = MK_FP(0x40, 0);
656 /* Blank the screen */
657 di();
658 outportb(0x3B8, 0);
659 #if HERC_CUSTOM
660 /* Reprogram the CRTC */
661 m = (wb - 1) * 4;
662 for (n = 0; n < 4; n++)
663 {
664 outportb(0x3B4, n);
665 outportb(0x3B5, h_params[n + m]);
666 }
667 m = (height - 4) * 4;
668 for (n = 0; n < 4; n++)
669 {
670 outportb(0x3B4, n + 4);
671 outportb(0x3B5, v_params[n + m]);
672 }
673 #endif
674 /* Enable the RAM character generator */
675 outportb(0x3B4, 0x14); /* Select CRTC register 0x14 */
676
677 outportb(0x3B5, x_ramfont); /* RAMfont mode */
678 if (slot > 4) /* Slots 5-11 require the Herc to go into Full mode */
679 {
680 outportb(0x3BF, 3);
681 }
682 else
683 {
684 outportb(0x3BF, 1);
685 /* Make character RAM visible at 0xB4000 */
686 }
687 for (n = 0; n < count; n++)
688 {
689 dest = MK_FP(0xB400, slot * 4096 + n * 16);
690 src = buffer + n * height * wb;
691 for (m = 0; m < height; m++)
692 {
693 dest[m] = src[m * wb];
694 }
695 }
696 outportb(0x3BF, 0x00); /* Hide character RAM and Full-mode RAM*/
697
698 #if HERC_CUSTOM
699 biosdata[0x4A] = 720 / width; /* CRT columns */
700 biosdata[0x84] = (350 / height) - 1; /* CRT rows minus 1 */
701 n = (biosdata[0x84] + 1) * biosdata[0x4A]; /* CRT characters */
702 n *= 2;
703 biosdata[0x4C] = (n & 0xFF);
704 biosdata[0x4D] = (n >> 8) & 0xFF;
705 #endif
706 /* Re-enable video */
707 outportb(0x3B8, biosdata[0x65]);
708 ei();
709 return NULL;
710 }
711 #undef di /* We want to use it in asm */
712
713 /* Resort to asm to load the font, because PPD can't pass BP through int86() */
714 #asm
715 .globl large_data
716 .globl large_code
717 .psect _TEXT,class=CODE
718 .globl _ega_loadfont
719 .signat _ega_loadfont,16444
720
721 _ega_loadfont:
722 push bp
723 mov bp,sp
724
725 push si
726 push di
727 push es
728
729 mov dx,ax ; Count
730 mov di,6[bp] ; Address: offset
731 mov ax,8[bp] ; Address: segment
732 mov es,ax ; ES:DI->font
733 mov cx,10[bp] ; Height
734 mov bx,12[bp] ; Font to load
735 mov bh,cl ; BH=height BL=map
736
737 mov ax,#0x1110 ; Function
738 mov cx,dx ; Count
739 mov dx,#0 ; First char
740 push bp
741 mov bp,di ; ES:BP->font
742 int #0x10
743 pop bp
744 pop es
745 pop di
746 pop si
747 pop bp
748 mov dx,#0
749 mov ax,#0 ; Return NULL
750 retf #8
751 #endasm
752
753
754