Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / video / pcvt / i386 / pcvt_sup.c
1 /*
2  * Copyright (c) 1999 Hellmuth Michaelis
3  *
4  * Copyright (c) 1992, 1995 Hellmuth Michaelis and Joerg Wunsch.
5  *
6  * Copyright (c) 1992, 1993 Brian Dunford-Shore and Scott Turner.
7  *
8  * Copyright (C) 1992, 1993 Soeren Schmidt.
9  *
10  * All rights reserved.
11  *
12  * For the sake of compatibility, portions of this code regarding the
13  * X server interface are taken from Soeren Schmidt's syscons driver.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  * 3. All advertising materials mentioning features or use of this software
24  *    must display the following acknowledgement:
25  *      This product includes software developed by Hellmuth Michaelis,
26  *      Brian Dunford-Shore, Joerg Wunsch, Scott Turner and Soeren Schmidt.
27  * 4. The name authors may not be used to endorse or promote products
28  *    derived from this software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
31  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
33  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
34  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
35  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
39  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  */
41
42 /*---------------------------------------------------------------------------*
43  *
44  *      pcvt_sup.c      VT220 Driver Support Routines
45  *      ---------------------------------------------
46  *
47  *      Last Edit-Date: [Thu Dec 30 17:01:03 1999]
48  *
49  * $FreeBSD: src/sys/i386/isa/pcvt/pcvt_sup.c,v 1.16 1999/12/30 16:17:10 hm Exp $
50  *
51  *---------------------------------------------------------------------------*/
52
53 #include "vt.h"
54 #if NVT > 0
55
56 #include <i386/isa/pcvt/pcvt_hdr.h>     /* global include */
57
58 #include <sys/resource.h>
59
60 static void vid_cursor ( struct cursorshape *data );
61 static void vgasetfontattr ( struct vgafontattr *data );
62 static void vgagetfontattr ( struct vgafontattr *data );
63 static void vgaloadchar ( struct vgaloadchar *data );
64 static void vid_getscreen ( struct screeninfo *data, Dev_t dev );
65 static void vid_setscreen ( struct screeninfo *data, Dev_t dev );
66 static void setchargen ( void );
67 static void setchargen3 ( void );
68 static void resetchargen ( void );
69 static void vgareadpel ( struct vgapel *data, Dev_t dev );
70 static void vgawritepel ( struct vgapel *data, Dev_t dev );
71 static void vgapcvtid ( struct pcvtid *data );
72 static void vgapcvtinfo ( struct pcvtinfo *data );
73
74 #ifdef XSERVER
75 static unsigned char * compute_charset_base ( unsigned fontset );
76 #endif /* XSERVER */
77
78 static struct callout_handle async_update_ch =
79     CALLOUT_HANDLE_INITIALIZER(&async_update_ch);
80
81 #if PCVT_SCREENSAVER
82 static void scrnsv_timedout ( void *arg );
83 static struct callout_handle scrnsv_timeout_ch =
84     CALLOUT_HANDLE_INITIALIZER(&scrnsv_timeout_ch);
85 static u_short *savedscreen = (u_short *)0;     /* ptr to screen contents */
86 static size_t scrnsv_size = (size_t)-1;         /* size of saved image */
87
88 #ifndef XSERVER
89 static unsigned scrnsv_timeout = 0;             /* initially off */
90 static void pcvt_set_scrnsv_tmo ( int timeout );/* else declared global */
91 #endif /* XSERVER */
92
93 #if PCVT_PRETTYSCRNS
94 static u_short *scrnsv_current = (u_short *)0;  /* attention char ptr */
95 static struct callout_handle scrnsv_blink_ch =
96     CALLOUT_HANDLE_INITIALIZER(&scrnsv_blink_ch);
97 static void scrnsv_blink ( void * );
98 static u_short getrand ( void );
99 #endif /* PCVT_PRETTYSCRNS */
100
101 #endif /* PCVT_SCREENSAVER */
102
103
104 /*---------------------------------------------------------------------------*
105  *      execute vga ioctls
106  *---------------------------------------------------------------------------*/
107 int
108 vgaioctl(Dev_t dev, int cmd, caddr_t data, int flag)
109 {
110         if(minor(dev) >= PCVT_NSCREENS)
111                 return -1;
112
113 /*
114  * Some of the commands are not applicable if the vt in question, or the
115  * current vt is in graphics mode (i.e., the X server acts on it); they
116  * will cause an EAGAIN (resource temporarily unavailable) to be returned.
117  */
118
119 #ifdef XSERVER
120 #if PCVT_USL_VT_COMPAT
121 #define is_dev_grafx vs[minor(dev)].vt_status & VT_GRAFX
122 #define is_current_grafx vsp->vt_status & VT_GRAFX
123 #else   /* old X interface */
124 #define is_dev_grafx pcvt_xmode
125 #define is_current_grafx pcvt_xmode
126 #endif /* PCVT_USL_VT_COMPAT */
127 #else /* !XSERVER */
128 #define is_dev_grafx 0  /* not applicable */
129 #define is_current_grafx 0
130 #endif /* XSERVER */
131
132         switch(cmd)
133         {
134                 case VGACURSOR:
135                         if(is_current_grafx)
136                                 return EAGAIN;
137                         vid_cursor((struct cursorshape *)data);
138                         break;
139
140                 case VGALOADCHAR:
141                         if((adaptor_type != VGA_ADAPTOR) &&
142                            (adaptor_type != EGA_ADAPTOR))
143                                 return -1;
144                         if(is_current_grafx)
145                                 return EAGAIN;
146                         vgaloadchar((struct vgaloadchar *)data);
147                         break;
148
149                 case VGASETFONTATTR:
150                         if((adaptor_type != VGA_ADAPTOR) &&
151                            (adaptor_type != EGA_ADAPTOR))
152                                 return -1;
153
154 #if PCVT_SCREENSAVER
155                         pcvt_scrnsv_reset();
156 #endif /* PCVT_SCREENSAVER */
157
158                         vgasetfontattr((struct vgafontattr *)data);
159                         break;
160
161                 case VGAGETFONTATTR:
162                         if((adaptor_type != VGA_ADAPTOR) &&
163                            (adaptor_type != EGA_ADAPTOR))
164                                 return -1;
165                         vgagetfontattr((struct vgafontattr *)data);
166                         break;
167
168                 case VGASETSCREEN:
169
170 #if defined XSERVER && !PCVT_USL_VT_COMPAT
171                         /* avoid screen switch if using old X mode */
172                         if(is_dev_grafx)
173                                 return EAGAIN;
174 #endif /* XSERVER && !PCVT_USL_VT_COMPAT */
175
176 #if PCVT_SCREENSAVER
177                         pcvt_scrnsv_reset();
178 #endif /* PCVT_SCREENSAVER */
179
180                         vid_setscreen((struct screeninfo *)data, dev);
181                         break;
182
183                 case VGAGETSCREEN:
184                         vid_getscreen((struct screeninfo *)data, dev);
185                         break;
186
187                 case VGAREADPEL:
188                         if(adaptor_type != VGA_ADAPTOR)
189                                 return -1;
190                         if(is_dev_grafx)
191                                 return EAGAIN;
192                         vgareadpel((struct vgapel *)data, dev);
193                         break;
194
195                 case VGAWRITEPEL:
196                         if(adaptor_type != VGA_ADAPTOR)
197                                 return -1;
198                         if(is_dev_grafx)
199                                 return EAGAIN;
200                         vgawritepel((struct vgapel *)data, dev);
201                         break;
202
203 #if PCVT_SCREENSAVER
204                 case VGASCREENSAVER:
205                         if(is_current_grafx)
206                                 return EAGAIN;
207                         pcvt_set_scrnsv_tmo(*(int *)data);
208                         pcvt_scrnsv_reset();
209                         break;
210 #endif /* PCVT_SCREENSAVER */
211
212                 case VGAPCVTID:
213                         vgapcvtid((struct pcvtid *)data);
214                         break;
215
216                 case VGAPCVTINFO:
217                         vgapcvtinfo((struct pcvtinfo *)data);
218                         break;
219
220                 case VGASETCOLMS:
221                         if(is_dev_grafx)
222                                 return EAGAIN;
223                         if(*(int *)data == 80)
224                                 (void)vt_col(&vs[minor(dev)], SCR_COL80);
225                         else if(*(int *)data == 132)
226                         {
227                                 if(vt_col(&vs[minor(dev)], SCR_COL132) == 0)
228                                         return EINVAL; /* not a VGA */
229                         }
230                         else
231                                 return EINVAL;
232                         break;
233
234 #if 0                   
235                 case SETSCROLLSIZE:
236                         reallocate_scrollbuffer(vsp, *(u_short *)data);
237                         break;
238 #endif
239
240                 case TIOCSWINSZ:
241                         /* do nothing here */
242                         break;
243
244                 default:
245                         return -1;
246         }
247         return 0;
248
249 #undef is_dev_grafx
250 #undef is_current_grafx
251 }
252
253 /*---------------------------------------------------------------------------*
254  *      video ioctl - return driver id
255  *---------------------------------------------------------------------------*/
256 static void
257 vgapcvtid(struct pcvtid *data)
258 {
259         snprintf(data->name, sizeof(data->name), "%s", PCVTIDNAME);
260         data->rmajor    = PCVTIDMAJOR;
261         data->rminor    = PCVTIDMINOR;
262 }
263
264 /*---------------------------------------------------------------------------*
265  *      video ioctl - return driver compile time options data
266  *---------------------------------------------------------------------------*/
267 static void
268 vgapcvtinfo(struct pcvtinfo *data)
269 {
270 #if PCVT_NETBSD
271         data->opsys     = CONF_NETBSD;
272         data->opsysrel  = PCVT_NETBSD;
273 #elif PCVT_FREEBSD
274         data->opsys     = CONF_FREEBSD;
275         data->opsysrel  = PCVT_FREEBSD;
276 #else
277         data->opsys     = CONF_UNKNOWNOPSYS;
278         data->opsysrel  = 0;
279 #endif
280
281         data->nscreens  = PCVT_NSCREENS;
282         data->scanset   = PCVT_SCANSET;
283         data->updatefast= PCVT_UPDATEFAST;
284         data->updateslow= PCVT_UPDATESLOW;
285         data->sysbeepf  = PCVT_SYSBEEPF;
286
287 #if PCVT_NETBSD || PCVT_FREEBSD >= 200
288         data->pcburst   = PCVT_PCBURST;
289 #else
290         data->pcburst   = 1;
291 #endif
292
293 #if PCVT_KBD_FIFO
294         data->kbd_fifo_sz = PCVT_KBD_FIFO_SZ;
295 #else
296         data->kbd_fifo_sz = 0;
297 #endif
298
299         data->compile_opts = (0
300
301 #if PCVT_VT220KEYB
302         | CONF_VT220KEYB
303 #endif
304 #if PCVT_SCREENSAVER
305         | CONF_SCREENSAVER
306 #endif
307 #if PCVT_PRETTYSCRNS
308         | CONF_PRETTYSCRNS
309 #endif
310 #if PCVT_CTRL_ALT_DEL
311         | CONF_CTRL_ALT_DEL
312 #endif
313 #if PCVT_USEKBDSEC
314         | CONF_USEKBDSEC
315 #endif
316 #if PCVT_24LINESDEF
317         | CONF_24LINESDEF
318 #endif
319 #if PCVT_EMU_MOUSE
320         | CONF_EMU_MOUSE
321 #endif
322 #if PCVT_SHOWKEYS
323         | CONF_SHOWKEYS
324 #endif
325 #if PCVT_KEYBDID
326         | CONF_KEYBDID
327 #endif
328 #if PCVT_SIGWINCH
329         | CONF_SIGWINCH
330 #endif
331 #if PCVT_NULLCHARS
332         | CONF_NULLCHARS
333 #endif
334 #if PCVT_BACKUP_FONTS
335         | CONF_BACKUP_FONTS
336 #endif
337 #if PCVT_SW0CNOUTP      /* was FORCE8BIT */
338         | CONF_SW0CNOUTP
339 #endif
340 #if PCVT_SETCOLOR
341         | CONF_SETCOLOR
342 #endif
343 #if PCVT_132GENERIC
344         | CONF_132GENERIC
345 #endif
346 #if PCVT_PALFLICKER
347         | CONF_PALFLICKER
348 #endif
349 #if PCVT_WAITRETRACE
350         | CONF_WAITRETRACE
351 #endif
352 #ifdef XSERVER
353         | CONF_XSERVER
354 #endif
355 #if PCVT_USL_VT_COMPAT
356         | CONF_USL_VT_COMPAT
357 #endif
358 #if PCVT_PORTIO_DELAY
359         | CONF_PORTIO_DELAY
360 #endif
361 #if PCVT_INHIBIT_NUMLOCK
362         | CONF_INHIBIT_NUMLOCK
363 #endif
364 #if PCVT_META_ESC
365         | CONF_META_ESC
366 #endif
367 #if PCVT_KBD_FIFO
368         | CONF_KBD_FIFO
369 #endif
370 #if PCVT_NOFASTSCROLL
371         | CONF_NOFASTSCROLL
372 #endif
373 #if PCVT_SLOW_INTERRUPT
374         | CONF_SLOW_INTERRUPT
375 #endif
376 #if PCVT_NO_LED_UPDATE
377         | CONF_NO_LED_UPDATE
378 #endif
379         );
380 }
381
382 /*---------------------------------------------------------------------------*
383  *      video ioctl - set cursor appearence
384  *---------------------------------------------------------------------------*/
385 static void
386 vid_cursor(struct cursorshape *data)
387 {
388         int screen;
389         int start;
390         int end;
391         int line_height;
392         int character_set;
393
394         /* for which virtual screen, -1 for current */
395         screen = data->screen_no;
396
397         if(screen == -1)          /* current ? */
398                 screen = current_video_screen;
399         else if(screen > totalscreens - 1)
400                 screen = totalscreens - 1;
401         else if(screen < 0)
402                 screen = 0;
403
404         if(adaptor_type == VGA_ADAPTOR || adaptor_type == EGA_ADAPTOR)
405         {
406                 character_set = vs[screen].vga_charset;
407                 character_set = (character_set < 0) ? 0 :
408                         ((character_set < totalfonts) ?
409                          character_set :
410                          totalfonts-1);
411
412                 line_height = vgacs[character_set].char_scanlines & 0x1F;
413         }
414         else if(adaptor_type == MDA_ADAPTOR)
415         {
416                 line_height = 14;
417         }
418         else
419         {
420                 line_height = 8;        /* CGA */
421         }
422
423         start = (data->start < 0) ? 0 :
424                 ((data->start > line_height) ? line_height : data->start);
425
426         if((vga_family == VGA_F_TRI) && (start == 0))
427                 start = 1;
428
429         end = (data->end < 0) ? 0 :
430                 ((data->end > line_height) ? line_height : data->end);
431
432         vs[screen].cursor_start = start;
433         vs[screen].cursor_end = end;
434
435         if(screen == current_video_screen)
436         {
437                 outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
438                 outb(addr_6845+1, start);
439                 outb(addr_6845,CRTC_CUREND);    /* cursor end reg */
440                 outb(addr_6845+1, end);
441         }
442 }
443
444 /*---------------------------------------------------------------------------*
445  *      ega/vga ioctl - set font attributes
446  *---------------------------------------------------------------------------*/
447 static void
448 vgasetfontattr(struct vgafontattr *data)
449 {
450         register int i;
451         int vga_character_set;
452         int lines_per_character;
453         int totscanlines;
454         int size;
455
456         vga_character_set = data->character_set;
457         vga_character_set = (vga_character_set < 0) ? 0 :
458                 ((vga_character_set < totalfonts) ?
459                 vga_character_set : totalfonts-1);
460
461         vgacs[vga_character_set].loaded = data->font_loaded;
462
463         /* Limit Characters to 32 scanlines doubled */
464         vgacs[vga_character_set].char_scanlines =
465                 (data->character_scanlines & 0x1F)
466                 | 0x40; /* always set bit 9 of line cmp reg */
467
468         if(adaptor_type == EGA_ADAPTOR)
469                 /* ...and screen height to scan 350 lines */
470                 vgacs[vga_character_set].scr_scanlines =
471                 (data->screen_scanlines > 0x5d) ?
472                 0x5d : data->screen_scanlines;
473         else
474                 /* ...and screen height to scan 480 lines */
475                 vgacs[vga_character_set].scr_scanlines =
476                 (data->screen_scanlines > 0xdF) ?
477                 0xdF : data->screen_scanlines;
478
479         lines_per_character =
480                 (int)(0x1F & vgacs[vga_character_set].char_scanlines)+1;
481
482         totscanlines = 0x101 + (int)vgacs[vga_character_set].scr_scanlines;
483
484         size = data->screen_size;
485
486         if(adaptor_type == EGA_ADAPTOR)
487         {
488                 switch(size)
489                 {
490                         case SIZ_25ROWS: /* This case is always OK */
491                                 break;
492
493                         case SIZ_35ROWS:
494                                 if(totscanlines/lines_per_character >= 35)
495                                         size = SIZ_35ROWS;
496                                 else
497                                         size = SIZ_25ROWS;
498                                 break;
499
500                         case SIZ_43ROWS:
501                         default:
502                                 if(totscanlines/lines_per_character >= 43)
503                                         size = SIZ_43ROWS;
504                                 else if(totscanlines/lines_per_character >= 35)
505                                         size = SIZ_35ROWS;
506                                 else
507                                         size = SIZ_25ROWS;
508                                 break;
509                 }
510         }
511         else
512         {
513                 switch(size)
514                 {
515                         case SIZ_25ROWS: /* This case is always OK */
516                                 break;
517
518                         case SIZ_28ROWS:
519                                 if(totscanlines/lines_per_character >= 28)
520                                         size = SIZ_28ROWS;
521                                 else
522                                         size = SIZ_25ROWS;
523                                 break;
524
525                         case SIZ_40ROWS:
526                                 if(totscanlines/lines_per_character >= 40)
527                                         size = SIZ_40ROWS;
528                                 else if(totscanlines/lines_per_character >= 28)
529                                         size = SIZ_28ROWS;
530                                 else
531                                         size = SIZ_25ROWS;
532                                 break;
533
534                         case SIZ_50ROWS:
535                         default:
536                                 if(totscanlines/lines_per_character >= 50)
537                                         size = SIZ_50ROWS;
538                                 else if(totscanlines/lines_per_character >= 40)
539                                         size = SIZ_40ROWS;
540                                 else if(totscanlines/lines_per_character >= 28)
541                                         size = SIZ_28ROWS;
542                                 else
543                                         size = SIZ_25ROWS;
544                         break;
545                 }
546         }
547
548         vgacs[vga_character_set].screen_size = size;
549
550         for (i = 0;i < PCVT_NSCREENS;i++)
551         {
552                 if(vga_character_set == vs[i].vga_charset)
553                         set_charset(&(vs[i]),vga_character_set);
554         }
555
556 #if !PCVT_USL_VT_COMPAT
557         vgapage(current_video_screen);
558 #else
559         switch_screen(current_video_screen, 0, 0);
560 #endif /* !PCVT_USL_VT_COMPAT */
561
562 }
563
564 /*---------------------------------------------------------------------------*
565  *      ega/vga ioctl - get font attributes
566  *---------------------------------------------------------------------------*/
567 static void
568 vgagetfontattr(struct vgafontattr *data)
569 {
570         int vga_character_set;
571
572         vga_character_set = data->character_set;
573         vga_character_set = (vga_character_set < 0) ? 0 :
574                 ((vga_character_set < (int)totalfonts) ?
575                  vga_character_set :
576                  (int)(totalfonts-1));
577
578         data->character_set = (int)vga_character_set;
579
580         data->font_loaded = (int)vgacs[vga_character_set].loaded;
581
582         data->character_scanlines =
583                 (int)vgacs[vga_character_set].char_scanlines
584                 & 0x1f;         /* do not display the overflow bits */
585
586         data->screen_scanlines = (int)vgacs[vga_character_set].scr_scanlines;
587
588         data->screen_size = (int)vgacs[vga_character_set].screen_size;
589 }
590
591 /*---------------------------------------------------------------------------*
592  *      ega/vga ioctl - load a character shape into character set
593  *---------------------------------------------------------------------------*/
594 static void
595 vgaloadchar(struct vgaloadchar *data)
596 {
597         int vga_character_set;
598         int character;
599         int lines_per_character;
600
601         vga_character_set = data->character_set;
602         vga_character_set = (vga_character_set < 0) ? 0 :
603                 ((vga_character_set < (int)totalfonts) ?
604                  vga_character_set : (int)(totalfonts-1));
605
606         character = (data->character < 0) ? 0 :
607                 ((data->character > 255) ? 255 : data->character);
608
609         lines_per_character = (int)data->character_scanlines;
610         lines_per_character = (lines_per_character < 0) ? 0 :
611                 ((lines_per_character > 32) ? 32 : lines_per_character);
612
613         loadchar(vga_character_set,character,lines_per_character,
614                  data->char_table);
615 }
616
617 /*---------------------------------------------------------------------------*
618  *      video ioctl - get screen information
619  *---------------------------------------------------------------------------*/
620 static void
621 vid_getscreen(struct screeninfo *data, Dev_t dev)
622 {
623         int device = minor(dev);
624         data->adaptor_type = adaptor_type;      /* video adapter installed */
625         data->monitor_type = color;             /* monitor type installed */
626         data->totalfonts = totalfonts;          /* no of downloadble fonts */
627         data->totalscreens = totalscreens;      /* no of virtual screens */
628         data->screen_no = device;               /* this screen number */
629         data->current_screen = current_video_screen; /* displayed screen no */
630         /* screen size */
631         data->screen_size = vgacs[(vs[device].vga_charset)].screen_size;
632         /* pure VT mode or HP/VT mode */
633         data->pure_vt_mode = vs[device].vt_pure_mode;
634         data->vga_family = vga_family;          /* manufacturer, family */
635         data->vga_type = vga_type;              /* detected chipset type */
636         data->vga_132 = can_do_132col;          /* 132 column support */
637         data->force_24lines = vs[device].force24; /* force 24 lines */
638 }
639
640 /*---------------------------------------------------------------------------*
641  *      video ioctl - set screen information
642  *---------------------------------------------------------------------------*/
643 static void
644 vid_setscreen(struct screeninfo *data, Dev_t dev)
645 {
646         int screen;
647
648         if(data->current_screen == -1)
649         {
650                 screen = minor(dev);
651         }
652         else
653         {
654                 if(data->current_screen >= PCVT_NSCREENS)
655                         return;                                 /* XXXXXX */
656                 screen = data->current_screen;
657         }
658
659         vgapage(screen);
660
661 #if defined XSERVER && PCVT_USL_VT_COMPAT
662         {
663                 int x = spltty(), waitfor = screen + 1;
664                 /* if the vt is yet to be released by a process, wait here */
665                 if(vs[screen].vt_status & VT_WAIT_REL)
666                         (void)usl_vt_ioctl(dev, VT_WAITACTIVE,
667                                            (caddr_t)&waitfor, 0, 0);
668                 splx(x);
669         }
670         /* make sure the switch really happened */
671         if(screen != current_video_screen)
672                 return;         /* XXX should say "EAGAIN" here */
673 #endif /* defined XSERVER && PCVT_USL_VT_COMPAT */
674
675         if((data->screen_size != -1) || (data->force_24lines != -1))
676         {
677                 if(data->screen_size == -1)
678                         data->screen_size =
679                                 vgacs[(vs[screen].vga_charset)].screen_size;
680
681                 if(data->force_24lines != -1)
682                 {
683                         vs[screen].force24 = data->force_24lines;
684
685                         if(vs[screen].force24)
686                         {
687                                 swritefkl(2,(u_char *)"FORCE24 ENABLE *",
688                                           &vs[screen]);
689                         }
690                         else
691                         {
692                                 swritefkl(2,(u_char *)"FORCE24 ENABLE  ",
693                                           &vs[screen]);
694                         }
695                 }
696
697                 if((data->screen_size == SIZ_25ROWS) ||
698                    (data->screen_size == SIZ_28ROWS) ||
699                    (data->screen_size == SIZ_35ROWS) ||
700                    (data->screen_size == SIZ_40ROWS) ||
701                    (data->screen_size == SIZ_43ROWS) ||
702                    (data->screen_size == SIZ_50ROWS))
703                 {
704                         if(data->screen_no == -1)
705                                 set_screen_size(vsp, data->screen_size);
706                         else
707                                 set_screen_size(&vs[minor(dev)],
708                                                 data->screen_size);
709                 }
710         }
711
712         if(data->pure_vt_mode != -1)
713         {
714                 if((data->pure_vt_mode == M_HPVT) ||
715                    (data->pure_vt_mode == M_PUREVT))
716                 {
717                         if(data->screen_no == -1)
718                                 set_emulation_mode(vsp, data->pure_vt_mode);
719                         else
720                                 set_emulation_mode(&vs[minor(dev)],
721                                                    data->pure_vt_mode);
722                 }
723         }
724 }
725
726 /*---------------------------------------------------------------------------*
727  *      set screen size/resolution for a virtual screen
728  *---------------------------------------------------------------------------*/
729 void
730 set_screen_size(struct video_state *svsp, int size)
731 {
732         int i;
733
734         for(i = 0; i < totalfonts; i++)
735         {
736                 if(vgacs[i].screen_size == size)
737                 {
738                         set_charset(svsp, i);
739                         clr_parms(svsp);        /* escape parameter init */
740                         svsp->state = STATE_INIT; /* initial state */
741                         svsp->scrr_beg = 0;     /* start of scrolling region */
742                         svsp->sc_flag = 0;      /* invalidate saved cursor
743                                                  * position */
744                         svsp->transparent = 0;  /* disable control code
745                                                  * processing */
746
747                         /* Update tty to reflect screen size */
748
749                         if (svsp->vs_tty)
750                         {
751                                 svsp->vs_tty->t_winsize.ws_col = svsp->maxcol;
752                                 svsp->vs_tty->t_winsize.ws_xpixel =
753                                         (svsp->maxcol == 80)? 720: 1056;
754                                 svsp->vs_tty->t_winsize.ws_ypixel = 400;
755                                 svsp->vs_tty->t_winsize.ws_row =
756                                         svsp->screen_rows;
757                         }
758                         /* screen_rows already calculated in set_charset() */
759                         if(svsp->vt_pure_mode == M_HPVT && svsp->labels_on)
760                         {
761                                 if(svsp->which_fkl == SYS_FKL)
762                                         sw_sfkl(svsp);
763                                 else if(svsp->which_fkl == USR_FKL)
764                                         sw_ufkl(svsp);
765                         }
766
767
768                         svsp->scrr_len = svsp->screen_rows;
769                         svsp->scrr_end = svsp->scrr_len - 1;
770
771 #if PCVT_SIGWINCH
772                         if (svsp->vs_tty && svsp->vs_tty->t_pgrp)
773                                 pgsignal(svsp->vs_tty->t_pgrp, SIGWINCH, 1);
774 #endif /* PCVT_SIGWINCH */
775
776                         reallocate_scrollbuffer(svsp, svsp->scrollback_pages);
777                         break;
778                 }
779         }
780 }
781
782 /*---------------------------------------------------------------------------*
783  *      resize the scrollback buffer to the specified number of "pages"
784  *---------------------------------------------------------------------------*/
785 void
786 reallocate_scrollbuffer(struct video_state *svsp, int pages)
787 {
788         int s;
789         u_short *stmp;
790         
791         if(pages < 2)
792                 pages = 2;
793         if(pages > 50)
794                 pages = 50;
795
796         s = splhigh();
797
798         if((stmp = (u_short *)malloc(svsp->maxcol * svsp->screen_rows *
799                         pages * CHR, M_DEVBUF, M_NOWAIT)) == NULL)
800         {
801                 splx(s);
802                 printf("pcvt: reallocate_scrollbuffer, malloc failed\n");
803                 return;
804         }
805
806         svsp->max_off = svsp->screen_rows * pages - 1;
807         
808         if(svsp->Scrollback)
809         {
810                 bcopy(svsp->Scrollback, stmp,
811                         (min(pages, svsp->scrollback_pages)) *
812                         svsp->screen_rows * svsp->maxcol * CHR);
813                 free(svsp->Scrollback, M_DEVBUF);
814                 svsp->Scrollback = stmp;
815         }
816         else
817         {
818                 svsp->scr_offset = 0;
819                 svsp->scrolling = 0;
820                 svsp->Scrollback = stmp;
821
822                 bcopy(svsp->Crtat, svsp->Scrollback,
823                         svsp->screen_rows * svsp->maxcol * CHR);
824
825                 svsp->scr_offset = svsp->row;
826         }
827
828         svsp->scrollback_pages = pages;
829
830         splx(s);
831 }
832
833 /*---------------------------------------------------------------------------*
834  *      VGA ioctl - read DAC palette entry
835  *---------------------------------------------------------------------------*/
836 static void
837 vgareadpel(struct vgapel *data, Dev_t dev)
838 {
839         register unsigned vpage = minor(dev);
840         register unsigned idx = data->idx;
841
842         if(idx >= NVGAPEL)
843                 return;         /* no such entry */
844
845         /* do not read VGA palette directly, use saved values */
846         data->r = vs[vpage].palette[idx].r;
847         data->g = vs[vpage].palette[idx].g;
848         data->b = vs[vpage].palette[idx].b;
849 }
850
851 /*---------------------------------------------------------------------------*
852  *      VGA ioctl - write DAC palette entry
853  *---------------------------------------------------------------------------*/
854 static void
855 vgawritepel(struct vgapel *data, Dev_t dev)
856 {
857         register unsigned vpage = minor(dev);
858         register unsigned idx = data->idx;
859
860         if(idx >= NVGAPEL)
861                 return;         /* no such entry */
862
863         /* first, update saved values for this video screen */
864         vs[vpage].palette[idx].r = data->r;
865         vs[vpage].palette[idx].g = data->g;
866         vs[vpage].palette[idx].b = data->b;
867
868         /* if this happens on active screen, update VGA DAC, too */
869         if(vpage == current_video_screen)
870                 vgapaletteio(idx, &vs[vpage].palette[idx], 1);
871 }
872
873 /*---------------------------------------------------------------------------*
874  *      VGA physical IO - read/write one palette entry
875  *---------------------------------------------------------------------------*/
876 void
877 vgapaletteio(unsigned idx, struct rgb *val, int writeit)
878 {
879
880 #if PCVT_PALFLICKER
881         vga_screen_off();
882 #endif /* PCVT_PALFLICKER */
883
884         if(writeit)
885         {
886                 outb(VGA_DAC + 2, idx);
887
888 #if PCVT_WAITRETRACE
889                 wait_retrace();
890 #endif /* PCVT_WAITRETRACE */
891
892                 outb(VGA_DAC + 3, val->r & VGA_PMSK);
893
894 #if PCVT_WAITRETRACE
895                 wait_retrace();
896 #endif /* PCVT_WAITRETRACE */
897
898                 outb(VGA_DAC + 3, val->g & VGA_PMSK);
899
900 #if PCVT_WAITRETRACE
901                 wait_retrace();
902 #endif /* PCVT_WAITRETRACE */
903
904                 outb(VGA_DAC + 3, val->b & VGA_PMSK);
905         }
906         else    /* read it */
907         {
908                 outb(VGA_DAC + 1, idx);
909
910 #if PCVT_WAITRETRACE
911                 wait_retrace();
912 #endif /* PCVT_WAITRETRACE */
913
914                 val->r = inb(VGA_DAC + 3) & VGA_PMSK;
915
916 #if PCVT_WAITRETRACE
917                 wait_retrace();
918 #endif /* PCVT_WAITRETRACE */
919
920                 val->g = inb(VGA_DAC + 3) & VGA_PMSK;
921
922 #if PCVT_WAITRETRACE
923                 wait_retrace();
924 #endif /* PCVT_WAITRETRACE */
925
926                 val->b = inb(VGA_DAC + 3) & VGA_PMSK;
927         }
928
929 #if PCVT_PALFLICKER
930         vga_screen_on();
931 #endif /* PCVT_PALFLICKER */
932
933 }
934
935 /*---------------------------------------------------------------------------*
936  *
937  *      update asynchronous: cursor, cursor pos displ, sys load, keyb scan
938  *
939  *      arg is:
940  *              UPDATE_START = do update; requeue
941  *              UPDATE_STOP  = suspend updates
942  *              UPDATE_KERN  = do update for kernel printfs
943  *
944  *---------------------------------------------------------------------------*/
945 void
946 async_update(void *arg)
947 {
948         static int lastpos = 0;
949         static int counter = PCVT_UPDATESLOW;
950
951 #ifdef XSERVER
952         /* need a method to suspend the updates */
953
954         if(arg == UPDATE_STOP)
955         {
956                 untimeout(async_update, UPDATE_START, async_update_ch);
957                 return;
958         }
959 #endif /* XSERVER */
960
961         /* first check if update is possible */
962
963         if(chargen_access               /* does no-one load characters? */
964 #ifdef XSERVER                          /* is vt0 not in graphics mode? */
965 #if !PCVT_USL_VT_COMPAT
966            || pcvt_xmode                /* XXX necessary ????? */
967 #endif /* PCVT_USL_VT_COMPAT */
968 #endif /* XSERVER */
969            )
970         {
971                 goto async_update_exit; /* do not update anything */
972         }
973
974 #if PCVT_SCREENSAVER
975         if(reset_screen_saver && (counter == PCVT_UPDATESLOW))
976         {
977                 pcvt_scrnsv_reset();    /* yes, do it */
978                 reset_screen_saver = 0; /* re-init */
979         }
980         else if(scrnsv_active)          /* is the screen not blanked? */
981         {
982                 goto async_update_exit; /* do not update anything */
983         }
984 #endif /* PCVT_SCREENSAVER */
985
986         /*-------------------------------------------------------------------*/
987         /* this takes place on EVERY virtual screen (if not in X mode etc...)*/
988         /*-------------------------------------------------------------------*/
989
990         if ( cursor_pos_valid &&
991             (lastpos != (vsp->Crtat + vsp->cur_offset - Crtat)))
992         {
993                 lastpos = vsp->Crtat + vsp->cur_offset - Crtat;
994                 outb(addr_6845, CRTC_CURSORH);  /* high register */
995                 outb(addr_6845+1, ((lastpos) >> 8));
996                 outb(addr_6845, CRTC_CURSORL);  /* low register */
997                 outb(addr_6845+1, (lastpos));
998         }
999
1000         if (arg == UPDATE_KERN)         /* Magic arg: for kernel printfs */
1001                 return;
1002
1003         if(--counter)                   /* below is possible update */
1004                 goto async_update_exit; /*  just now and then ..... */
1005         counter = PCVT_UPDATESLOW;      /* caution, see screensaver above !! */
1006
1007         /*-------------------------------------------------------------------*/
1008         /* this takes place ONLY on screen 0 if in HP mode, labels on, !X    */
1009         /*-------------------------------------------------------------------*/
1010
1011         /* additional processing for HP necessary ? */
1012
1013         if((vs[0].vt_pure_mode == M_HPVT) && (vs[0].labels_on))
1014         {
1015                 static volatile u_char buffer[] =
1016                        "System Load: 1min: 0.00 5min: 0.00 15min: 0.00";
1017                 register int tmp, i;
1018 #if PCVT_SHOWKEYS
1019                 extern u_char rawkeybuf[80];
1020
1021                 if(keyboard_show)
1022                 {
1023                         for(i = 0; i < 80; i++)
1024                         {
1025                                 *((vs[0].Crtat+((vs[0].screen_rows+2)
1026                                         * vs[0].maxcol))+i) =
1027                                  user_attr | rawkeybuf[i];
1028                         }
1029                 }
1030                 else
1031                 {
1032 #endif  /* PCVT_SHOWKEYS */
1033
1034                 /* display load averages in last line (taken from tty.c) */
1035                         i = 18;
1036 #ifdef NEW_AVERUNNABLE
1037                         tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2)
1038                                 >> FSHIFT;
1039 #else
1040                         tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT;
1041 #endif
1042
1043                         buffer[i++] =
1044                                 ((((tmp/100)/10) == 0) ?
1045                                  ' ' :
1046                                  ((tmp/100)/10) + '0');
1047                         buffer[i++] = ((tmp/100)%10) + '0';
1048                         buffer[i++] = '.';
1049                         buffer[i++] = ((tmp%100)/10) + '0';
1050                         buffer[i++] = ((tmp%100)%10) + '0';
1051                         i += 6;
1052 #ifdef NEW_AVERUNNABLE
1053                         tmp = (averunnable.ldavg[1] * 100 + FSCALE / 2)
1054                                 >> FSHIFT;
1055 #else
1056                         tmp = (averunnable[1] * 100 + FSCALE / 2) >> FSHIFT;
1057 #endif
1058                         buffer[i++] = ((((tmp/100)/10) == 0) ?
1059                                        ' ' :
1060                                        ((tmp/100)/10) + '0');
1061                         buffer[i++] = ((tmp/100)%10) + '0';
1062                         buffer[i++] = '.';
1063                         buffer[i++] = ((tmp%100)/10) + '0';
1064                         buffer[i++] = ((tmp%100)%10) + '0';
1065                         i += 7;
1066 #ifdef NEW_AVERUNNABLE
1067                         tmp = (averunnable.ldavg[2] * 100 + FSCALE / 2)
1068                                 >> FSHIFT;
1069 #else
1070                         tmp = (averunnable[2] * 100 + FSCALE / 2) >> FSHIFT;
1071 #endif
1072                         buffer[i++] = ((((tmp/100)/10) == 0) ?
1073                                        ' ' :
1074                                        ((tmp/100)/10) + '0');
1075                         buffer[i++] = ((tmp/100)%10) + '0';
1076                         buffer[i++] = '.';
1077                         buffer[i++] = ((tmp%100)/10) + '0';
1078                         buffer[i++] = ((tmp%100)%10) + '0';
1079                         buffer[i] = '\0';
1080
1081                         for(i = 0; buffer[i]; i++)
1082                         {
1083                                 *((vs[0].Crtat +
1084                                    ((vs[0].screen_rows + 2) * vs[0].maxcol)
1085                                    ) + i
1086                                   ) = user_attr | buffer[i];
1087                         }
1088
1089 #if PCVT_SHOWKEYS
1090                         for(; i < 77; i++)
1091                         {
1092                                 *((vs[0].Crtat +
1093                                    ((vs[0].screen_rows + 2) * vs[0].maxcol)
1094                                    ) + i
1095                                   ) = user_attr | ' ';
1096                         }
1097
1098                 }
1099 #endif  /* PCVT_SHOWKEYS */
1100         }
1101
1102         /*-------------------------------------------------------------------*/
1103         /* this takes place on EVERY screen which is in HP mode, labels on,!X*/
1104         /*-------------------------------------------------------------------*/
1105
1106         if((vsp->vt_pure_mode == M_HPVT) && (vsp->labels_on))
1107         {
1108                 register int col = vsp->col+1;
1109                 register u_short *p = vsp->Crtat +
1110                                 (vsp->screen_rows * vsp->maxcol);
1111
1112                 /* update column display between labels */
1113
1114                 if(vsp->maxcol == SCR_COL132)
1115                 {
1116                         p += (SCR_COL132 - SCR_COL80)/2;
1117
1118                         if(col >= 100)
1119                         {
1120                                 *(p + LABEL_COLU) = user_attr | '1';
1121                                 col -= 100;
1122                         }
1123                         else
1124                         {
1125                                 *(p + LABEL_COLU) = user_attr | '0';
1126                         }
1127                 }
1128                 *(p + LABEL_COLH) = user_attr | ((col/10) + '0');
1129                 *(p + LABEL_COLL) = user_attr | ((col%10) + '0');
1130
1131                 /* update row display between labels */
1132
1133                 *(p + LABEL_ROWH) = (user_attr | (((vsp->row+1)/10) + '0'));
1134                 *(p + LABEL_ROWL) = (user_attr | (((vsp->row+1)%10) + '0'));
1135         }
1136
1137 async_update_exit:
1138
1139         if(arg == UPDATE_START)
1140         {
1141            async_update_ch = timeout(async_update, UPDATE_START,
1142                                      PCVT_UPDATEFAST);
1143         }
1144 }
1145
1146 /*---------------------------------------------------------------------------*
1147  *      set character set for virtual screen
1148  *---------------------------------------------------------------------------*/
1149 void
1150 set_charset(struct video_state *svsp, int curvgacs)
1151 {
1152         static int sizetab[] = { 25, 28, 35, 40, 43, 50 };
1153         int oldsize, oldrows, newsize, newrows;
1154
1155         if((curvgacs < 0) || (curvgacs > (NVGAFONTS-1)))
1156                 return;
1157
1158         svsp->vga_charset = curvgacs;
1159
1160         select_vga_charset(curvgacs);
1161
1162         oldsize = svsp->screen_rowsize;
1163         oldrows = svsp->screen_rows;
1164         newsize = sizetab[(vgacs[curvgacs].screen_size)];
1165         newrows = newsize;
1166         if (svsp->vt_pure_mode == M_HPVT)
1167                 newrows -= 3;
1168         if (newrows == 25 && svsp->force24)
1169                 newrows = 24;
1170         if (newrows < oldrows) {
1171                 int nscroll = svsp->row + 1 - newrows;
1172
1173                 if (svsp->row >= oldrows) /* Sanity check */
1174                         nscroll = oldrows - newrows;
1175                 if (nscroll > 0) {
1176                         /* Scroll up */
1177                         bcopy (svsp->Crtat + nscroll * svsp->maxcol,
1178                                svsp->Crtat,
1179                                newrows * svsp->maxcol * CHR);
1180                         svsp->row -= nscroll;
1181                         svsp->cur_offset -= nscroll * svsp->maxcol;
1182                 }
1183                 if (newrows < newsize)
1184                         fillw(user_attr | ' ',
1185                               svsp->Crtat + newrows * svsp->maxcol,
1186                               (newsize - newrows) * svsp->maxcol);
1187         } else if (oldrows < newsize)
1188                 fillw(user_attr | ' ',
1189                       svsp->Crtat + oldrows * svsp->maxcol,
1190                       (newsize - oldrows) * svsp->maxcol);
1191
1192         svsp->screen_rowsize = newsize;
1193         svsp->screen_rows = newrows;
1194
1195         /* Clip scrolling region */
1196         if(svsp->scrr_end > svsp->screen_rows - 1)
1197                 svsp->scrr_end = svsp->screen_rows - 1;
1198         svsp->scrr_len = svsp->scrr_end - svsp->scrr_beg + 1;
1199
1200         /* Clip cursor pos */
1201
1202         if(svsp->cur_offset > (svsp->scrr_len * svsp->maxcol))
1203                 svsp->cur_offset = (svsp->scrr_len * svsp->maxcol) + svsp->col;
1204 }
1205
1206 /*---------------------------------------------------------------------------*
1207  *      select a vga character set
1208  *---------------------------------------------------------------------------*/
1209 void
1210 select_vga_charset(int vga_charset)
1211 {
1212         int first, second;
1213         int fflag = 0;
1214         int sflag = 0;
1215         u_char cmap = 0;
1216
1217         static u_char cmaptaba[] =
1218                 {0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13};
1219
1220         static u_char cmaptabb[] =
1221                 {0x00, 0x04, 0x08, 0x0c, 0x20, 0x24, 0x28, 0x2c};
1222
1223         if((adaptor_type != EGA_ADAPTOR) && (adaptor_type != VGA_ADAPTOR))
1224                 return;
1225
1226         if((vga_charset < 0) || (vga_charset >= totalfonts))
1227                 return;
1228
1229         if(!vgacs[vga_charset].loaded)
1230                 return;
1231
1232         /*--------------------------------------------------------------
1233            find the the first and second charset of a given resolution.
1234            the first is used for lower 256 and the second (if any) is
1235            used for the upper 256 entries of a complete 512 entry ega/
1236            vga charset.
1237         --------------------------------------------------------------*/
1238
1239         for(first = 0; first < totalfonts; first++)
1240         {
1241                 if(!vgacs[first].loaded)
1242                         continue;
1243                 if(vgacs[first].screen_size != vgacs[vga_charset].screen_size)
1244                         continue;
1245                 if(vgacs[first].char_scanlines !=
1246                    vgacs[vga_charset].char_scanlines)
1247                         continue;
1248                 if(vgacs[first].scr_scanlines !=
1249                    vgacs[vga_charset].scr_scanlines)
1250                         continue;
1251                 fflag = 1;
1252                 break;
1253         }
1254
1255         if(fflag != 1)
1256                 return;
1257
1258         for(second = first+1; second < totalfonts; second++)
1259         {
1260                 if(!vgacs[second].loaded)
1261                         continue;
1262                 if(vgacs[second].screen_size != vgacs[vga_charset].screen_size)
1263                         continue;
1264                 if(vgacs[second].char_scanlines !=
1265                    vgacs[vga_charset].char_scanlines)
1266                         continue;
1267                 if(vgacs[second].scr_scanlines !=
1268                    vgacs[vga_charset].scr_scanlines)
1269                         continue;
1270                 sflag = 1;
1271                 break;
1272         }
1273
1274         cmap = cmaptaba[first];
1275         if(sflag)
1276         {
1277                 cmap |= cmaptabb[second];
1278                 vgacs[first].secondloaded = second;
1279         }
1280         else
1281         {
1282                 vgacs[first].secondloaded = 0; /*cs 0 can never become a 2nd!*/
1283         }
1284
1285         if(vsp->wd132col)
1286         {
1287                 cmap = (vga_charset & 0x07);
1288                 cmap |= 0x10;
1289         }
1290
1291         outb(TS_INDEX, TS_FONTSEL);     /* character map select register */
1292         outb(TS_DATA, cmap);            /* new char map */
1293
1294         outb(addr_6845, CRTC_MAXROW);   /* max scan line reg */
1295         outb(addr_6845+1,
1296                 vgacs[first].char_scanlines); /* scanlines/char */
1297
1298         outb(addr_6845, CRTC_VDE);      /* vert display enable end */
1299         outb(addr_6845+1,
1300                 vgacs[first].scr_scanlines);  /* low byte of scr scanlines */
1301
1302         if((color == 0) && (adaptor_type == VGA_ADAPTOR))
1303         {
1304                 outb(addr_6845, CRTC_ULOC);     /* underline location reg */
1305                 outb(addr_6845+1, (vgacs[first].char_scanlines & 0x1F));
1306         }
1307 }
1308
1309 /*---------------------------------------------------------------------------*
1310  *      switch vga-card to load a character set
1311  *---------------------------------------------------------------------------*/
1312 static void
1313 setchargen(void)
1314 {
1315         chargen_access = 1;     /* flag we are accessing the chargen ram */
1316
1317         /* program sequencer to access character generator */
1318
1319         outb(TS_INDEX, TS_SYNCRESET);
1320         outb(TS_DATA, 0x01);    /* synchronous reset */
1321
1322         outb(TS_INDEX, TS_WRPLMASK);
1323         outb(TS_DATA, 0x04);    /* write to map 2 */
1324
1325         outb(TS_INDEX, TS_MEMMODE);
1326         outb(TS_DATA, 0x07);    /* sequential addressing */
1327
1328         outb(TS_INDEX, TS_SYNCRESET);
1329         outb(TS_DATA, 0x03);    /* clear synchronous reset */
1330
1331         /* program graphics controller to access character generator */
1332
1333         outb(GDC_INDEX, GDC_RDPLANESEL);
1334         outb(GDC_DATA, 0x02);   /* select map 2 for cpu reads */
1335
1336         outb(GDC_INDEX, GDC_MODE);
1337         outb(GDC_DATA, 0x00);   /* disable odd-even addressing */
1338
1339         outb(GDC_INDEX, GDC_MISC);
1340         outb(GDC_DATA, 0x00);   /* map starts at 0xA000 */
1341 }
1342
1343 /*---------------------------------------------------------------------------*
1344  *      switch vga-card to load a character set to plane 3
1345  *---------------------------------------------------------------------------*/
1346 static void
1347 setchargen3(void)
1348 {
1349         chargen_access = 1;     /* flag we are accessing the chargen ram */
1350
1351         /* program sequencer to access character generator */
1352
1353         outb(TS_INDEX, TS_SYNCRESET);
1354         outb(TS_DATA, 0x01);    /* synchronous reset */
1355
1356         outb(TS_INDEX, TS_WRPLMASK);
1357         outb(TS_DATA, 0x08);    /* write to map 3 */
1358
1359         outb(TS_INDEX, TS_MEMMODE);
1360         outb(TS_DATA, 0x07);    /* sequential addressing */
1361
1362         outb(TS_INDEX, TS_SYNCRESET);
1363         outb(TS_DATA, 0x03);    /* clear synchronous reset */
1364
1365         /* program graphics controller to access character generator */
1366
1367         outb(GDC_INDEX, GDC_RDPLANESEL);
1368         outb(GDC_DATA, 0x03);   /* select map 3 for cpu reads */
1369
1370         outb(GDC_INDEX, GDC_MODE);
1371         outb(GDC_DATA, 0x00);   /* disable odd-even addressing */
1372
1373         outb(GDC_INDEX, GDC_MISC);
1374         outb(GDC_DATA, 0x00);   /* map starts at 0xA000 */
1375 }
1376
1377 /*---------------------------------------------------------------------------*
1378  *      switch back vga-card to normal operation
1379  *---------------------------------------------------------------------------*/
1380 static void
1381 resetchargen(void)
1382 {
1383         /* program sequencer to access video ram */
1384
1385         outb(TS_INDEX, TS_SYNCRESET);
1386         outb(TS_DATA, 0x01);    /* synchronous reset */
1387
1388         outb(TS_INDEX, TS_WRPLMASK);
1389         outb(TS_DATA, 0x03);    /* write to map 0 & 1 */
1390
1391         outb(TS_INDEX, TS_MEMMODE);
1392         outb(TS_DATA, 0x03);    /* odd-even addressing */
1393
1394         outb(TS_INDEX, TS_SYNCRESET);
1395         outb(TS_DATA, 0x03);    /* clear synchronous reset */
1396
1397         /* program graphics controller to access character generator */
1398
1399         outb(GDC_INDEX, GDC_RDPLANESEL);
1400         outb(GDC_DATA, 0x00);   /* select map 0 for cpu reads */
1401
1402         outb(GDC_INDEX, GDC_MODE);
1403         outb(GDC_DATA, 0x10);   /* enable odd-even addressing */
1404
1405         outb(GDC_INDEX, GDC_MISC);
1406         if(color)
1407                 outb(GDC_DATA, 0x0e);   /* map starts at 0xb800 */
1408         else
1409                 outb(GDC_DATA, 0x0a);   /* map starts at 0xb000 */
1410
1411         chargen_access = 0;     /* flag we are NOT accessing the chargen ram */
1412 }
1413
1414 #if PCVT_WAITRETRACE
1415 /*---------------------------------------------------------------------------*
1416  *      wait for being in a retrace time window
1417  *      NOTE: this is __VERY__ bad programming practice in this environment !!
1418  *---------------------------------------------------------------------------*/
1419
1420 static void
1421 wait_retrace(void)
1422 {
1423         if(color)
1424         {
1425                 while(!(inb(GN_INPSTAT1C) & 0x01))
1426                         ;
1427         }
1428         else
1429         {
1430                 while(!(inb(GN_INPSTAT1M) & 0x01))
1431                         ;
1432         }
1433 }
1434
1435 #endif /* PCVT_WAITRETRACE */
1436
1437 /*---------------------------------------------------------------------------*
1438  *      switch screen off (VGA only)
1439  *---------------------------------------------------------------------------*/
1440 void
1441 vga_screen_off(void)
1442 {
1443         unsigned char old;
1444
1445         outb(TS_INDEX, TS_SYNCRESET);
1446         outb(TS_DATA, 0x01);            /* synchronous reset */
1447
1448         outb(TS_INDEX, TS_MODE);        /* clocking mode reg */
1449         old = inb(TS_DATA);             /* get current value */
1450
1451         outb(TS_INDEX, TS_MODE);        /* clocking mode reg */
1452         outb(TS_DATA, (old | 0x20));    /* screen off bit on */
1453
1454         outb(TS_INDEX, TS_SYNCRESET);
1455         outb(TS_DATA, 0x03);            /* clear synchronous reset */
1456 }
1457
1458 /*---------------------------------------------------------------------------*
1459  *      switch screen back on (VGA only)
1460  *---------------------------------------------------------------------------*/
1461 void
1462 vga_screen_on(void)
1463 {
1464         unsigned char old;
1465
1466         outb(TS_INDEX, TS_SYNCRESET);
1467         outb(TS_DATA, 0x01);            /* synchronous reset */
1468
1469         outb(TS_INDEX, TS_MODE);        /* clocking mode reg */
1470         old = inb(TS_DATA);             /* get current value */
1471
1472         outb(TS_INDEX, TS_MODE);        /* clocking mode reg */
1473         outb(TS_DATA, (old & ~0x20));   /* screen off bit off */
1474
1475         outb(TS_INDEX, TS_SYNCRESET);
1476         outb(TS_DATA, 0x03);            /* clear synchronous reset */
1477 }
1478
1479 /*---------------------------------------------------------------------------*
1480  *      compute character set base address (in kernel map)
1481  *---------------------------------------------------------------------------*/
1482 static unsigned char *
1483 compute_charset_base(unsigned fontset)
1484 {
1485         unsigned char *d = (unsigned char *)Crtat;
1486
1487         static int charset_offset[8] = { 0x0000, 0x4000, 0x8000, 0xC000,
1488                                          0x2000, 0x6000, 0xA000, 0xE000 };
1489
1490         static int charsetw_offset[8] = { 0x0000, 0x2000, 0x4000, 0x6000,
1491                                           0x8000, 0xA000, 0xC000, 0xE000 };
1492
1493         switch(adaptor_type)
1494         {
1495                 case EGA_ADAPTOR:
1496                         fontset = (fontset > 3) ? 3 : fontset;
1497                         break;
1498
1499                 case VGA_ADAPTOR:
1500                         fontset = (fontset > 7) ? 7 : fontset;
1501                         break;
1502
1503                 default:
1504                         return 0;
1505         }
1506
1507         if(color)
1508                 d -= (0xB8000 - 0xA0000);       /* Point to 0xA0000 */
1509         else
1510                 d -= (0xB0000 - 0xA0000);       /* Point to 0xA0000 */
1511
1512         if(vsp->wd132col)
1513                 d += charsetw_offset[fontset];  /* Load into Character set n */
1514         else
1515                 d += charset_offset[fontset];   /* Load into Character set n */
1516
1517         return d;
1518 }
1519
1520 /*---------------------------------------------------------------------------*
1521  *      load a char into ega/vga character generator ram
1522  *---------------------------------------------------------------------------*/
1523 void
1524 loadchar(int fontset, int character, int char_scanlines, u_char *char_table)
1525 {
1526         unsigned char *d;
1527
1528 #if PCVT_BACKUP_FONTS
1529         unsigned char *bak;
1530 #endif /* PCVT_BACKUP_FONTS */
1531
1532         int j, k;
1533
1534         if((d = compute_charset_base(fontset)) == 0)
1535                 return;
1536
1537         d += (character * 32);          /* 32 bytes per character */
1538
1539         if(vsp->wd132col &&
1540            (fontset == 1||fontset == 3||fontset == 5||fontset == 7))
1541                 setchargen3();                  /* access chargen ram */
1542         else
1543                 setchargen();                   /* access chargen ram */
1544
1545         for(j = k = 0; j < char_scanlines; j++) /* x bit high characters */
1546         {
1547                 *d = char_table[k];
1548                 d++;
1549                 k++;
1550         }
1551         for(; j < 32; j++)              /* Up to 32 bytes per character image*/
1552         {
1553                 *d = 0x00;
1554                 d++;
1555         }
1556
1557         resetchargen();                 /* access video ram */
1558
1559 #if PCVT_BACKUP_FONTS
1560         if(saved_charsets[fontset] == 0)
1561                 saved_charsets[fontset] =
1562                         (u_char *)malloc(32 * 256, M_DEVBUF, M_WAITOK);
1563
1564         if((bak = saved_charsets[fontset]))
1565         {
1566                 /* make a backup copy of this char */
1567                 bak += (character * 32);
1568                 bzero(bak, 32);
1569                 bcopy(char_table, bak, char_scanlines);
1570         }
1571 #ifdef DIAGNOSTIC
1572         else
1573                 panic("pcvt loadchar: no backup buffer");
1574 #endif /* DIAGNOSTIC */
1575
1576 #endif /* PCVT_BACKUP_FONTS */
1577
1578 }
1579
1580 /*---------------------------------------------------------------------------*
1581  *      save/restore character set n to addr b
1582  *---------------------------------------------------------------------------*/
1583 #if !PCVT_BACKUP_FONTS
1584
1585 void
1586 vga_move_charset(unsigned n, unsigned char *b, int save_it)
1587 {
1588         unsigned char *d = compute_charset_base(n);
1589
1590 #ifdef DIAGNOSTIC
1591         if(d == 0)
1592                 panic("vga_move_charset: wrong adaptor");
1593 #endif
1594
1595         if(vsp->wd132col && (n == 1||n == 3||n == 5||n == 7))
1596         {
1597                 setchargen3();
1598                 d -= 0x2000;
1599         }
1600         else
1601         {
1602                 setchargen();
1603         }
1604
1605         /* PLEASE, leave the following alone using bcopyb, as several   */
1606         /* chipsets have problems if their memory is accessed with 32   */
1607         /* or 16 bits wide, don't change this to using bcopy for speed! */
1608
1609         if(save_it)
1610                 bcopyb(d, b, 256 /* chars */ * 32 /* bytes per char */);
1611         else
1612                 bcopyb(b, d, 256 /* chars */ * 32 /* bytes per char */);
1613
1614         resetchargen();
1615 }
1616
1617 #else /* PCVT_BACKUP_FONTS */
1618
1619 /* since there are always backed up copies, we do not save anything here */
1620 /* parameter "b" is totally ignored */
1621
1622 void
1623 vga_move_charset(unsigned n, unsigned char *b, int save_it)
1624 {
1625         unsigned char *d = compute_charset_base(n);
1626
1627         if(save_it)
1628                 return;
1629
1630         if(saved_charsets[n] == 0)
1631 #ifdef DIAGNOSTIC
1632                 panic("pcvt: restoring unbuffered charset");
1633 #else
1634                 return;
1635 #endif
1636
1637 #ifdef DIAGNOSTIC
1638         if(d == 0)
1639                 panic("vga_move_charset: wrong adaptor");
1640 #endif
1641
1642         if(vsp->wd132col && (n == 1||n == 3||n == 5||n == 7))
1643         {
1644                 setchargen3();
1645                 d -= 0x2000;
1646         }
1647         else
1648         {
1649                 setchargen();
1650         }
1651
1652         /* PLEASE, leave the following alone using bcopyb, as several   */
1653         /* chipsets have problems if their memory is accessed with 32   */
1654         /* or 16 bits wide, don't change this to using bcopy for speed! */
1655
1656         bcopyb(saved_charsets[n], d,
1657                256 /* chars */ * 32 /* bytes per char */);
1658
1659         resetchargen();
1660 }
1661
1662 #endif /* PCVT_BACKUP_FONTS */
1663
1664
1665 #if !PCVT_USL_VT_COMPAT
1666 /*---------------------------------------------------------------------------*
1667  *      switch to virtual screen n (0 ... PCVT_NSCREENS-1)
1668  *---------------------------------------------------------------------------*/
1669 void
1670 vgapage(int n)
1671 {
1672
1673 #if !PCVT_KBD_FIFO
1674         int x;
1675 #endif  /* !PCVT_KBD_FIFO */
1676
1677         int cols = vsp->maxcol;         /* get current col val */
1678
1679         if(n < 0 || n >= totalscreens)
1680                 return;
1681
1682 #if !PCVT_KBD_FIFO
1683         x = spltty();                   /* protect us */
1684 #endif  /* !PCVT_KBD_FIFO */
1685
1686         /* video board memory -> kernel memory */
1687
1688         bcopy(vsp->Crtat, vsp->Memory, vsp->screen_rows * vsp->maxcol * CHR);
1689
1690         vsp->Crtat = vsp->Memory;       /* operate in memory now */
1691
1692         /* update global screen pointers/variables */
1693
1694         current_video_screen = n;       /* current screen no */
1695
1696 #if !PCVT_NETBSD && !(PCVT_FREEBSD > 110 && PCVT_FREEBSD < 200)
1697         pcconsp = &pccons[n];           /* current tty */
1698 #elif PCVT_FREEBSD > 110 && PCVT_FREEBSD < 200
1699         pcconsp = pccons[n];            /* current tty */
1700 #else
1701         pcconsp = pc_tty[n];            /* current tty */
1702 #endif
1703
1704         vsp = &vs[n];                   /* current video state ptr */
1705
1706         /* kernel memory -> video board memory */
1707
1708         bcopy(vsp->Crtat, Crtat, vsp->screen_rows * vsp->maxcol * CHR);
1709
1710         vsp->Crtat = Crtat;             /* operate on screen now */
1711
1712         outb(addr_6845, CRTC_STARTADRH);
1713         outb(addr_6845+1, 0);
1714         outb(addr_6845, CRTC_STARTADRL);
1715         outb(addr_6845+1, 0);
1716
1717 #if !PCVT_KBD_FIFO
1718         splx(x);
1719 #endif  /* !PCVT_KBD_FIFO */
1720
1721         select_vga_charset(vsp->vga_charset);
1722
1723         if(vsp->maxcol != cols)
1724                 vga_col(vsp, vsp->maxcol);      /* select 80/132 columns */
1725
1726         outb(addr_6845, CRTC_CURSORH);  /* select high register */
1727         outb(addr_6845+1, vsp->cur_offset >> 8);
1728         outb(addr_6845, CRTC_CURSORL);  /* select low register */
1729         outb(addr_6845+1, vsp->cur_offset);
1730
1731         if(vsp->cursor_on)
1732         {
1733                 outb(addr_6845, CRTC_CURSTART); /* select high register */
1734                 outb(addr_6845+1, vsp->cursor_start);
1735                 outb(addr_6845, CRTC_CUREND);   /* select low register */
1736                 outb(addr_6845+1, vsp->cursor_end);
1737         }
1738         else
1739         {
1740                 sw_cursor(0);
1741         }
1742
1743         if(adaptor_type == VGA_ADAPTOR)
1744         {
1745                 unsigned i;
1746
1747                 /* switch VGA DAC palette entries */
1748
1749                 for(i = 0; i < NVGAPEL; i++)
1750                         vgapaletteio(i, &vsp->palette[i], 1);
1751         }
1752
1753         update_led();                   /* update led's */
1754
1755         update_hp(vsp);                 /* update fkey labels, if present */
1756 }
1757 #endif /* !PCVT_USL_VT_COMPAT */
1758
1759 /*---------------------------------------------------------------------------*
1760  *      test if it is a vga
1761  *---------------------------------------------------------------------------*/
1762
1763 int
1764 vga_test(void)
1765 {
1766         u_char old, new, check;
1767
1768         outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
1769         old = inb(addr_6845+1);         /* get current value */
1770
1771         new = old | CURSOR_ON_BIT;      /* set cursor on by setting bit 5 on */
1772
1773         outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
1774         outb(addr_6845+1,new);          /* cursor should be on now */
1775
1776         outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
1777         check = inb(addr_6845+1);       /* get current value */
1778
1779         if(check != new)
1780         {
1781                 outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
1782                 outb(addr_6845+1,old);          /* failsafe */
1783                 return(0);                      /* must be ega */
1784         }
1785
1786         new = old & ~CURSOR_ON_BIT;     /* turn cursor off by clearing bit 5 */
1787
1788         outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
1789         outb(addr_6845+1,new);          /* cursor should be off now */
1790
1791         outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
1792         check = inb(addr_6845+1);       /* get current value */
1793
1794         if(check != new)
1795         {
1796                 outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
1797                 outb(addr_6845+1,old);          /* failsafe */
1798                 return(0);                      /* must be ega */
1799         }
1800
1801         outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
1802         outb(addr_6845+1,old);          /* failsafe */
1803
1804         return(1);      /* vga */
1805 }
1806
1807 /*---------------------------------------------------------------------------*
1808  *      convert upper/lower sixel font array to vga font array
1809  *---------------------------------------------------------------------------*/
1810 void
1811 sixel_vga(struct sixels *sixelp, u_char *vgachar)
1812 {
1813         register int i, j;
1814         register int shift;
1815         register u_char mask;
1816
1817         for(j = 0; j < 16; j++)
1818                 vgachar[j] = 0;
1819
1820         mask = 0x01;
1821         for(j = 0; j < 6; j++)
1822         {
1823                 for(i = 0, shift = 7; i < 8; i++, shift--)
1824                         vgachar[j] |= ((((sixelp->upper[i]) & mask) >> j)
1825                                        << shift);
1826                 mask <<= 1;
1827         }
1828
1829         mask = 0x01;
1830         for(j = 0; j < 4; j++)
1831         {
1832                 for(i = 0, shift = 7; i < 8; i++, shift--)
1833                         vgachar[j+6] |= ((((sixelp->lower[i]) & mask) >>j)
1834                                          << shift);
1835                 mask <<= 1;
1836         }
1837 }
1838
1839 /*---------------------------------------------------------------------------*
1840  *      Expand 8x10 EGA/VGA characters to 8x16 EGA/VGA characters
1841  *---------------------------------------------------------------------------*/
1842 void
1843 vga10_vga16(u_char *invga, u_char *outvga)
1844 {
1845         register int i,j;
1846
1847         /*
1848          * Keep the top and bottom scanlines the same and double every scan
1849          * line in between.
1850          */
1851
1852         outvga[0] = invga[0];
1853         outvga[1] = invga[1];
1854         outvga[14] = invga[8];
1855         outvga[15] = invga[9];
1856
1857         for(i = j = 2;i < 8 && j < 14;i++,j += 2)
1858         {
1859                 outvga[j]   = invga[i];
1860                 outvga[j+1] = invga[i];
1861         }
1862 }
1863
1864 /*---------------------------------------------------------------------------*
1865  *      Expand 8x10 EGA/VGA characters to 8x14 EGA/VGA characters
1866  *---------------------------------------------------------------------------*/
1867 void
1868 vga10_vga14(u_char *invga, u_char *outvga)
1869 {
1870         register int i;
1871
1872         /*
1873          * Double the top two and bottom two scanlines and copy everything
1874          * in between.
1875          */
1876
1877         outvga[0] = invga[0];
1878         outvga[1] = invga[0];
1879         outvga[2] = invga[1];
1880         outvga[3] = invga[1];
1881         outvga[10] = invga[8];
1882         outvga[11] = invga[8];
1883         outvga[12] = invga[9];
1884         outvga[13] = invga[9];
1885
1886         for(i = 2;i < 8;i++)
1887                 outvga[i+2]   = invga[i];
1888 }
1889
1890 /*---------------------------------------------------------------------------*
1891  *      Expand 8x10 EGA/VGA characters to 8x10 EGA/VGA characters
1892  *---------------------------------------------------------------------------*/
1893 void
1894 vga10_vga10(u_char *invga, u_char *outvga)
1895 {
1896         register int i;
1897
1898         for(i = 0;i < 10;i++)
1899                 outvga[i]   = invga[i];
1900 }
1901
1902 /*---------------------------------------------------------------------------*
1903  *      Contract 8x10 EGA/VGA characters to 8x8 EGA/VGA characters
1904  *---------------------------------------------------------------------------*/
1905 void
1906 vga10_vga8(u_char *invga, u_char *outvga)
1907 {
1908         /* Skip scanlines 3 and 7 */
1909
1910         outvga[0] = invga[0];
1911         outvga[1] = invga[1];
1912         outvga[2] = invga[2];
1913         outvga[3] = invga[4];
1914         outvga[4] = invga[5];
1915         outvga[5] = invga[6];
1916         outvga[6] = invga[8];
1917         outvga[7] = invga[9];
1918 }
1919
1920 /*---------------------------------------------------------------------------*
1921  *      force a vga card to behave like an ega for debugging
1922  *---------------------------------------------------------------------------*/
1923 #if FORCE_EGA
1924 void
1925 force_ega(void)
1926 {
1927         unsigned char vgareg;
1928
1929         if(adaptor_type == VGA_ADAPTOR)
1930         {
1931                 adaptor_type = EGA_ADAPTOR;
1932                 totalfonts = 4;
1933                 vgareg = inb(GN_MISCOUTR); /* Miscellaneous Output Register */
1934                 vgareg |= 128;             /* Set 350 scanline mode */
1935                 vgareg &= ~64;
1936                 outb(GN_MISCOUTW,vgareg);
1937         }
1938 }
1939 #endif /* FORCE_EGA */
1940
1941 /*---------------------------------------------------------------------------*
1942  *      disconnect attribute bit 3 from generating intensity
1943  *      (and use it for a second character set !)
1944  *---------------------------------------------------------------------------*/
1945 void
1946 set_2ndcharset(void)
1947 {
1948         if(color)                       /* prepare to access index register! */
1949                 inb(GN_INPSTAT1C);
1950         else
1951                 inb(GN_INPSTAT1M);
1952
1953         /* select color plane enable reg, caution: set ATC access bit ! */
1954
1955         outb(ATC_INDEX, (ATC_COLPLEN | ATC_ACCESS));
1956         outb(ATC_DATAW, 0x07);          /* disable plane 3 */
1957 }
1958
1959 #if PCVT_SCREENSAVER
1960 #if PCVT_PRETTYSCRNS
1961
1962 /*---------------------------------------------------------------------------*
1963  * produce some kinda random number, had a look into the system library...
1964  *---------------------------------------------------------------------------*/
1965 static u_short
1966 getrand(void)
1967 {
1968 #if !PCVT_FREEBSD
1969         extern struct timeval time; /* time-of-day register */
1970 #endif
1971         static unsigned long seed = 1;
1972         register u_short res = (u_short)seed;
1973         seed = seed * 1103515245L + time_second;
1974         return res;
1975 }
1976
1977 /*---------------------------------------------------------------------------*
1978  *      produce "nice" screensaving ....
1979  *---------------------------------------------------------------------------*/
1980 static void
1981 scrnsv_blink(void * arg)
1982 {
1983         static struct rgb blink_rgb[8] =
1984         {
1985                 {63, 63, 63},   /* white */
1986                 {0, 63, 42},    /* pale green */
1987                 {63, 63, 0},    /* yellow */
1988                 {63, 21, 63},   /* violet */
1989                 {42, 63, 0},    /* yellow-green */
1990                 {63, 42, 0},    /* amber */
1991                 {63, 42, 42},   /* rose */
1992                 {21, 42, 42}    /* cyan */
1993         };
1994         register u_short r = getrand();
1995         unsigned pos = (r % (scrnsv_size / 2));
1996
1997         *scrnsv_current = /* (0 << 8) + */ ' ';
1998         scrnsv_current = vsp->Crtat + pos;
1999         *scrnsv_current = (7 /* LIGHTGRAY */ << 8) + '*';
2000         if(adaptor_type == VGA_ADAPTOR)
2001                 vgapaletteio(7 /* LIGHTGRAY */, &blink_rgb[(r >> 4) & 7], 1);
2002         scrnsv_blink_ch = timeout(scrnsv_blink, NULL, hz);
2003 }
2004
2005 #endif /* PCVT_PRETTYSCRNS */
2006
2007 /*---------------------------------------------------------------------------*
2008  *      set timeout time
2009  *---------------------------------------------------------------------------*/
2010 #ifndef XSERVER
2011 static void
2012 pcvt_set_scrnsv_tmo(int timeout)
2013 #else
2014 void
2015 pcvt_set_scrnsv_tmo(int timeout)
2016 #endif /* XSERVER */
2017 {
2018         int x = splhigh();
2019
2020         if(scrnsv_timeout)
2021                 untimeout(scrnsv_timedout, NULL, scrnsv_timeout_ch);
2022
2023         scrnsv_timeout = timeout;
2024         pcvt_scrnsv_reset();            /* sanity */
2025         splx(x);
2026         if(timeout == 0 && savedscreen)
2027         {
2028                 /* release buffer when screen saver turned off */
2029                 free(savedscreen, M_TEMP);
2030                 savedscreen = (u_short *)0;
2031         }
2032 }
2033
2034 /*---------------------------------------------------------------------------*
2035  *      we were timed out
2036  *---------------------------------------------------------------------------*/
2037 static void
2038 scrnsv_timedout(void *arg)
2039 {
2040         /* this function is called by timeout() */
2041         /* raise priority to avoid conflicts with kbd intr */
2042         int x = spltty();
2043
2044         /*
2045          * due to some undefined problems with video adaptor RAM
2046          * access timing, the following has been splitted into
2047          * two pieces called subsequently with a time difference
2048          * of 100 millisec
2049          */
2050
2051         if(++scrnsv_active == 1)
2052         {
2053                 register size_t s;
2054                 /*
2055                  * first, allocate a buffer
2056                  * do only if none allocated yet or another size required
2057                  * this reduces malloc() overhead by avoiding successive
2058                  * calls to malloc() and free() if they would have requested
2059                  * the same buffer
2060                  *
2061                  * XXX This is inherited from old days where no buffering
2062                  * happened at all. Meanwhile we should use the standard
2063                  * screen buffer instead. Any volunteers? :-) [At least,
2064                  * this code proved to work...]
2065                  */
2066
2067                 s = sizeof(u_short) * vsp->screen_rowsize * vsp->maxcol;
2068
2069                 if(savedscreen == (u_short *)0 || s != scrnsv_size)
2070                 {
2071                         /* really need to allocate */
2072                         if(savedscreen)
2073                                 free(savedscreen, M_TEMP);
2074                         scrnsv_size = s;
2075                         if((savedscreen =
2076                             (u_short *)malloc(s, M_TEMP, M_NOWAIT))
2077                            == (u_short *)0)
2078                         {
2079                                 /*
2080                                  * didn't get the buffer memory,
2081                                  * turn off screen saver
2082                                  */
2083                                 scrnsv_timeout = scrnsv_active = 0;
2084                                 splx(x);
2085                                 return;
2086                         }
2087                 }
2088                 /* save current screen */
2089                 bcopy(vsp->Crtat, savedscreen, scrnsv_size);
2090
2091                 /* on VGA's, make sure palette is set to blank screen */
2092                 if(adaptor_type == VGA_ADAPTOR)
2093                 {
2094                         struct rgb black = {0, 0, 0};
2095                         vgapaletteio(0 /* BLACK */, &black, 1);
2096                 }
2097                 /* prepare for next time... */
2098                 scrnsv_timeout_ch = timeout(scrnsv_timedout, NULL, hz / 10);
2099         }
2100         else
2101         {
2102                 /* second call, now blank the screen */
2103                 /* fill screen with blanks */
2104                 fillw(/* (BLACK<<8) + */ ' ', vsp->Crtat, scrnsv_size / 2);
2105
2106 #if PCVT_PRETTYSCRNS
2107                 scrnsv_current = vsp->Crtat;
2108                 scrnsv_blink_ch = timeout(scrnsv_blink, NULL, hz);
2109 #endif /* PCVT_PRETTYSCRNS */
2110
2111                 sw_cursor(0);   /* cursor off on mda/cga */
2112         }
2113         splx(x);
2114 }
2115
2116 /*---------------------------------------------------------------------------*
2117  *      interface to screensaver "subsystem"
2118  *---------------------------------------------------------------------------*/
2119 void
2120 pcvt_scrnsv_reset(void)
2121 {
2122         /*
2123          * to save lotta time with superfluous timeout()/untimeout() calls
2124          * when having massive output operations, we remember the last
2125          * second of kernel timer we've rescheduled scrnsv_timedout()
2126          */
2127         static long last_schedule = 0L;
2128         register int x = splhigh();
2129         int reschedule = 0;
2130
2131         if((scrnsv_active == 1 || scrnsv_timeout) &&
2132            last_schedule != time_second)
2133         {
2134                 last_schedule = time_second;
2135                 reschedule = 1;
2136                 untimeout(scrnsv_timedout, NULL, scrnsv_timeout_ch);
2137         }
2138         if(scrnsv_active)
2139         {
2140
2141 #if PCVT_PRETTYSCRNS
2142                 if(scrnsv_active > 1)
2143                         untimeout(scrnsv_blink, NULL, scrnsv_blink_ch);
2144 #endif /* PCVT_PRETTYSCRNS */
2145
2146                 bcopy(savedscreen, vsp->Crtat, scrnsv_size);
2147                 if(adaptor_type == VGA_ADAPTOR)
2148                 {
2149                         /* back up VGA palette info */
2150                         vgapaletteio(0 /* BLACK */, &vsp->palette[0], 1);
2151
2152 #if PCVT_PRETTYSCRNS
2153                         vgapaletteio(7 /* LIGHTGRAY */, &vsp->palette[7], 1);
2154 #endif /* PCVT_PRETTYSCRNS */
2155
2156                 }
2157                 scrnsv_active = 0;
2158
2159                 if(vsp->cursor_on)
2160                         sw_cursor(1);   /* cursor on */
2161         }
2162
2163         if(reschedule)
2164         {
2165                 /* mark next timeout */
2166                 scrnsv_timeout_ch = timeout(scrnsv_timedout, NULL,
2167                                             scrnsv_timeout * hz);
2168         }
2169         splx(x);
2170 }
2171
2172 #endif /* PCVT_SCREENSAVER */
2173
2174 /*---------------------------------------------------------------------------*
2175  *      switch cursor on/off
2176  *---------------------------------------------------------------------------*/
2177 void
2178 sw_cursor(int onoff)
2179 {
2180         if(adaptor_type == EGA_ADAPTOR)
2181         {
2182                 int start, end;
2183                 if(onoff)
2184                 {
2185                         start = vsp->cursor_start;
2186                         end = vsp->cursor_end;
2187                 }
2188                 else
2189                 {
2190                         int cs = vs[current_video_screen].vga_charset;
2191
2192                         cs = (cs < 0) ? 0 : ((cs < totalfonts) ?
2193                                              cs : totalfonts-1);
2194
2195                         start = (vgacs[cs].char_scanlines & 0x1F) + 1;
2196                         end = 0;
2197                 }
2198                 outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
2199                 outb(addr_6845+1, start);
2200                 outb(addr_6845,CRTC_CUREND);    /* cursor end reg */
2201                 outb(addr_6845+1, end);
2202         }
2203         else    /* mda, cga, vga */
2204         {
2205                 outb(addr_6845,CRTC_CURSTART);  /* cursor start reg */
2206                 if(onoff)
2207                         outb(addr_6845+1, vsp->cursor_start);
2208                 else
2209                         outb(addr_6845+1, CURSOR_ON_BIT);
2210         }
2211 }
2212
2213 /*---------------------------------------------------------------------------*
2214  *      cold init support, if a mono monitor is attached to a
2215  *      vga or ega, it comes up with a mda emulation. switch
2216  *      board to generic ega/vga mode in this case.
2217  *---------------------------------------------------------------------------*/
2218 void
2219 mda2egaorvga(void)
2220 {
2221         /*
2222          * program sequencer to access
2223          * video ram
2224          */
2225
2226         /* synchronous reset */
2227         outb(TS_INDEX, TS_SYNCRESET);
2228         outb(TS_DATA, 0x01);
2229
2230         /* write to map 0 & 1 */
2231         outb(TS_INDEX, TS_WRPLMASK);
2232         outb(TS_DATA, 0x03);
2233
2234         /* odd-even addressing */
2235         outb(TS_INDEX, TS_MEMMODE);
2236         outb(TS_DATA, 0x03);
2237
2238         /* clear synchronous reset */
2239         outb(TS_INDEX, TS_SYNCRESET);
2240         outb(TS_DATA, 0x03);
2241
2242         /*
2243          * program graphics controller
2244          * to access character
2245          * generator
2246          */
2247
2248         /* select map 0 for cpu reads */
2249         outb(GDC_INDEX, GDC_RDPLANESEL);
2250         outb(GDC_DATA, 0x00);
2251
2252         /* enable odd-even addressing */
2253         outb(GDC_INDEX, GDC_MODE);
2254         outb(GDC_DATA, 0x10);
2255
2256         /* map starts at 0xb000 */
2257         outb(GDC_INDEX, GDC_MISC);
2258         outb(GDC_DATA, 0x0a);
2259 }
2260
2261 #endif  /* NVT > 0 */
2262
2263 /* ------------------------- E O F ------------------------------------------*/