libpayload: Add PDCurses and ncurses' libform/libmenu
[coreboot.git] / payloads / libpayload / curses / PDCurses-3.4 / dos / pdcscrn.c
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     -- frotz@dri.com    900730 */
48
49 /* _get_font() - Get the current font size */
50
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
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
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
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
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
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
281 static int _query_adapter_type(void)
282 {
283     PDCREGS regs;
284     int retval = _NONE;
285
286     /* thanks to paganini@ax.apc.org 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 paganini@ax.apc.org 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
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
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
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
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
628 void PDC_reset_prog_mode(void)
629 {
630         PDC_LOG(("PDC_reset_prog_mode() - called.\n"));
631 }
632
633 void PDC_reset_shell_mode(void)
634 {
635         PDC_LOG(("PDC_reset_shell_mode() - called.\n"));
636 }
637
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
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
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
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
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
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
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
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 }