xref: /aosp_15_r20/external/coreboot/payloads/libpayload/curses/PDCurses/dos/pdcscrn.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* Public Domain Curses */
2 
3 #include "pdcdos.h"
4 
5 RCSID("$Id: pdcscrn.c,v 1.89 2008/07/13 16:08:17 wmcbrine Exp $")
6 
7 #include <stdlib.h>
8 
9 #ifdef CHTYPE_LONG
10 # define PDC_OFFSET 32
11 #else
12 # define PDC_OFFSET  8
13 #endif
14 
15 /* COLOR_PAIR to attribute encoding table. */
16 
17 unsigned char *pdc_atrtab = (unsigned char *)NULL;
18 
19 int pdc_adapter;         /* screen type */
20 int pdc_scrnmode;        /* default screen mode */
21 int pdc_font;            /* default font size */
22 bool pdc_direct_video;   /* allow direct screen memory writes */
23 bool pdc_bogus_adapter;  /* TRUE if adapter has insane values */
24 unsigned pdc_video_seg;  /* video base segment */
25 unsigned pdc_video_ofs;  /* video base offset */
26 
27 static short curstoreal[16], realtocurs[16] =
28 {
29     COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED,
30     COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, COLOR_BLACK + 8,
31     COLOR_BLUE + 8, COLOR_GREEN + 8, COLOR_CYAN + 8, COLOR_RED + 8,
32     COLOR_MAGENTA + 8, COLOR_YELLOW + 8, COLOR_WHITE + 8
33 };
34 
35 static bool sizeable = FALSE;   /* TRUE if adapter is resizeable    */
36 
37 static unsigned short *saved_screen = NULL;
38 static int saved_lines = 0;
39 static int saved_cols = 0;
40 
41 static int saved_scrnmode[3];
42 static int saved_font[3];
43 
44 /* Thanks to Jeff Duntemann, K16RA for providing the impetus
45    (through the Dr. Dobbs Journal, March 1989 issue) for getting
46    the routines below merged into Bjorn Larsson's PDCurses 1.3...
47     -- [email protected]    900730 */
48 
49 /* _get_font() - Get the current font size */
50 
_get_font(void)51 static int _get_font(void)
52 {
53     int retval;
54 
55     retval = getdosmemword(0x485);
56 
57     /* Assume the MDS Genius is in 66 line mode. */
58 
59     if ((retval == 0) && (pdc_adapter == _MDS_GENIUS))
60         retval = _FONT15;
61 
62     switch (pdc_adapter)
63     {
64     case _MDA:
65         retval = 10;    /* POINTS is not certain on MDA/Hercules */
66         break;
67 
68     case _EGACOLOR:
69     case _EGAMONO:
70         switch (retval)
71         {
72         case _FONT8:
73         case _FONT14:
74             break;
75         default:
76             retval = _FONT14;
77         }
78         break;
79 
80     case _CGA:
81         retval = _FONT8;
82     }
83 
84     return retval;
85 }
86 
87 /* _set_font() - Sets the current font size, if the adapter allows such a
88    change. It is an error to attempt to change the font size on a
89    "bogus" adapter. The reason for this is that we have a known video
90    adapter identity problem. e.g. Two adapters report the same identifying
91    characteristics. */
92 
_set_font(int size)93 static void _set_font(int size)
94 {
95     PDCREGS regs;
96 
97     if (pdc_bogus_adapter)
98         return;
99 
100     switch (pdc_adapter)
101     {
102     case _CGA:
103     case _MDA:
104     case _MCGACOLOR:
105     case _MCGAMONO:
106     case _MDS_GENIUS:
107         break;
108 
109     case _EGACOLOR:
110     case _EGAMONO:
111         if (sizeable && (pdc_font != size))
112         {
113             switch (size)
114             {
115             case _FONT8:
116                 regs.W.ax = 0x1112;
117                 regs.h.bl = 0x00;
118                 PDCINT(0x10, regs);
119                 break;
120             case _FONT14:
121                 regs.W.ax = 0x1111;
122                 regs.h.bl = 0x00;
123                 PDCINT(0x10, regs);
124             }
125         }
126         break;
127 
128     case _VGACOLOR:
129     case _VGAMONO:
130         if (sizeable && (pdc_font != size))
131         {
132             switch (size)
133             {
134             case _FONT8:
135                 regs.W.ax = 0x1112;
136                 regs.h.bl = 0x00;
137                 PDCINT(0x10, regs);
138                 break;
139             case _FONT14:
140                 regs.W.ax = 0x1111;
141                 regs.h.bl = 0x00;
142                 PDCINT(0x10, regs);
143                 break;
144             case _FONT16:
145                 regs.W.ax = 0x1114;
146                 regs.h.bl = 0x00;
147                 PDCINT(0x10, regs);
148             }
149         }
150     }
151 
152     curs_set(SP->visibility);
153 
154     pdc_font = _get_font();
155 }
156 
157 /* _set_80x25() - force a known screen state: 80x25 text mode. Forces the
158    appropriate 80x25 alpha mode given the display adapter. */
159 
_set_80x25(void)160 static void _set_80x25(void)
161 {
162     PDCREGS regs;
163 
164     switch (pdc_adapter)
165     {
166     case _CGA:
167     case _EGACOLOR:
168     case _EGAMONO:
169     case _VGACOLOR:
170     case _VGAMONO:
171     case _MCGACOLOR:
172     case _MCGAMONO:
173         regs.h.ah = 0x00;
174         regs.h.al = 0x03;
175         PDCINT(0x10, regs);
176         break;
177     case _MDA:
178         regs.h.ah = 0x00;
179         regs.h.al = 0x07;
180         PDCINT(0x10, regs);
181     }
182 }
183 
184 /* _get_scrn_mode() - Return the current BIOS video mode */
185 
_get_scrn_mode(void)186 static int _get_scrn_mode(void)
187 {
188     PDCREGS regs;
189 
190     regs.h.ah = 0x0f;
191     PDCINT(0x10, regs);
192 
193     return (int)regs.h.al;
194 }
195 
196 /* _set_scrn_mode() - Sets the BIOS Video Mode Number only if it is
197    different from the current video mode. */
198 
_set_scrn_mode(int new_mode)199 static void _set_scrn_mode(int new_mode)
200 {
201     PDCREGS regs;
202 
203     if (_get_scrn_mode() != new_mode)
204     {
205         regs.h.ah = 0;
206         regs.h.al = (unsigned char) new_mode;
207         PDCINT(0x10, regs);
208     }
209 
210     pdc_font = _get_font();
211     pdc_scrnmode = new_mode;
212     LINES = PDC_get_rows();
213     COLS = PDC_get_columns();
214 }
215 
216 /* _sanity_check() - A video adapter identification sanity check. This
217    routine will force sane values for various control flags. */
218 
_sanity_check(int adapter)219 static int _sanity_check(int adapter)
220 {
221     int fontsize = _get_font();
222     int rows = PDC_get_rows();
223 
224     PDC_LOG(("_sanity_check() - called: Adapter %d\n", adapter));
225 
226     switch (adapter)
227     {
228     case _EGACOLOR:
229     case _EGAMONO:
230         switch (rows)
231         {
232         case 25:
233         case 43:
234             break;
235         default:
236             pdc_bogus_adapter = TRUE;
237         }
238 
239         switch (fontsize)
240         {
241         case _FONT8:
242         case _FONT14:
243             break;
244         default:
245             pdc_bogus_adapter = TRUE;
246         }
247         break;
248 
249     case _VGACOLOR:
250     case _VGAMONO:
251         break;
252 
253     case _CGA:
254     case _MDA:
255     case _MCGACOLOR:
256     case _MCGAMONO:
257         switch (rows)
258         {
259         case 25:
260             break;
261         default:
262             pdc_bogus_adapter = TRUE;
263         }
264         break;
265 
266     default:
267         pdc_bogus_adapter = TRUE;
268     }
269 
270     if (pdc_bogus_adapter)
271     {
272         sizeable = FALSE;
273         pdc_direct_video = FALSE;
274     }
275 
276     return adapter;
277 }
278 
279 /* _query_adapter_type() - Determine PC video adapter type. */
280 
_query_adapter_type(void)281 static int _query_adapter_type(void)
282 {
283     PDCREGS regs;
284     int retval = _NONE;
285 
286     /* thanks to [email protected] for the GO32 fix */
287 
288 #if !defined(__DJGPP__) && !defined(__WATCOMC__)
289     struct SREGS segs;
290 #endif
291     short video_base = getdosmemword(0x463);
292 
293     PDC_LOG(("_query_adapter_type() - called\n"));
294 
295     /* attempt to call VGA Identify Adapter Function */
296 
297     regs.W.ax = 0x1a00;
298     PDCINT(0x10, regs);
299 
300     if ((regs.h.al == 0x1a) && (retval == _NONE))
301     {
302         /* We know that the PS/2 video BIOS is alive and well. */
303 
304         switch (regs.h.al)
305         {
306         case 0:
307             retval = _NONE;
308             break;
309         case 1:
310             retval = _MDA;
311             break;
312         case 2:
313             retval = _CGA;
314             break;
315         case 4:
316             retval = _EGACOLOR;
317             sizeable = TRUE;
318             break;
319         case 5:
320             retval = _EGAMONO;
321             break;
322         case 26:            /* ...alt. VGA BIOS... */
323         case 7:
324             retval = _VGACOLOR;
325             sizeable = TRUE;
326             break;
327         case 8:
328             retval = _VGAMONO;
329             break;
330         case 10:
331         case 13:
332             retval = _MCGACOLOR;
333             break;
334         case 12:
335             retval = _MCGAMONO;
336             break;
337         default:
338             retval = _CGA;
339         }
340     }
341     else
342     {
343         /* No VGA BIOS, check for an EGA BIOS by selecting an
344            Alternate Function Service...
345 
346            bx == 0x0010 --> return EGA information */
347 
348         regs.h.ah = 0x12;
349         regs.W.bx = 0x10;
350         PDCINT(0x10, regs);
351 
352         if ((regs.h.bl != 0x10) && (retval == _NONE))
353         {
354             /* An EGA BIOS exists */
355 
356             regs.h.ah = 0x12;
357             regs.h.bl = 0x10;
358             PDCINT(0x10, regs);
359 
360             if (regs.h.bh == 0)
361                 retval = _EGACOLOR;
362             else
363                 retval = _EGAMONO;
364         }
365         else if (retval == _NONE)
366         {
367             /* Now we know we only have CGA or MDA */
368 
369             PDCINT(0x11, regs);
370 
371             switch (regs.h.al & 0x30)
372             {
373             case 0x10:
374             case 0x20:
375                 retval = _CGA;
376                 break;
377             case 0x30:
378                 retval = _MDA;
379                 break;
380             default:
381                 retval = _NONE;
382             }
383         }
384     }
385 
386     if (video_base == 0x3d4)
387     {
388         pdc_video_seg = 0xb800;
389         switch (retval)
390         {
391         case _EGAMONO:
392             retval = _EGACOLOR;
393             break;
394         case _VGAMONO:
395             retval = _VGACOLOR;
396         }
397     }
398 
399     if (video_base == 0x3b4)
400     {
401         pdc_video_seg = 0xb000;
402         switch (retval)
403         {
404         case _EGACOLOR:
405             retval = _EGAMONO;
406             break;
407         case _VGACOLOR:
408             retval = _VGAMONO;
409         }
410     }
411 
412     if ((retval == _NONE)
413 #ifndef CGA_DIRECT
414     ||  (retval == _CGA)
415 #endif
416     )
417         pdc_direct_video = FALSE;
418 
419     if ((unsigned)pdc_video_seg == 0xb000)
420         SP->mono = TRUE;
421     else
422         SP->mono = FALSE;
423 
424     /* Check for DESQview shadow buffer
425        thanks to [email protected] for the GO32 fix */
426 
427 #ifndef __WATCOMC__
428     regs.h.ah = 0xfe;
429     regs.h.al = 0;
430     regs.x.di = pdc_video_ofs;
431 # ifdef __DJGPP__
432     regs.x.es = pdc_video_seg;
433     __dpmi_int(0x10, &regs);
434     pdc_video_seg = regs.x.es;
435 # else
436     segs.es   = pdc_video_seg;
437     int86x(0x10, &regs, &regs, &segs);
438     pdc_video_seg = segs.es;
439 # endif
440     pdc_video_ofs = regs.x.di;
441 #endif
442     if (!pdc_adapter)
443         pdc_adapter = retval;
444 
445     return _sanity_check(retval);
446 }
447 
448 /* close the physical screen -- may restore the screen to its state
449    before PDC_scr_open(); miscellaneous cleanup */
450 
PDC_scr_close(void)451 void PDC_scr_close(void)
452 {
453 #if SMALL || MEDIUM
454 # ifndef __PACIFIC__
455     struct SREGS segregs;
456 # endif
457     int ds;
458 #endif
459     PDC_LOG(("PDC_scr_close() - called\n"));
460 
461     if (getenv("PDC_RESTORE_SCREEN") && saved_screen)
462     {
463 #ifdef __DJGPP__
464         dosmemput(saved_screen, saved_lines * saved_cols * 2,
465             (unsigned long)_FAR_POINTER(pdc_video_seg,
466             pdc_video_ofs));
467 #else
468 # if (SMALL || MEDIUM)
469 #  ifdef __PACIFIC__
470         ds = FP_SEG((void far *)saved_screen);
471 #  else
472         segread(&segregs);
473         ds = segregs.ds;
474 #  endif
475         movedata(ds, (int)saved_screen, pdc_video_seg, pdc_video_ofs,
476         (saved_lines * saved_cols * 2));
477 # else
478         memcpy((void *)_FAR_POINTER(pdc_video_seg, pdc_video_ofs),
479         (void *)saved_screen, (saved_lines * saved_cols * 2));
480 # endif
481 #endif
482         free(saved_screen);
483         saved_screen = NULL;
484     }
485 
486     reset_shell_mode();
487 
488     if (SP->visibility != 1)
489         curs_set(1);
490 
491     /* Position cursor to the bottom left of the screen. */
492 
493     PDC_gotoyx(PDC_get_rows() - 2, 0);
494 }
495 
PDC_scr_free(void)496 void PDC_scr_free(void)
497 {
498     if (SP)
499         free(SP);
500     if (pdc_atrtab)
501         free(pdc_atrtab);
502 
503     pdc_atrtab = (unsigned char *)NULL;
504 }
505 
506 /* open the physical screen -- allocate SP, miscellaneous intialization,
507    and may save the existing screen for later restoration */
508 
PDC_scr_open(int argc,char ** argv)509 int PDC_scr_open(int argc, char **argv)
510 {
511 #if SMALL || MEDIUM
512 # ifndef __PACIFIC__
513     struct SREGS segregs;
514 # endif
515     int ds;
516 #endif
517     int i;
518 
519     PDC_LOG(("PDC_scr_open() - called\n"));
520 
521     SP = calloc(1, sizeof(SCREEN));
522     pdc_atrtab = calloc(PDC_COLOR_PAIRS * PDC_OFFSET, 1);
523 
524     if (!SP || !pdc_atrtab)
525         return ERR;
526 
527     for (i = 0; i < 16; i++)
528         curstoreal[realtocurs[i]] = i;
529 
530     SP->orig_attr = FALSE;
531 
532     pdc_direct_video = TRUE; /* Assume that we can */
533     pdc_video_seg = 0xb000;  /* Base screen segment addr */
534     pdc_video_ofs = 0x0;     /* Base screen segment ofs */
535 
536     pdc_adapter = _query_adapter_type();
537     pdc_scrnmode = _get_scrn_mode();
538     pdc_font = _get_font();
539 
540     SP->lines = PDC_get_rows();
541     SP->cols = PDC_get_columns();
542 
543     SP->mouse_wait = PDC_CLICK_PERIOD;
544     SP->audible = TRUE;
545 
546     /* If the environment variable PDCURSES_BIOS is set, the DOS int10()
547        BIOS calls are used in place of direct video memory access. */
548 
549     if (getenv("PDCURSES_BIOS"))
550         pdc_direct_video = FALSE;
551 
552     /* This code for preserving the current screen. */
553 
554     if (getenv("PDC_RESTORE_SCREEN"))
555     {
556         saved_lines = SP->lines;
557         saved_cols = SP->cols;
558 
559         saved_screen = malloc(saved_lines * saved_cols * 2);
560 
561         if (!saved_screen)
562         {
563             SP->_preserve = FALSE;
564             return OK;
565         }
566 #ifdef __DJGPP__
567         dosmemget((unsigned long)_FAR_POINTER(pdc_video_seg, pdc_video_ofs),
568                   saved_lines * saved_cols * 2, saved_screen);
569 #else
570 # if SMALL || MEDIUM
571 #  ifdef __PACIFIC__
572         ds = FP_SEG((void far *) saved_screen);
573 #  else
574         segread(&segregs);
575         ds = segregs.ds;
576 #  endif
577         movedata(pdc_video_seg, pdc_video_ofs, ds, (int)saved_screen,
578                  (saved_lines * saved_cols * 2));
579 # else
580         memcpy((void *)saved_screen,
581                (void *)_FAR_POINTER(pdc_video_seg, pdc_video_ofs),
582                (saved_lines * saved_cols * 2));
583 # endif
584 #endif
585     }
586 
587     SP->_preserve = (getenv("PDC_PRESERVE_SCREEN") != NULL);
588 
589     return OK;
590 }
591 
592 /* the core of resize_term() */
593 
PDC_resize_screen(int nlines,int ncols)594 int PDC_resize_screen(int nlines, int ncols)
595 {
596     PDC_LOG(("PDC_resize_screen() - called. Lines: %d Cols: %d\n",
597              nlines, ncols));
598 
599     /* Trash the stored value of orig_cursor -- it's only good if the
600        video mode doesn't change */
601 
602     SP->orig_cursor = 0x0607;
603 
604     switch (pdc_adapter)
605     {
606     case _EGACOLOR:
607         if (nlines >= 43)
608             _set_font(_FONT8);
609         else
610             _set_80x25();
611         break;
612 
613     case _VGACOLOR:
614         if (nlines > 28)
615             _set_font(_FONT8);
616         else
617             if (nlines > 25)
618                 _set_font(_FONT14);
619             else
620                 _set_80x25();
621     }
622 
623     PDC_set_blink(COLORS == 8);
624 
625     return OK;
626 }
627 
PDC_reset_prog_mode(void)628 void PDC_reset_prog_mode(void)
629 {
630         PDC_LOG(("PDC_reset_prog_mode() - called.\n"));
631 }
632 
PDC_reset_shell_mode(void)633 void PDC_reset_shell_mode(void)
634 {
635         PDC_LOG(("PDC_reset_shell_mode() - called.\n"));
636 }
637 
PDC_restore_screen_mode(int i)638 void PDC_restore_screen_mode(int i)
639 {
640     if (i >= 0 && i <= 2)
641     {
642         pdc_font = _get_font();
643         _set_font(saved_font[i]);
644 
645         if (_get_scrn_mode() != saved_scrnmode[i])
646             _set_scrn_mode(saved_scrnmode[i]);
647     }
648 }
649 
PDC_save_screen_mode(int i)650 void PDC_save_screen_mode(int i)
651 {
652     if (i >= 0 && i <= 2)
653     {
654         saved_font[i] = pdc_font;
655         saved_scrnmode[i] = pdc_scrnmode;
656     }
657 }
658 
PDC_init_pair(short pair,short fg,short bg)659 void PDC_init_pair(short pair, short fg, short bg)
660 {
661     unsigned char att, temp_bg;
662     chtype i;
663 
664     fg = curstoreal[fg];
665     bg = curstoreal[bg];
666 
667     for (i = 0; i < PDC_OFFSET; i++)
668     {
669         att = fg | (bg << 4);
670 
671         if (i & (A_REVERSE >> PDC_ATTR_SHIFT))
672             att = bg | (fg << 4);
673         if (i & (A_UNDERLINE >> PDC_ATTR_SHIFT))
674             att = 1;
675         if (i & (A_INVIS >> PDC_ATTR_SHIFT))
676         {
677             temp_bg = att >> 4;
678             att = temp_bg << 4 | temp_bg;
679         }
680         if (i & (A_BOLD >> PDC_ATTR_SHIFT))
681             att |= 8;
682         if (i & (A_BLINK >> PDC_ATTR_SHIFT))
683             att |= 128;
684 
685         pdc_atrtab[pair * PDC_OFFSET + i] = att;
686     }
687 }
688 
PDC_pair_content(short pair,short * fg,short * bg)689 int PDC_pair_content(short pair, short *fg, short *bg)
690 {
691     *fg = realtocurs[pdc_atrtab[pair * PDC_OFFSET] & 0x0F];
692     *bg = realtocurs[(pdc_atrtab[pair * PDC_OFFSET] & 0xF0) >> 4];
693 
694     return OK;
695 }
696 
697 /* _egapal() - Find the EGA palette value (0-63) for the color (0-15).
698    On VGA, this is an index into the DAC. */
699 
_egapal(short color)700 static short _egapal(short color)
701 {
702     PDCREGS regs;
703 
704     regs.W.ax = 0x1007;
705     regs.h.bl = curstoreal[color];
706 
707     PDCINT(0x10, regs);
708 
709     return regs.h.bh;
710 }
711 
PDC_can_change_color(void)712 bool PDC_can_change_color(void)
713 {
714     return (pdc_adapter == _VGACOLOR);
715 }
716 
717 /* These are only valid when pdc_adapter == _VGACOLOR */
718 
PDC_color_content(short color,short * red,short * green,short * blue)719 int PDC_color_content(short color, short *red, short *green, short *blue)
720 {
721     PDCREGS regs;
722 
723     /* Read single DAC register */
724 
725     regs.W.ax = 0x1015;
726     regs.h.bl = _egapal(color);
727 
728     PDCINT(0x10, regs);
729 
730     /* Scale and store */
731 
732     *red = DIVROUND((unsigned)(regs.h.dh) * 1000, 63);
733     *green = DIVROUND((unsigned)(regs.h.ch) * 1000, 63);
734     *blue = DIVROUND((unsigned)(regs.h.cl) * 1000, 63);
735 
736     return OK;
737 }
738 
PDC_init_color(short color,short red,short green,short blue)739 int PDC_init_color(short color, short red, short green, short blue)
740 {
741     PDCREGS regs;
742 
743     /* Scale */
744 
745     regs.h.dh = DIVROUND((unsigned)red * 63, 1000);
746     regs.h.ch = DIVROUND((unsigned)green * 63, 1000);
747     regs.h.cl = DIVROUND((unsigned)blue * 63, 1000);
748 
749     /* Set single DAC register */
750 
751     regs.W.ax = 0x1010;
752     regs.W.bx = _egapal(color);
753 
754     PDCINT(0x10, regs);
755 
756     return OK;
757 }
758