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