VGA: Extract code from vga.c into new files vgaio.c and vgafb.c.
[seabios.git] / vgasrc / vgafb.c
1 // Code for manipulating VGA framebuffers.
2 //
3 // Copyright (C) 2009  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2001-2008 the LGPL VGABios developers Team
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "biosvar.h" // GET_BDA
9 #include "util.h" // memset_far
10 #include "vgatables.h" // find_vga_entry
11
12 // XXX
13 inline void
14 memcpy16_far(u16 d_seg, void *d_far, u16 s_seg, const void *s_far, size_t len)
15 {
16     memcpy_far(d_seg, d_far, s_seg, s_far, len);
17 }
18
19
20 /****************************************************************
21  * Screen scrolling
22  ****************************************************************/
23
24 static void
25 vgamem_copy_pl4(u8 xstart, u8 ysrc, u8 ydest, u8 cols, u8 nbcols,
26                 u8 cheight)
27 {
28     u16 src = ysrc * cheight * nbcols + xstart;
29     u16 dest = ydest * cheight * nbcols + xstart;
30     outw(0x0105, VGAREG_GRDC_ADDRESS);
31     u8 i;
32     for (i = 0; i < cheight; i++)
33         memcpy_far(SEG_GRAPH, (void*)(dest + i * nbcols)
34                    , SEG_GRAPH, (void*)(src + i * nbcols), cols);
35     outw(0x0005, VGAREG_GRDC_ADDRESS);
36 }
37
38 static void
39 vgamem_fill_pl4(u8 xstart, u8 ystart, u8 cols, u8 nbcols, u8 cheight,
40                 u8 attr)
41 {
42     u16 dest = ystart * cheight * nbcols + xstart;
43     outw(0x0205, VGAREG_GRDC_ADDRESS);
44     u8 i;
45     for (i = 0; i < cheight; i++)
46         memset_far(SEG_GRAPH, (void*)(dest + i * nbcols), attr, cols);
47     outw(0x0005, VGAREG_GRDC_ADDRESS);
48 }
49
50 static void
51 vgamem_copy_cga(u8 xstart, u8 ysrc, u8 ydest, u8 cols, u8 nbcols,
52                 u8 cheight)
53 {
54     u16 src = ((ysrc * cheight * nbcols) >> 1) + xstart;
55     u16 dest = ((ydest * cheight * nbcols) >> 1) + xstart;
56     u8 i;
57     for (i = 0; i < cheight; i++)
58         if (i & 1)
59             memcpy_far(SEG_CTEXT, (void*)(0x2000 + dest + (i >> 1) * nbcols)
60                        , SEG_CTEXT, (void*)(0x2000 + src + (i >> 1) * nbcols)
61                        , cols);
62         else
63             memcpy_far(SEG_CTEXT, (void*)(dest + (i >> 1) * nbcols)
64                        , SEG_CTEXT, (void*)(src + (i >> 1) * nbcols), cols);
65 }
66
67 static void
68 vgamem_fill_cga(u8 xstart, u8 ystart, u8 cols, u8 nbcols, u8 cheight,
69                 u8 attr)
70 {
71     u16 dest = ((ystart * cheight * nbcols) >> 1) + xstart;
72     u8 i;
73     for (i = 0; i < cheight; i++)
74         if (i & 1)
75             memset_far(SEG_CTEXT, (void*)(0x2000 + dest + (i >> 1) * nbcols)
76                        , attr, cols);
77         else
78             memset_far(SEG_CTEXT, (void*)(dest + (i >> 1) * nbcols), attr, cols);
79 }
80
81 void
82 biosfn_scroll(u8 nblines, u8 attr, u8 rul, u8 cul, u8 rlr, u8 clr, u8 page,
83               u8 dir)
84 {
85     // page == 0xFF if current
86     if (rul > rlr)
87         return;
88     if (cul > clr)
89         return;
90
91     // Get the mode
92     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
93     if (!vmode_g)
94         return;
95
96     // Get the dimensions
97     u16 nbrows = GET_BDA(video_rows) + 1;
98     u16 nbcols = GET_BDA(video_cols);
99
100     // Get the current page
101     if (page == 0xFF)
102         page = GET_BDA(video_page);
103
104     if (rlr >= nbrows)
105         rlr = nbrows - 1;
106     if (clr >= nbcols)
107         clr = nbcols - 1;
108     if (nblines > nbrows)
109         nblines = 0;
110     u8 cols = clr - cul + 1;
111
112     if (GET_GLOBAL(vmode_g->class) == TEXT) {
113         // Compute the address
114         void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page));
115         dprintf(3, "Scroll, address %p (%d %d %02x)\n"
116                 , address_far, nbrows, nbcols, page);
117
118         if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
119             && clr == nbcols - 1) {
120             memset16_far(GET_GLOBAL(vmode_g->sstart), address_far
121                          , (u16)attr * 0x100 + ' ', nbrows * nbcols * 2);
122         } else {                // if Scroll up
123             if (dir == SCROLL_UP) {
124                 u16 i;
125                 for (i = rul; i <= rlr; i++)
126                     if ((i + nblines > rlr) || (nblines == 0))
127                         memset16_far(GET_GLOBAL(vmode_g->sstart)
128                                      , address_far + (i * nbcols + cul) * 2
129                                      , (u16)attr * 0x100 + ' ', cols * 2);
130                     else
131                         memcpy16_far(GET_GLOBAL(vmode_g->sstart)
132                                      , address_far + (i * nbcols + cul) * 2
133                                      , GET_GLOBAL(vmode_g->sstart)
134                                      , (void*)(((i + nblines) * nbcols + cul) * 2)
135                                      , cols * 2);
136             } else {
137                 u16 i;
138                 for (i = rlr; i >= rul; i--) {
139                     if ((i < rul + nblines) || (nblines == 0))
140                         memset16_far(GET_GLOBAL(vmode_g->sstart)
141                                      , address_far + (i * nbcols + cul) * 2
142                                      , (u16)attr * 0x100 + ' ', cols * 2);
143                     else
144                         memcpy16_far(GET_GLOBAL(vmode_g->sstart)
145                                      , address_far + (i * nbcols + cul) * 2
146                                      , GET_GLOBAL(vmode_g->sstart)
147                                      , (void*)(((i - nblines) * nbcols + cul) * 2)
148                                      , cols * 2);
149                     if (i > rlr)
150                         break;
151                 }
152             }
153         }
154         return;
155     }
156
157     // FIXME gfx mode not complete
158     struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
159     u8 cheight = GET_GLOBAL(vparam_g->cheight);
160     switch (GET_GLOBAL(vmode_g->memmodel)) {
161     case PLANAR4:
162     case PLANAR1:
163         if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
164             && clr == nbcols - 1) {
165             outw(0x0205, VGAREG_GRDC_ADDRESS);
166             memset_far(GET_GLOBAL(vmode_g->sstart), 0, attr,
167                        nbrows * nbcols * cheight);
168             outw(0x0005, VGAREG_GRDC_ADDRESS);
169         } else {            // if Scroll up
170             if (dir == SCROLL_UP) {
171                 u16 i;
172                 for (i = rul; i <= rlr; i++)
173                     if ((i + nblines > rlr) || (nblines == 0))
174                         vgamem_fill_pl4(cul, i, cols, nbcols, cheight,
175                                         attr);
176                     else
177                         vgamem_copy_pl4(cul, i + nblines, i, cols,
178                                         nbcols, cheight);
179             } else {
180                 u16 i;
181                 for (i = rlr; i >= rul; i--) {
182                     if ((i < rul + nblines) || (nblines == 0))
183                         vgamem_fill_pl4(cul, i, cols, nbcols, cheight,
184                                         attr);
185                     else
186                         vgamem_copy_pl4(cul, i, i - nblines, cols,
187                                         nbcols, cheight);
188                     if (i > rlr)
189                         break;
190                 }
191             }
192         }
193         break;
194     case CGA: {
195         u8 bpp = GET_GLOBAL(vmode_g->pixbits);
196         if (nblines == 0 && rul == 0 && cul == 0 && rlr == nbrows - 1
197             && clr == nbcols - 1) {
198             memset_far(GET_GLOBAL(vmode_g->sstart), 0, attr,
199                        nbrows * nbcols * cheight * bpp);
200         } else {
201             if (bpp == 2) {
202                 cul <<= 1;
203                 cols <<= 1;
204                 nbcols <<= 1;
205             }
206             // if Scroll up
207             if (dir == SCROLL_UP) {
208                 u16 i;
209                 for (i = rul; i <= rlr; i++)
210                     if ((i + nblines > rlr) || (nblines == 0))
211                         vgamem_fill_cga(cul, i, cols, nbcols, cheight,
212                                         attr);
213                     else
214                         vgamem_copy_cga(cul, i + nblines, i, cols,
215                                         nbcols, cheight);
216             } else {
217                 u16 i;
218                 for (i = rlr; i >= rul; i--) {
219                     if ((i < rul + nblines) || (nblines == 0))
220                         vgamem_fill_cga(cul, i, cols, nbcols, cheight,
221                                         attr);
222                     else
223                         vgamem_copy_cga(cul, i, i - nblines, cols,
224                                         nbcols, cheight);
225                     if (i > rlr)
226                         break;
227                 }
228             }
229         }
230         break;
231     }
232     default:
233         dprintf(1, "Scroll in graphics mode\n");
234     }
235 }
236
237
238 /****************************************************************
239  * Read/write characters to screen
240  ****************************************************************/
241
242 static void
243 write_gfx_char_pl4(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols,
244                    u8 cheight)
245 {
246     u8 *fdata_g;
247     switch (cheight) {
248     case 14:
249         fdata_g = vgafont14;
250         break;
251     case 16:
252         fdata_g = vgafont16;
253         break;
254     default:
255         fdata_g = vgafont8;
256     }
257     u16 addr = xcurs + ycurs * cheight * nbcols;
258     u16 src = car * cheight;
259     outw(0x0f02, VGAREG_SEQU_ADDRESS);
260     outw(0x0205, VGAREG_GRDC_ADDRESS);
261     if (attr & 0x80)
262         outw(0x1803, VGAREG_GRDC_ADDRESS);
263     else
264         outw(0x0003, VGAREG_GRDC_ADDRESS);
265     u8 i;
266     for (i = 0; i < cheight; i++) {
267         u8 *dest_far = (void*)(addr + i * nbcols);
268         u8 j;
269         for (j = 0; j < 8; j++) {
270             u8 mask = 0x80 >> j;
271             outw((mask << 8) | 0x08, VGAREG_GRDC_ADDRESS);
272             GET_FARVAR(SEG_GRAPH, *dest_far);
273             if (GET_GLOBAL(fdata_g[src + i]) & mask)
274                 SET_FARVAR(SEG_GRAPH, *dest_far, attr & 0x0f);
275             else
276                 SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
277         }
278     }
279     outw(0xff08, VGAREG_GRDC_ADDRESS);
280     outw(0x0005, VGAREG_GRDC_ADDRESS);
281     outw(0x0003, VGAREG_GRDC_ADDRESS);
282 }
283
284 static void
285 write_gfx_char_cga(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols, u8 bpp)
286 {
287     u8 *fdata_g = vgafont8;
288     u16 addr = (xcurs * bpp) + ycurs * 320;
289     u16 src = car * 8;
290     u8 i;
291     for (i = 0; i < 8; i++) {
292         u8 *dest_far = (void*)(addr + (i >> 1) * 80);
293         if (i & 1)
294             dest_far += 0x2000;
295         u8 mask = 0x80;
296         if (bpp == 1) {
297             u8 data = 0;
298             if (attr & 0x80)
299                 data = GET_FARVAR(SEG_CTEXT, *dest_far);
300             u8 j;
301             for (j = 0; j < 8; j++) {
302                 if (GET_GLOBAL(fdata_g[src + i]) & mask) {
303                     if (attr & 0x80)
304                         data ^= (attr & 0x01) << (7 - j);
305                     else
306                         data |= (attr & 0x01) << (7 - j);
307                 }
308                 mask >>= 1;
309             }
310             SET_FARVAR(SEG_CTEXT, *dest_far, data);
311         } else {
312             while (mask > 0) {
313                 u8 data = 0;
314                 if (attr & 0x80)
315                     data = GET_FARVAR(SEG_CTEXT, *dest_far);
316                 u8 j;
317                 for (j = 0; j < 4; j++) {
318                     if (GET_GLOBAL(fdata_g[src + i]) & mask) {
319                         if (attr & 0x80)
320                             data ^= (attr & 0x03) << ((3 - j) * 2);
321                         else
322                             data |= (attr & 0x03) << ((3 - j) * 2);
323                     }
324                     mask >>= 1;
325                 }
326                 SET_FARVAR(SEG_CTEXT, *dest_far, data);
327                 dest_far += 1;
328             }
329         }
330     }
331 }
332
333 static void
334 write_gfx_char_lin(u8 car, u8 attr, u8 xcurs, u8 ycurs, u8 nbcols)
335 {
336     u8 *fdata_g = vgafont8;
337     u16 addr = xcurs * 8 + ycurs * nbcols * 64;
338     u16 src = car * 8;
339     u8 i;
340     for (i = 0; i < 8; i++) {
341         u8 *dest_far = (void*)(addr + i * nbcols * 8);
342         u8 mask = 0x80;
343         u8 j;
344         for (j = 0; j < 8; j++) {
345             u8 data = 0x00;
346             if (GET_GLOBAL(fdata_g[src + i]) & mask)
347                 data = attr;
348             SET_FARVAR(SEG_GRAPH, dest_far[j], data);
349             mask >>= 1;
350         }
351     }
352 }
353
354 void
355 biosfn_write_char_attr(u8 car, u8 page, u8 attr, u16 count)
356 {
357     // Get the mode
358     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
359     if (!vmode_g)
360         return;
361
362     // Get the cursor pos for the page
363     u16 cursor = biosfn_get_cursor_pos(page);
364     u8 xcurs = cursor & 0x00ff;
365     u8 ycurs = (cursor & 0xff00) >> 8;
366
367     // Get the dimensions
368     u16 nbrows = GET_BDA(video_rows) + 1;
369     u16 nbcols = GET_BDA(video_cols);
370
371     if (GET_GLOBAL(vmode_g->class) == TEXT) {
372         // Compute the address
373         void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
374                                     + (xcurs + ycurs * nbcols) * 2);
375
376         u16 dummy = ((u16)attr << 8) + car;
377         memset16_far(GET_GLOBAL(vmode_g->sstart), address_far, dummy, count * 2);
378         return;
379     }
380
381     // FIXME gfx mode not complete
382     struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
383     u8 cheight = GET_GLOBAL(vparam_g->cheight);
384     u8 bpp = GET_GLOBAL(vmode_g->pixbits);
385     while ((count-- > 0) && (xcurs < nbcols)) {
386         switch (GET_GLOBAL(vmode_g->memmodel)) {
387         case PLANAR4:
388         case PLANAR1:
389             write_gfx_char_pl4(car, attr, xcurs, ycurs, nbcols, cheight);
390             break;
391         case CGA:
392             write_gfx_char_cga(car, attr, xcurs, ycurs, nbcols, bpp);
393             break;
394         case LINEAR8:
395             write_gfx_char_lin(car, attr, xcurs, ycurs, nbcols);
396             break;
397         }
398         xcurs++;
399     }
400 }
401
402 void
403 biosfn_write_char_only(u8 car, u8 page, u8 attr, u16 count)
404 {
405     // Get the mode
406     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
407     if (!vmode_g)
408         return;
409
410     // Get the cursor pos for the page
411     u16 cursor = biosfn_get_cursor_pos(page);
412     u8 xcurs = cursor & 0x00ff;
413     u8 ycurs = (cursor & 0xff00) >> 8;
414
415     // Get the dimensions
416     u16 nbrows = GET_BDA(video_rows) + 1;
417     u16 nbcols = GET_BDA(video_cols);
418
419     if (GET_GLOBAL(vmode_g->class) == TEXT) {
420         // Compute the address
421         u8 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
422                                   + (xcurs + ycurs * nbcols) * 2);
423         while (count-- > 0) {
424             SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far, car);
425             address_far += 2;
426         }
427         return;
428     }
429
430     // FIXME gfx mode not complete
431     struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
432     u8 cheight = GET_GLOBAL(vparam_g->cheight);
433     u8 bpp = GET_GLOBAL(vmode_g->pixbits);
434     while ((count-- > 0) && (xcurs < nbcols)) {
435         switch (GET_GLOBAL(vmode_g->memmodel)) {
436         case PLANAR4:
437         case PLANAR1:
438             write_gfx_char_pl4(car, attr, xcurs, ycurs, nbcols, cheight);
439             break;
440         case CGA:
441             write_gfx_char_cga(car, attr, xcurs, ycurs, nbcols, bpp);
442             break;
443         case LINEAR8:
444             write_gfx_char_lin(car, attr, xcurs, ycurs, nbcols);
445             break;
446         }
447         xcurs++;
448     }
449 }
450
451 void
452 biosfn_read_char_attr(u8 page, u16 *car)
453 {
454     // Get the mode
455     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
456     if (!vmode_g)
457         return;
458
459     // Get the cursor pos for the page
460     u16 cursor = biosfn_get_cursor_pos(page);
461     u8 xcurs = cursor & 0x00ff;
462     u8 ycurs = (cursor & 0xff00) >> 8;
463
464     // Get the dimensions
465     u16 nbrows = GET_BDA(video_rows) + 1;
466     u16 nbcols = GET_BDA(video_cols);
467
468     if (GET_GLOBAL(vmode_g->class) == TEXT) {
469         // Compute the address
470         u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, page)
471                                    + (xcurs + ycurs * nbcols) * 2);
472
473         *car = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
474     } else {
475         // FIXME gfx mode
476         dprintf(1, "Read char in graphics mode\n");
477     }
478 }
479
480
481 /****************************************************************
482  * Read/write pixels
483  ****************************************************************/
484
485 void
486 biosfn_write_pixel(u8 BH, u8 AL, u16 CX, u16 DX)
487 {
488     // Get the mode
489     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
490     if (!vmode_g)
491         return;
492     if (GET_GLOBAL(vmode_g->class) == TEXT)
493         return;
494
495     u8 *addr_far, mask, attr, data;
496     switch (GET_GLOBAL(vmode_g->memmodel)) {
497     case PLANAR4:
498     case PLANAR1:
499         addr_far = (void*)(CX / 8 + DX * GET_BDA(video_cols));
500         mask = 0x80 >> (CX & 0x07);
501         outw((mask << 8) | 0x08, VGAREG_GRDC_ADDRESS);
502         outw(0x0205, VGAREG_GRDC_ADDRESS);
503         data = GET_FARVAR(SEG_GRAPH, *addr_far);
504         if (AL & 0x80)
505             outw(0x1803, VGAREG_GRDC_ADDRESS);
506         SET_FARVAR(SEG_GRAPH, *addr_far, AL);
507         outw(0xff08, VGAREG_GRDC_ADDRESS);
508         outw(0x0005, VGAREG_GRDC_ADDRESS);
509         outw(0x0003, VGAREG_GRDC_ADDRESS);
510         break;
511     case CGA:
512         if (GET_GLOBAL(vmode_g->pixbits) == 2)
513             addr_far = (void*)((CX >> 2) + (DX >> 1) * 80);
514         else
515             addr_far = (void*)((CX >> 3) + (DX >> 1) * 80);
516         if (DX & 1)
517             addr_far += 0x2000;
518         data = GET_FARVAR(SEG_CTEXT, *addr_far);
519         if (GET_GLOBAL(vmode_g->pixbits) == 2) {
520             attr = (AL & 0x03) << ((3 - (CX & 0x03)) * 2);
521             mask = 0x03 << ((3 - (CX & 0x03)) * 2);
522         } else {
523             attr = (AL & 0x01) << (7 - (CX & 0x07));
524             mask = 0x01 << (7 - (CX & 0x07));
525         }
526         if (AL & 0x80) {
527             data ^= attr;
528         } else {
529             data &= ~mask;
530             data |= attr;
531         }
532         SET_FARVAR(SEG_CTEXT, *addr_far, data);
533         break;
534     case LINEAR8:
535         addr_far = (void*)(CX + DX * (GET_BDA(video_cols) * 8));
536         SET_FARVAR(SEG_GRAPH, *addr_far, AL);
537         break;
538     }
539 }
540
541 void
542 biosfn_read_pixel(u8 BH, u16 CX, u16 DX, u16 *AX)
543 {
544     // Get the mode
545     struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
546     if (!vmode_g)
547         return;
548     if (GET_GLOBAL(vmode_g->class) == TEXT)
549         return;
550
551     u8 *addr_far, mask, attr=0, data, i;
552     switch (GET_GLOBAL(vmode_g->memmodel)) {
553     case PLANAR4:
554     case PLANAR1:
555         addr_far = (void*)(CX / 8 + DX * GET_BDA(video_cols));
556         mask = 0x80 >> (CX & 0x07);
557         attr = 0x00;
558         for (i = 0; i < 4; i++) {
559             outw((i << 8) | 0x04, VGAREG_GRDC_ADDRESS);
560             data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
561             if (data > 0)
562                 attr |= (0x01 << i);
563         }
564         break;
565     case CGA:
566         addr_far = (void*)((CX >> 2) + (DX >> 1) * 80);
567         if (DX & 1)
568             addr_far += 0x2000;
569         data = GET_FARVAR(SEG_CTEXT, *addr_far);
570         if (GET_GLOBAL(vmode_g->pixbits) == 2)
571             attr = (data >> ((3 - (CX & 0x03)) * 2)) & 0x03;
572         else
573             attr = (data >> (7 - (CX & 0x07))) & 0x01;
574         break;
575     case LINEAR8:
576         addr_far = (void*)(CX + DX * (GET_BDA(video_cols) * 8));
577         attr = GET_FARVAR(SEG_GRAPH, *addr_far);
578         break;
579     }
580     *AX = (*AX & 0xff00) | attr;
581 }
582
583
584 /****************************************************************
585  * Font loading
586  ****************************************************************/
587
588 void
589 biosfn_load_text_user_pat(u16 ES, u16 BP, u16 CX, u16 DX, u8 BL, u8 BH)
590 {
591     get_font_access();
592     u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
593     u16 i;
594     for (i = 0; i < CX; i++) {
595         void *src_far = (void*)(BP + i * BH);
596         void *dest_far = (void*)(blockaddr + (DX + i) * 32);
597         memcpy_far(SEG_GRAPH, dest_far, ES, src_far, BH);
598     }
599     release_font_access();
600 }
601
602 void
603 biosfn_load_text_8_14_pat(u8 BL)
604 {
605     get_font_access();
606     u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
607     u16 i;
608     for (i = 0; i < 0x100; i++) {
609         u16 src = i * 14;
610         void *dest_far = (void*)(blockaddr + i * 32);
611         memcpy_far(SEG_GRAPH, dest_far, get_global_seg(), &vgafont14[src], 14);
612     }
613     release_font_access();
614 }
615
616 void
617 biosfn_load_text_8_8_pat(u8 BL)
618 {
619     get_font_access();
620     u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
621     u16 i;
622     for (i = 0; i < 0x100; i++) {
623         u16 src = i * 8;
624         void *dest_far = (void*)(blockaddr + i * 32);
625         memcpy_far(SEG_GRAPH, dest_far, get_global_seg(), &vgafont8[src], 8);
626     }
627     release_font_access();
628 }
629
630 void
631 biosfn_load_text_8_16_pat(u8 BL)
632 {
633     get_font_access();
634     u16 blockaddr = ((BL & 0x03) << 14) + ((BL & 0x04) << 11);
635     u16 i;
636     for (i = 0; i < 0x100; i++) {
637         u16 src = i * 16;
638         void *dest_far = (void*)(blockaddr + i * 32);
639         memcpy_far(SEG_GRAPH, dest_far, get_global_seg(), &vgafont16[src], 16);
640     }
641     release_font_access();
642 }