Deleted Added
full compact
syscons.c (12840) syscons.c (13228)
1/*-
2 * Copyright (c) 1992-1995 S�ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
1/*-
2 * Copyright (c) 1992-1995 S�ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $Id: syscons.c,v 1.137 1995/12/10 15:54:55 bde Exp $
28 * $Id: syscons.c,v 1.138 1995/12/14 22:03:03 bde Exp $
29 */
30
31#include "sc.h"
32#include "apm.h"
29 */
30
31#include "sc.h"
32#include "apm.h"
33#include "opt_ddb.h"
34
33#if NSC > 0
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/conf.h>
37#include <sys/ioctl.h>
38#include <sys/proc.h>
39#include <sys/signalvar.h>
40#include <sys/tty.h>
41#include <sys/uio.h>
42#include <sys/callout.h>
43#include <sys/kernel.h>
44#include <sys/syslog.h>
45#include <sys/errno.h>
46#include <sys/malloc.h>
47#include <sys/devconf.h>
48#ifdef DEVFS
49#include <sys/devfsext.h>
50#endif
51
52#include <machine/clock.h>
53#include <machine/cons.h>
54#include <machine/console.h>
55#include <machine/psl.h>
56#include <machine/frame.h>
57#include <machine/pc/display.h>
58#include <machine/apm_bios.h>
59#include <machine/random.h>
60
61#include <vm/vm.h>
62#include <vm/vm_param.h>
63#include <vm/pmap.h>
64
65#include <i386/isa/isa.h>
66#include <i386/isa/isa_device.h>
67#include <i386/isa/timerreg.h>
68#include <i386/isa/kbdtables.h>
69#include <i386/isa/syscons.h>
70
71#if !defined(MAXCONS)
72#define MAXCONS 16
73#endif
74
75
76/* this may break on older VGA's but is usefull on real 32 bit systems */
77#define bcopyw bcopy
78
79static default_attr user_default = {
80 (FG_LIGHTGREY | BG_BLACK) << 8,
81 (FG_BLACK | BG_LIGHTGREY) << 8
82};
83
84static default_attr kernel_default = {
85 (FG_WHITE | BG_BLACK) << 8,
86 (FG_BLACK | BG_LIGHTGREY) << 8
87};
88
89static scr_stat main_console;
90static scr_stat *console[MAXCONS];
91static void *sc_devfs_token[MAXCONS];
92 scr_stat *cur_console;
93static scr_stat *new_scp, *old_scp;
94static term_stat kernel_console;
95static default_attr *current_default;
96static char init_done = FALSE;
97static int configuration = 0;
98static char switch_in_progress = FALSE;
99static char blink_in_progress = FALSE;
100static char write_in_progress = FALSE;
101 u_int crtc_addr = MONO_BASE;
102static char crtc_vga = FALSE;
103static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
104static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
105static char *font_8 = NULL, *font_14 = NULL, *font_16 = NULL;
106static int fonts_loaded = 0;
107 char palette[3*256];
108static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
109static int delayed_next_scr = FALSE;
110static long scrn_blank_time = 0; /* screen saver timeout value */
111 int scrn_blanked = FALSE; /* screen saver active flag */
112static long scrn_time_stamp;
113 u_char scr_map[256];
114static char *video_mode_ptr = NULL;
115#if ASYNCH
116static u_char kbd_reply = 0;
117#endif
118
119static u_short mouse_and_mask[16] = {
120 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
121 0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
122};
123static u_short mouse_or_mask[16] = {
124 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
125 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
126};
127
128static void none_saver(int blank) { }
129
130void (*current_saver) __P((int blank)) = none_saver;
131
132static int scattach(struct isa_device *dev);
133static int scparam(struct tty *tp, struct termios *t);
134static int scprobe(struct isa_device *dev);
135static void scstart(struct tty *tp);
136
137/* OS specific stuff */
138#ifdef not_yet_done
139#define VIRTUAL_TTY(x) (sccons[x] = ttymalloc(sccons[x]))
140struct CONSOLE_TTY (sccons[MAXCONS] = ttymalloc(sccons[MAXCONS]))
141struct tty *sccons[MAXCONS+1];
142#else
143#define VIRTUAL_TTY(x) &sccons[x]
144#define CONSOLE_TTY &sccons[MAXCONS]
145static struct tty sccons[MAXCONS+1];
146#endif
147#define MONO_BUF pa_to_va(0xB0000)
148#define CGA_BUF pa_to_va(0xB8000)
149u_short *Crtat;
150
151#define WRAPHIST(scp, pointer, offset)\
152 ((scp->history) + ((((pointer) - (scp->history)) + (scp->history_size)\
153 + (offset)) % (scp->history_size)))
154
155struct isa_driver scdriver = {
156 scprobe, scattach, "sc", 1
157};
158
159static d_open_t scopen;
160static d_close_t scclose;
161static d_read_t scread;
162static d_write_t scwrite;
163static d_ioctl_t scioctl;
164static d_devtotty_t scdevtotty;
165static d_mmap_t scmmap;
166
167#define CDEV_MAJOR 12
168static struct cdevsw scdevsw = {
169 scopen, scclose, scread, scwrite,
170 scioctl, nullstop, noreset, scdevtotty,
171 ttselect, scmmap, nostrategy, "sc", NULL, -1 };
172
173/*
174 * Calculate hardware attributes word using logical attributes mask and
175 * hardware colors
176 */
177
178static int
179mask2attr(struct term_stat *term)
180{
181 int attr, mask = term->attr_mask;
182
183 if (mask & REVERSE_ATTR) {
184 attr = ((mask & FOREGROUND_CHANGED) ?
185 ((term->cur_color & 0xF000) >> 4) :
186 (term->rev_color & 0x0F00)) |
187 ((mask & BACKGROUND_CHANGED) ?
188 ((term->cur_color & 0x0F00) << 4) :
189 (term->rev_color & 0xF000));
190 } else
191 attr = term->cur_color;
192
193 /* XXX: underline mapping for Hercules adapter can be better */
194 if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
195 attr ^= 0x0800;
196 if (mask & BLINK_ATTR)
197 attr ^= 0x8000;
198
199 return attr;
200}
201
202static int
203scprobe(struct isa_device *dev)
204{
205 int i, retries = 5;
206 unsigned char val;
207
208 /* Enable interrupts and keyboard controller */
209 kbd_wait();
210 outb(KB_STAT, KB_WRITE);
211 kbd_wait();
212 outb(KB_DATA, KB_MODE);
213
214 /* flush any noise in the buffer */
215 while (inb(KB_STAT) & KB_BUF_FULL) {
216 DELAY(10);
217 (void) inb(KB_DATA);
218 }
219
220 /* Reset keyboard hardware */
221 while (retries--) {
222 kbd_wait();
223 outb(KB_DATA, KB_RESET);
224 for (i=0; i<100000; i++) {
225 DELAY(10);
226 val = inb(KB_DATA);
227 if (val == KB_ACK || val == KB_ECHO)
228 goto gotres;
229 if (val == KB_RESEND)
230 break;
231 }
232 }
233gotres:
234 if (!retries)
235 printf("scprobe: keyboard won't accept RESET command\n");
236 else {
237gotack:
238 DELAY(10);
239 while ((inb(KB_STAT) & KB_BUF_FULL) == 0) DELAY(10);
240 DELAY(10);
241 val = inb(KB_DATA);
242 if (val == KB_ACK)
243 goto gotack;
244 if (val != KB_RESET_DONE)
245 printf("scprobe: keyboard RESET failed %02x\n", val);
246 }
247#ifdef XT_KEYBOARD
248 kbd_wait();
249 outb(KB_DATA, 0xF0);
250 kbd_wait();
251 outb(KB_DATA, 1);
252 kbd_wait();
253#endif /* XT_KEYBOARD */
254 return (IO_KBDSIZE);
255}
256
257static struct kern_devconf kdc_sc[NSC] = {
258 0, 0, 0, /* filled in by dev_attach */
259 "sc", 0, { MDDT_ISA, 0, "tty" },
260 isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
261 &kdc_isa0, /* parent */
262 0, /* parentdata */
263 DC_BUSY, /* the console is almost always busy */
264 "Graphics console",
265 DC_CLS_DISPLAY /* class */
266};
267
268static inline void
269sc_registerdev(struct isa_device *id)
270{
271 if(id->id_unit)
272 kdc_sc[id->id_unit] = kdc_sc[0];
273 kdc_sc[id->id_unit].kdc_unit = id->id_unit;
274 kdc_sc[id->id_unit].kdc_isa = id;
275 dev_attach(&kdc_sc[id->id_unit]);
276}
277
278#if NAPM > 0
279static int
280scresume(void *dummy)
281{
282 shfts = 0;
283 ctls = 0;
284 alts = 0;
285 agrs = 0;
286 metas = 0;
287 return 0;
288}
289#endif
290
291static int
292scattach(struct isa_device *dev)
293{
294 scr_stat *scp;
295 int vc;
296 char name[32];
297
298 scinit();
299 configuration = dev->id_flags;
300
301 scp = console[0];
302
303 if (crtc_vga) {
304 font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT);
305 font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT);
306 font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT);
307 copy_font(SAVE, FONT_16, font_16);
308 fonts_loaded = FONT_16;
309 scp->font = FONT_16;
310 save_palette();
311 }
312
313 scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
314 M_DEVBUF, M_NOWAIT);
315 /* copy screen to buffer */
316 bcopyw(Crtat, scp->scr_buf, scp->xsize * scp->ysize * sizeof(u_short));
317 scp->cursor_pos = scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
318 scp->mouse_pos = scp->scr_buf;
319
320 /* initialize history buffer & pointers */
321 scp->history_head = scp->history_pos = scp->history =
322 (u_short *)malloc(scp->history_size*sizeof(u_short),
323 M_DEVBUF, M_NOWAIT);
324 bzero(scp->history_head, scp->history_size*sizeof(u_short));
325
326 /* initialize cursor stuff */
327 draw_cursor(scp, TRUE);
328 if (crtc_vga && (configuration & CHAR_CURSOR))
329 set_destructive_cursor(scp, TRUE);
330
331 /* get screen update going */
332 scrn_timer();
333
334 update_leds(scp->status);
335 sc_registerdev(dev);
336
337 printf("sc%d: ", dev->id_unit);
338 if (crtc_vga)
339 if (crtc_addr == MONO_BASE)
340 printf("VGA mono");
341 else
342 printf("VGA color");
343 else
344 if (crtc_addr == MONO_BASE)
345 printf("MDA/hercules");
346 else
347 printf("CGA/EGA");
348 printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, configuration);
349
350#if NAPM > 0
351 scp->r_hook.ah_fun = scresume;
352 scp->r_hook.ah_arg = NULL;
353 scp->r_hook.ah_name = "system keyboard";
354 scp->r_hook.ah_order = APM_MID_ORDER;
355 apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook);
356#endif
357
358#ifdef DEVFS
359 for ( vc = 0 ; vc < MAXCONS; vc++) {
360 sprintf(name,"ttyv%x", vc);
361 sc_devfs_token[vc] = devfs_add_devsw("/" ,name, &scdevsw, vc,
362 DV_CHR, 0, 0, 0600 );
363 }
364#endif
365 {
366 dev_t dev = makedev(CDEV_MAJOR, 0);
367
368 cdevsw_add(&dev, &scdevsw, NULL);
369 }
370
371 return 0;
372}
373
374struct tty
375*scdevtotty(dev_t dev)
376{
377 int unit = minor(dev);
378
379 if (unit > MAXCONS || unit < 0)
380 return(NULL);
381 if (unit == MAXCONS)
382 return CONSOLE_TTY;
383 return VIRTUAL_TTY(unit);
384}
385
386static scr_stat
387*get_scr_stat(dev_t dev)
388{
389 int unit = minor(dev);
390
391 if (unit > MAXCONS || unit < 0)
392 return(NULL);
393 if (unit == MAXCONS)
394 return console[0];
395 return console[unit];
396}
397
398static int
399get_scr_num()
400{
401 int i = 0;
402
403 while ((i < MAXCONS) && (cur_console != console[i]))
404 i++;
405 return i < MAXCONS ? i : 0;
406}
407
408int
409scopen(dev_t dev, int flag, int mode, struct proc *p)
410{
411 struct tty *tp = scdevtotty(dev);
412
413 if (!tp)
414 return(ENXIO);
415
416 tp->t_oproc = scstart;
417 tp->t_param = scparam;
418 tp->t_dev = dev;
419 if (!(tp->t_state & TS_ISOPEN)) {
420 ttychars(tp);
421 tp->t_iflag = TTYDEF_IFLAG;
422 tp->t_oflag = TTYDEF_OFLAG;
423 tp->t_cflag = TTYDEF_CFLAG;
424 tp->t_lflag = TTYDEF_LFLAG;
425 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
426 scparam(tp, &tp->t_termios);
427 ttsetwater(tp);
428 (*linesw[tp->t_line].l_modem)(tp, 1);
429 }
430 else
431 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
432 return(EBUSY);
433 if (!console[minor(dev)])
434 console[minor(dev)] = alloc_scp();
435 return((*linesw[tp->t_line].l_open)(dev, tp));
436}
437
438int
439scclose(dev_t dev, int flag, int mode, struct proc *p)
440{
441 struct tty *tp = scdevtotty(dev);
442 struct scr_stat *scp;
443
444 if (!tp)
445 return(ENXIO);
446 if (minor(dev) < MAXCONS) {
447 scp = get_scr_stat(tp->t_dev);
448 if (scp->status & SWITCH_WAIT_ACQ)
449 wakeup((caddr_t)&scp->smode);
450#if not_yet_done
451 if (scp == &main_console) {
452 scp->pid = 0;
453 scp->proc = NULL;
454 scp->smode.mode = VT_AUTO;
455 }
456 else {
457 free(scp->scr_buf, M_DEVBUF);
458 free(scp->history, M_DEVBUF);
459 free(scp, M_DEVBUF);
460 console[minor(dev)] = NULL;
461 }
462#else
463 scp->pid = 0;
464 scp->proc = NULL;
465 scp->smode.mode = VT_AUTO;
466#endif
467 }
468 (*linesw[tp->t_line].l_close)(tp, flag);
469 ttyclose(tp);
470 return(0);
471}
472
473int
474scread(dev_t dev, struct uio *uio, int flag)
475{
476 struct tty *tp = scdevtotty(dev);
477
478 if (!tp)
479 return(ENXIO);
480 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
481}
482
483int
484scwrite(dev_t dev, struct uio *uio, int flag)
485{
486 struct tty *tp = scdevtotty(dev);
487
488 if (!tp)
489 return(ENXIO);
490 return((*linesw[tp->t_line].l_write)(tp, uio, flag));
491}
492
493void
494scintr(int unit)
495{
496 static struct tty *cur_tty;
497 int c, len;
498 u_char *cp;
499
500 /* make screensaver happy */
501 scrn_time_stamp = time.tv_sec;
502 if (scrn_blanked) {
503 (*current_saver)(FALSE);
504 cur_console->start = 0;
505 cur_console->end = cur_console->xsize * cur_console->ysize;
506 }
507
508 c = scgetc(1);
509
510 cur_tty = VIRTUAL_TTY(get_scr_num());
511 if (!(cur_tty->t_state & TS_ISOPEN))
512 if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN))
513 return;
514
515 switch (c & 0xff00) {
516 case 0x0000: /* normal key */
517 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
518 break;
519 case NOKEY: /* nothing there */
520 break;
521 case FKEY: /* function key, return string */
522 if (cp = get_fstr((u_int)c, (u_int *)&len)) {
523 while (len-- > 0)
524 (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty);
525 }
526 break;
527 case MKEY: /* meta is active, prepend ESC */
528 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
529 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
530 break;
531 case BKEY: /* backtab fixed sequence (esc [ Z) */
532 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
533 (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
534 (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
535 break;
536 }
537}
538
539static int
540scparam(struct tty *tp, struct termios *t)
541{
542 tp->t_ispeed = t->c_ispeed;
543 tp->t_ospeed = t->c_ospeed;
544 tp->t_cflag = t->c_cflag;
545 return 0;
546}
547
548int
549scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
550{
551 int i, error;
552 struct tty *tp;
553 struct trapframe *fp;
554 scr_stat *scp;
555
556 tp = scdevtotty(dev);
557 if (!tp)
558 return ENXIO;
559 scp = get_scr_stat(tp->t_dev);
560
561 switch (cmd) { /* process console hardware related ioctl's */
562
563 case GIO_ATTR: /* get current attributes */
564 *(int*)data = scp->term.cur_attr;
565 return 0;
566
567 case GIO_COLOR: /* is this a color console ? */
568 if (crtc_addr == COLOR_BASE)
569 *(int*)data = 1;
570 else
571 *(int*)data = 0;
572 return 0;
573
574 case CONS_CURRENT: /* get current adapter type */
575 if (crtc_vga)
576 *(int*)data = KD_VGA;
577 else
578 if (crtc_addr == MONO_BASE)
579 *(int*)data = KD_MONO;
580 else
581 *(int*)data = KD_CGA;
582 return 0;
583
584 case CONS_GET: /* get current video mode */
585 *(int*)data = scp->mode;
586 return 0;
587
588 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
589 scrn_blank_time = *(int*)data;
590 return 0;
591
592 case CONS_CURSORTYPE: /* set cursor type blink/noblink */
593 if ((*(int*)data) & 0x01)
594 configuration |= BLINK_CURSOR;
595 else
596 configuration &= ~BLINK_CURSOR;
597 if ((*(int*)data) & 0x02) {
598 configuration |= CHAR_CURSOR;
599 set_destructive_cursor(scp, TRUE);
600 } else
601 configuration &= ~CHAR_CURSOR;
602 return 0;
603
604 case CONS_BELLTYPE: /* set bell type sound/visual */
605 if (*data)
606 configuration |= VISUAL_BELL;
607 else
608 configuration &= ~VISUAL_BELL;
609 return 0;
610
611 case CONS_HISTORY: /* set history size */
612 if (*data) {
613 free(scp->history, M_DEVBUF);
614 scp->history_size = *(int*)data;
615 if (scp->history_size < scp->ysize)
616 scp->history = NULL;
617 else {
618 scp->history_size *= scp->xsize;
619 scp->history_head = scp->history_pos = scp->history =
620 (u_short *)malloc(scp->history_size*sizeof(u_short),
621 M_DEVBUF, M_WAITOK);
622 bzero(scp->history_head, scp->history_size*sizeof(u_short));
623 }
624 return 0;
625 }
626 else
627 return EINVAL;
628
629 case CONS_MOUSECTL: /* control mouse arrow */
630 {
631 mouse_info_t *mouse = (mouse_info_t*)data;
632 int fontsize;
633
634 switch (scp->font) {
635 default:
636 case FONT_8:
637 fontsize = 8; break;
638 case FONT_14:
639 fontsize = 14; break;
640 case FONT_16:
641 fontsize = 16; break;
642 }
643 switch (mouse->operation) {
644 case MOUSE_SHOW:
645 if (!(scp->status & MOUSE_ENABLED)) {
646 scp->mouse_oldpos = Crtat + (scp->mouse_pos - scp->scr_buf);
647 scp->status |= (UPDATE_MOUSE | MOUSE_ENABLED);
648 }
649 else
650 return EINVAL;
651 break;
652
653 case MOUSE_HIDE:
654 if (scp->status & MOUSE_ENABLED) {
655 scp->status &= ~MOUSE_ENABLED;
656 scp->status |= UPDATE_MOUSE;
657 }
658 else
659 return EINVAL;
660 break;
661
662 case MOUSE_MOVEABS:
663 scp->mouse_xpos = mouse->x;
664 scp->mouse_ypos = mouse->y;
665 goto set_mouse_pos;
666
667 case MOUSE_MOVEREL:
668 scp->mouse_xpos += mouse->x;
669 scp->mouse_ypos += mouse->y;
670set_mouse_pos:
671 if (scp->mouse_xpos < 0)
672 scp->mouse_xpos = 0;
673 if (scp->mouse_ypos < 0)
674 scp->mouse_ypos = 0;
675 if (scp->mouse_xpos >= scp->xsize*8)
676 scp->mouse_xpos = (scp->xsize*8)-1;
677 if (scp->mouse_ypos >= scp->ysize*fontsize)
678 scp->mouse_ypos = (scp->ysize*fontsize)-1;
679 scp->mouse_pos = scp->scr_buf +
680 (scp->mouse_ypos/fontsize)*scp->xsize + scp->mouse_xpos/8;
681 if (scp->status & MOUSE_ENABLED)
682 scp->status |= UPDATE_MOUSE;
683 break;
684
685 case MOUSE_GETPOS:
686 mouse->x = scp->mouse_xpos;
687 mouse->y = scp->mouse_ypos;
688 return 0;
689
690 default:
691 return EINVAL;
692 }
693 /* make screensaver happy */
694 if (scp == cur_console) {
695 scrn_time_stamp = time.tv_sec;
696 if (scrn_blanked) {
697 (*current_saver)(FALSE);
698 cur_console->start = 0;
699 cur_console->end = cur_console->xsize * cur_console->ysize;
700 }
701 }
702 return 0;
703 }
704
705 case CONS_GETINFO: /* get current (virtual) console info */
706 {
707 vid_info_t *ptr = (vid_info_t*)data;
708 if (ptr->size == sizeof(struct vid_info)) {
709 ptr->m_num = get_scr_num();
710 ptr->mv_col = scp->xpos;
711 ptr->mv_row = scp->ypos;
712 ptr->mv_csz = scp->xsize;
713 ptr->mv_rsz = scp->ysize;
714 ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
715 ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
716 ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
717 ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
718 ptr->mv_grfc.fore = 0; /* not supported */
719 ptr->mv_grfc.back = 0; /* not supported */
720 ptr->mv_ovscan = scp->border;
721 ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
722 return 0;
723 }
724 return EINVAL;
725 }
726
727 case CONS_GETVERS: /* get version number */
728 *(int*)data = 0x200; /* version 2.0 */
729 return 0;
730
731 /* VGA TEXT MODES */
732 case SW_VGA_C40x25:
733 case SW_VGA_C80x25: case SW_VGA_M80x25:
734 case SW_VGA_C80x30: case SW_VGA_M80x30:
735 case SW_VGA_C80x50: case SW_VGA_M80x50:
736 case SW_VGA_C80x60: case SW_VGA_M80x60:
737 case SW_B40x25: case SW_C40x25:
738 case SW_B80x25: case SW_C80x25:
739 case SW_ENH_B40x25: case SW_ENH_C40x25:
740 case SW_ENH_B80x25: case SW_ENH_C80x25:
741 case SW_ENH_B80x43: case SW_ENH_C80x43:
742
743 if (!crtc_vga || video_mode_ptr == NULL)
744 return ENXIO;
745 switch (cmd & 0xff) {
746 case M_VGA_C80x60: case M_VGA_M80x60:
747 if (!(fonts_loaded & FONT_8))
748 return EINVAL;
749 scp->xsize = 80;
750 scp->ysize = 60;
751 break;
752 case M_VGA_C80x50: case M_VGA_M80x50:
753 if (!(fonts_loaded & FONT_8))
754 return EINVAL;
755 scp->xsize = 80;
756 scp->ysize = 50;
757 break;
758 case M_ENH_B80x43: case M_ENH_C80x43:
759 if (!(fonts_loaded & FONT_8))
760 return EINVAL;
761 scp->xsize = 80;
762 scp->ysize = 43;
763 break;
764 case M_VGA_C80x30: case M_VGA_M80x30:
765 scp->xsize = 80;
766 scp->ysize = 30;
767 break;
768 default:
769 if ((cmd & 0xff) > M_VGA_CG320)
770 return EINVAL;
771 else
772 scp->xsize = *(video_mode_ptr+((cmd&0xff)*64));
773 scp->ysize = *(video_mode_ptr+((cmd&0xff)*64)+1)+1;
774 break;
775 }
776 scp->mode = cmd & 0xff;
777 scp->status &= ~UNKNOWN_MODE; /* text mode */
778 free(scp->scr_buf, M_DEVBUF);
779 scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
780 M_DEVBUF, M_WAITOK);
781 if (scp == cur_console)
782 set_mode(scp);
783 clear_screen(scp);
784 if (tp->t_winsize.ws_col != scp->xsize
785 || tp->t_winsize.ws_row != scp->ysize) {
786 tp->t_winsize.ws_col = scp->xsize;
787 tp->t_winsize.ws_row = scp->ysize;
788 pgsignal(tp->t_pgrp, SIGWINCH, 1);
789 }
790 return 0;
791
792 /* GRAPHICS MODES */
793 case SW_BG320: case SW_BG640:
794 case SW_CG320: case SW_CG320_D: case SW_CG640_E:
795 case SW_CG640x350: case SW_ENH_CG640:
796 case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
797
798 if (!crtc_vga || video_mode_ptr == NULL)
799 return ENXIO;
800 scp->mode = cmd & 0xFF;
801 scp->status |= UNKNOWN_MODE; /* graphics mode */
802 scp->xsize = (*(video_mode_ptr + (scp->mode*64))) * 8;
803 scp->ysize = (*(video_mode_ptr + (scp->mode*64) + 1) + 1) *
804 (*(video_mode_ptr + (scp->mode*64) + 2));
805 set_mode(scp);
806 /* clear_graphics();*/
807
808 if (tp->t_winsize.ws_xpixel != scp->xsize
809 || tp->t_winsize.ws_ypixel != scp->ysize) {
810 tp->t_winsize.ws_xpixel = scp->xsize;
811 tp->t_winsize.ws_ypixel = scp->ysize;
812 pgsignal(tp->t_pgrp, SIGWINCH, 1);
813 }
814 return 0;
815
816 case VT_SETMODE: /* set screen switcher mode */
817 bcopy(data, &scp->smode, sizeof(struct vt_mode));
818 if (scp->smode.mode == VT_PROCESS) {
819 scp->proc = p;
820 scp->pid = scp->proc->p_pid;
821 }
822 return 0;
823
824 case VT_GETMODE: /* get screen switcher mode */
825 bcopy(&scp->smode, data, sizeof(struct vt_mode));
826 return 0;
827
828 case VT_RELDISP: /* screen switcher ioctl */
829 switch(*data) {
830 case VT_FALSE: /* user refuses to release screen, abort */
831 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
832 old_scp->status &= ~SWITCH_WAIT_REL;
833 switch_in_progress = FALSE;
834 return 0;
835 }
836 return EINVAL;
837
838 case VT_TRUE: /* user has released screen, go on */
839 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
840 scp->status &= ~SWITCH_WAIT_REL;
841 exchange_scr();
842 if (new_scp->smode.mode == VT_PROCESS) {
843 new_scp->status |= SWITCH_WAIT_ACQ;
844 psignal(new_scp->proc, new_scp->smode.acqsig);
845 }
846 else
847 switch_in_progress = FALSE;
848 return 0;
849 }
850 return EINVAL;
851
852 case VT_ACKACQ: /* acquire acknowledged, switch completed */
853 if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
854 scp->status &= ~SWITCH_WAIT_ACQ;
855 switch_in_progress = FALSE;
856 return 0;
857 }
858 return EINVAL;
859
860 default:
861 return EINVAL;
862 }
863 /* NOT REACHED */
864
865 case VT_OPENQRY: /* return free virtual console */
866 for (i = 0; i < MAXCONS; i++) {
867 tp = VIRTUAL_TTY(i);
868 if (!(tp->t_state & TS_ISOPEN)) {
869 *data = i + 1;
870 return 0;
871 }
872 }
873 return EINVAL;
874
875 case VT_ACTIVATE: /* switch to screen *data */
876 return switch_scr(scp, (*data) - 1);
877
878 case VT_WAITACTIVE: /* wait for switch to occur */
879 if (*data > MAXCONS || *data < 0)
880 return EINVAL;
881 if (minor(dev) == (*data) - 1)
882 return 0;
883 if (*data == 0) {
884 if (scp == cur_console)
885 return 0;
886 }
887 else
888 scp = console[(*data) - 1];
889 while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
890 "waitvt", 0)) == ERESTART) ;
891 return error;
892
893 case VT_GETACTIVE:
894 *data = get_scr_num()+1;
895 return 0;
896
897 case KDENABIO: /* allow io operations */
898 error = suser(p->p_ucred, &p->p_acflag);
899 if (error != 0)
900 return error;
901 fp = (struct trapframe *)p->p_md.md_regs;
902 fp->tf_eflags |= PSL_IOPL;
903 return 0;
904
905 case KDDISABIO: /* disallow io operations (default) */
906 fp = (struct trapframe *)p->p_md.md_regs;
907 fp->tf_eflags &= ~PSL_IOPL;
908 return 0;
909
910 case KDSETMODE: /* set current mode of this (virtual) console */
911 switch (*data) {
912 case KD_TEXT: /* switch to TEXT (known) mode */
913 /* restore fonts & palette ! */
914 if (crtc_vga) {
915 if (fonts_loaded & FONT_8)
916 copy_font(LOAD, FONT_8, font_8);
917 if (fonts_loaded & FONT_14)
918 copy_font(LOAD, FONT_14, font_14);
919 if (fonts_loaded & FONT_16)
920 copy_font(LOAD, FONT_16, font_16);
921 if (configuration & CHAR_CURSOR)
922 set_destructive_cursor(scp, TRUE);
923 load_palette();
924 }
925 /* FALL THROUGH */
926
927 case KD_TEXT1: /* switch to TEXT (known) mode */
928 /* no restore fonts & palette */
929 scp->status &= ~UNKNOWN_MODE;
930 if (crtc_vga && video_mode_ptr)
931 set_mode(scp);
932 clear_screen(scp);
933 return 0;
934
935 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */
936 scp->status |= UNKNOWN_MODE;
937 return 0;
938 default:
939 return EINVAL;
940 }
941 /* NOT REACHED */
942
943 case KDGETMODE: /* get current mode of this (virtual) console */
944 *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
945 return 0;
946
947 case KDSBORDER: /* set border color of this (virtual) console */
948 if (!crtc_vga)
949 return ENXIO;
950 scp->border = *data;
951 if (scp == cur_console)
952 set_border(scp->border);
953 return 0;
954
955 case KDSKBSTATE: /* set keyboard state (locks) */
956 if (*data >= 0 && *data <= LOCK_KEY_MASK) {
957 scp->status &= ~LOCK_KEY_MASK;
958 scp->status |= *data;
959 if (scp == cur_console)
960 update_leds(scp->status);
961 return 0;
962 }
963 return EINVAL;
964
965 case KDGKBSTATE: /* get keyboard state (locks) */
966 *data = scp->status & LOCK_KEY_MASK;
967 return 0;
968
969 case KDSETRAD: /* set keyboard repeat & delay rates */
970 if (*data & 0x80)
971 return EINVAL;
972 i = spltty();
973 kbd_cmd(KB_SETRAD);
974 kbd_cmd(*data);
975 splx(i);
976 return 0;
977
978 case KDSKBMODE: /* set keyboard mode */
979 switch (*data) {
980 case K_RAW: /* switch to RAW scancode mode */
981 scp->status |= KBD_RAW_MODE;
982 return 0;
983
984 case K_XLATE: /* switch to XLT ascii mode */
985 if (scp == cur_console && scp->status == KBD_RAW_MODE)
986 shfts = ctls = alts = agrs = metas = 0;
987 scp->status &= ~KBD_RAW_MODE;
988 return 0;
989 default:
990 return EINVAL;
991 }
992 /* NOT REACHED */
993
994 case KDGKBMODE: /* get keyboard mode */
995 *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE;
996 return 0;
997
998 case KDMKTONE: /* sound the bell */
999 if (*(int*)data)
1000 do_bell(scp, (*(int*)data)&0xffff,
1001 (((*(int*)data)>>16)&0xffff)*hz/1000);
1002 else
1003 do_bell(scp, scp->bell_pitch, scp->bell_duration);
1004 return 0;
1005
1006 case KIOCSOUND: /* make tone (*data) hz */
1007 if (scp == cur_console) {
1008 if (*(int*)data) {
1009 int pitch = TIMER_FREQ/(*(int*)data);
1010
1011 /* set command for counter 2, 2 byte write */
1012 if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE))
1013 return EBUSY;
1014
1015 /* set pitch */
1016 outb(TIMER_CNTR2, pitch);
1017 outb(TIMER_CNTR2, (pitch>>8));
1018
1019 /* enable counter 2 output to speaker */
1020 outb(IO_PPI, inb(IO_PPI) | 3);
1021 }
1022 else {
1023 /* disable counter 2 output to speaker */
1024 outb(IO_PPI, inb(IO_PPI) & 0xFC);
1025 release_timer2();
1026 }
1027 }
1028 return 0;
1029
1030 case KDGKBTYPE: /* get keyboard type */
1031 *data = 0; /* type not known (yet) */
1032 return 0;
1033
1034 case KDSETLED: /* set keyboard LED status */
1035 if (*data >= 0 && *data <= LED_MASK) {
1036 scp->status &= ~LED_MASK;
1037 scp->status |= *data;
1038 if (scp == cur_console)
1039 update_leds(scp->status);
1040 return 0;
1041 }
1042 return EINVAL;
1043
1044 case KDGETLED: /* get keyboard LED status */
1045 *data = scp->status & LED_MASK;
1046 return 0;
1047
1048 case GETFKEY: /* get functionkey string */
1049 if (*(u_short*)data < n_fkey_tab) {
1050 fkeyarg_t *ptr = (fkeyarg_t*)data;
1051 bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef,
1052 fkey_tab[ptr->keynum].len);
1053 ptr->flen = fkey_tab[ptr->keynum].len;
1054 return 0;
1055 }
1056 else
1057 return EINVAL;
1058
1059 case SETFKEY: /* set functionkey string */
1060 if (*(u_short*)data < n_fkey_tab) {
1061 fkeyarg_t *ptr = (fkeyarg_t*)data;
1062 bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str,
1063 min(ptr->flen, MAXFK));
1064 fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
1065 return 0;
1066 }
1067 else
1068 return EINVAL;
1069
1070 case GIO_SCRNMAP: /* get output translation table */
1071 bcopy(&scr_map, data, sizeof(scr_map));
1072 return 0;
1073
1074 case PIO_SCRNMAP: /* set output translation table */
1075 bcopy(data, &scr_map, sizeof(scr_map));
1076 return 0;
1077
1078 case GIO_KEYMAP: /* get keyboard translation table */
1079 bcopy(&key_map, data, sizeof(key_map));
1080 return 0;
1081
1082 case PIO_KEYMAP: /* set keyboard translation table */
1083 bcopy(data, &key_map, sizeof(key_map));
1084 return 0;
1085
1086 case PIO_FONT8x8: /* set 8x8 dot font */
1087 if (!crtc_vga)
1088 return ENXIO;
1089 bcopy(data, font_8, 8*256);
1090 fonts_loaded |= FONT_8;
1091 copy_font(LOAD, FONT_8, font_8);
1092 if (configuration & CHAR_CURSOR)
1093 set_destructive_cursor(scp, TRUE);
1094 return 0;
1095
1096 case GIO_FONT8x8: /* get 8x8 dot font */
1097 if (!crtc_vga)
1098 return ENXIO;
1099 if (fonts_loaded & FONT_8) {
1100 bcopy(font_8, data, 8*256);
1101 return 0;
1102 }
1103 else
1104 return ENXIO;
1105
1106 case PIO_FONT8x14: /* set 8x14 dot font */
1107 if (!crtc_vga)
1108 return ENXIO;
1109 bcopy(data, font_14, 14*256);
1110 fonts_loaded |= FONT_14;
1111 copy_font(LOAD, FONT_14, font_14);
1112 if (configuration & CHAR_CURSOR)
1113 set_destructive_cursor(scp, TRUE);
1114 return 0;
1115
1116 case GIO_FONT8x14: /* get 8x14 dot font */
1117 if (!crtc_vga)
1118 return ENXIO;
1119 if (fonts_loaded & FONT_14) {
1120 bcopy(font_14, data, 14*256);
1121 return 0;
1122 }
1123 else
1124 return ENXIO;
1125
1126 case PIO_FONT8x16: /* set 8x16 dot font */
1127 if (!crtc_vga)
1128 return ENXIO;
1129 bcopy(data, font_16, 16*256);
1130 fonts_loaded |= FONT_16;
1131 copy_font(LOAD, FONT_16, font_16);
1132 if (configuration & CHAR_CURSOR)
1133 set_destructive_cursor(scp, TRUE);
1134 return 0;
1135
1136 case GIO_FONT8x16: /* get 8x16 dot font */
1137 if (!crtc_vga)
1138 return ENXIO;
1139 if (fonts_loaded & FONT_16) {
1140 bcopy(font_16, data, 16*256);
1141 return 0;
1142 }
1143 else
1144 return ENXIO;
1145 default:
1146 break;
1147 }
1148
1149 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1150 if (error >= 0)
1151 return(error);
1152 error = ttioctl(tp, cmd, data, flag);
1153 if (error >= 0)
1154 return(error);
1155 return(ENOTTY);
1156}
1157
1158static void
1159scstart(struct tty *tp)
1160{
1161 struct clist *rbp;
1162 int s, len;
1163 u_char buf[PCBURST];
1164 scr_stat *scp = get_scr_stat(tp->t_dev);
1165
1166 /* XXX who repeats the call when the above flags are cleared? */
1167 if (scp->status & SLKED || blink_in_progress)
1168 return;
1169 s = spltty();
1170 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1171 tp->t_state |= TS_BUSY;
1172 rbp = &tp->t_outq;
1173 while (rbp->c_cc) {
1174 len = q_to_b(rbp, buf, PCBURST);
1175 splx(s);
1176 ansi_put(scp, buf, len);
1177 s = spltty();
1178 }
1179 tp->t_state &= ~TS_BUSY;
1180 ttwwakeup(tp);
1181 }
1182 splx(s);
1183}
1184
1185void
1186sccnprobe(struct consdev *cp)
1187{
1188 struct isa_device *dvp;
1189
1190 /*
1191 * Take control if we are the highest priority enabled display device.
1192 */
1193 dvp = find_display();
1194 if (dvp != NULL && dvp->id_driver != &scdriver) {
1195 cp->cn_pri = CN_DEAD;
1196 return;
1197 }
1198
1199 /* initialize required fields */
1200 cp->cn_dev = makedev(CDEV_MAJOR, MAXCONS);
1201 cp->cn_pri = CN_INTERNAL;
1202}
1203
1204void
1205sccninit(struct consdev *cp)
1206{
1207 scinit();
1208}
1209
1210void
1211sccnputc(dev_t dev, int c)
1212{
1213 u_char buf[1];
1214 scr_stat *scp = console[0];
1215 term_stat save = scp->term;
1216
1217 scp->term = kernel_console;
1218 current_default = &kernel_default;
1219 if (scp->scr_buf == Crtat)
1220 draw_cursor(scp, FALSE);
1221 buf[0] = c;
1222 ansi_put(scp, buf, 1);
1223 kernel_console = scp->term;
1224 current_default = &user_default;
1225 scp->term = save;
1226 if (scp == cur_console /* && scrn_timer not running */) {
1227 if (scp->scr_buf != Crtat && (scp->start <= scp->end)) {
1228 bcopyw(scp->scr_buf + scp->start, Crtat + scp->start,
1229 (1 + scp->end - scp->start) * sizeof(u_short));
1230 scp->start = scp->xsize * scp->ysize;
1231 scp->end = 0;
1232 scp->status &= ~CURSOR_SHOWN;
1233 }
1234 draw_cursor(scp, TRUE);
1235 }
1236}
1237
1238int
1239sccngetc(dev_t dev)
1240{
1241 int s = spltty(); /* block scintr while we poll */
1242 int c = scgetc(0);
1243 splx(s);
1244 return(c);
1245}
1246
1247int
1248sccncheckc(dev_t dev)
1249{
1250 return (scgetc(1) & 0xff);
1251}
1252
1253static void
1254scrn_timer()
1255{
1256 static int cursor_blinkrate;
1257 scr_stat *scp = cur_console;
1258
1259 /* should we just return ? */
1260 if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) {
1261 timeout((timeout_func_t)scrn_timer, 0, hz/10);
1262 return;
1263 }
1264
1265 if (!scrn_blanked) {
1266 /* update screen image */
1267 if (scp->start <= scp->end) {
1268 bcopyw(scp->scr_buf + scp->start, Crtat + scp->start,
1269 (1 + scp->end - scp->start) * sizeof(u_short));
1270 scp->status &= ~CURSOR_SHOWN;
1271 scp->start = scp->xsize * scp->ysize;
1272 scp->end = 0;
1273 }
1274 /* update "pseudo" mouse arrow */
1275 if ((scp->status & MOUSE_ENABLED) && (scp->status & UPDATE_MOUSE))
1276 draw_mouse_image(scp);
1277
1278 /* update cursor image */
1279 if (scp->status & CURSOR_ENABLED)
1280 draw_cursor(scp,
1281 !(configuration&BLINK_CURSOR) || !(cursor_blinkrate++&0x04));
1282 }
1283 if (scrn_blank_time && (time.tv_sec>scrn_time_stamp+scrn_blank_time))
1284 (*current_saver)(TRUE);
1285 timeout((timeout_func_t)scrn_timer, 0, hz/25);
1286}
1287
1288static void
1289clear_screen(scr_stat *scp)
1290{
1291 move_crsr(scp, 0, 0);
1292 fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
1293 scp->xsize * scp->ysize);
1294 mark_all(scp);
1295}
1296
1297static int
1298switch_scr(scr_stat *scp, u_int next_scr)
1299{
1300 if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid)))
1301 switch_in_progress = FALSE;
1302
1303 if (next_scr >= MAXCONS || switch_in_progress ||
1304 (cur_console->smode.mode == VT_AUTO
1305 && cur_console->status & UNKNOWN_MODE)) {
1306 do_bell(scp, BELL_PITCH, BELL_DURATION);
1307 return EINVAL;
1308 }
1309
1310 /* is the wanted virtual console open ? */
1311 if (next_scr) {
1312 struct tty *tp = VIRTUAL_TTY(next_scr);
1313 if (!(tp->t_state & TS_ISOPEN)) {
1314 do_bell(scp, BELL_PITCH, BELL_DURATION);
1315 return EINVAL;
1316 }
1317 }
1318 /* delay switch if actively updating screen */
1319 if (write_in_progress || blink_in_progress) {
1320 delayed_next_scr = next_scr+1;
1321 return 0;
1322 }
1323 switch_in_progress = TRUE;
1324 old_scp = cur_console;
1325 new_scp = console[next_scr];
1326 wakeup((caddr_t)&new_scp->smode);
1327 if (new_scp == old_scp) {
1328 switch_in_progress = FALSE;
1329 delayed_next_scr = FALSE;
1330 return 0;
1331 }
1332
1333 /* has controlling process died? */
1334 if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
1335 old_scp->smode.mode = VT_AUTO;
1336 if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
1337 new_scp->smode.mode = VT_AUTO;
1338
1339 /* check the modes and switch approbiatly */
1340 if (old_scp->smode.mode == VT_PROCESS) {
1341 old_scp->status |= SWITCH_WAIT_REL;
1342 psignal(old_scp->proc, old_scp->smode.relsig);
1343 }
1344 else {
1345 exchange_scr();
1346 if (new_scp->smode.mode == VT_PROCESS) {
1347 new_scp->status |= SWITCH_WAIT_ACQ;
1348 psignal(new_scp->proc, new_scp->smode.acqsig);
1349 }
1350 else
1351 switch_in_progress = FALSE;
1352 }
1353 return 0;
1354}
1355
1356static void
1357exchange_scr(void)
1358{
1359 move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
1360 cur_console = new_scp;
1361 if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE)){
1362 if (crtc_vga && video_mode_ptr)
1363 set_mode(new_scp);
1364 }
1365 move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
1366 if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
1367 if (fonts_loaded & FONT_8)
1368 copy_font(LOAD, FONT_8, font_8);
1369 if (fonts_loaded & FONT_14)
1370 copy_font(LOAD, FONT_14, font_14);
1371 if (fonts_loaded & FONT_16)
1372 copy_font(LOAD, FONT_16, font_16);
1373 if (configuration & CHAR_CURSOR)
1374 set_destructive_cursor(new_scp, TRUE);
1375 load_palette();
1376 }
1377 if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
1378 shfts = ctls = alts = agrs = metas = 0;
1379 update_leds(new_scp->status);
1380 delayed_next_scr = FALSE;
1381 bcopyw(new_scp->scr_buf, Crtat,
1382 (new_scp->xsize*new_scp->ysize)*sizeof(u_short));
1383 new_scp->status &= ~CURSOR_SHOWN;
1384}
1385
1386static inline void
1387move_crsr(scr_stat *scp, int x, int y)
1388{
1389 if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize)
1390 return;
1391 scp->xpos = x;
1392 scp->ypos = y;
1393 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1394 scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos;
1395 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1396}
1397
1398static void
1399scan_esc(scr_stat *scp, u_char c)
1400{
1401 static u_char ansi_col[16] =
1402 {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
1403 int i, n;
1404 u_short *src, *dst, count;
1405
1406 if (scp->term.esc == 1) {
1407 switch (c) {
1408
1409 case '[': /* Start ESC [ sequence */
1410 scp->term.esc = 2;
1411 scp->term.last_param = -1;
1412 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
1413 scp->term.param[i] = 1;
1414 scp->term.num_param = 0;
1415 return;
1416
1417 case 'M': /* Move cursor up 1 line, scroll if at top */
1418 if (scp->ypos > 0)
1419 move_crsr(scp, scp->xpos, scp->ypos - 1);
1420 else {
1421 bcopyw(scp->scr_buf, scp->scr_buf + scp->xsize,
1422 (scp->ysize - 1) * scp->xsize * sizeof(u_short));
1423 fillw(scp->term.cur_color | scr_map[0x20],
1424 scp->scr_buf, scp->xsize);
1425 mark_all(scp);
1426 }
1427 break;
1428#if notyet
1429 case 'Q':
1430 scp->term.esc = 4;
1431 break;
1432#endif
1433 case 'c': /* Clear screen & home */
1434 clear_screen(scp);
1435 break;
1436 }
1437 }
1438 else if (scp->term.esc == 2) {
1439 if (c >= '0' && c <= '9') {
1440 if (scp->term.num_param < MAX_ESC_PAR) {
1441 if (scp->term.last_param != scp->term.num_param) {
1442 scp->term.last_param = scp->term.num_param;
1443 scp->term.param[scp->term.num_param] = 0;
1444 }
1445 else
1446 scp->term.param[scp->term.num_param] *= 10;
1447 scp->term.param[scp->term.num_param] += c - '0';
1448 return;
1449 }
1450 }
1451 scp->term.num_param = scp->term.last_param + 1;
1452 switch (c) {
1453
1454 case ';':
1455 if (scp->term.num_param < MAX_ESC_PAR)
1456 return;
1457 break;
1458
1459 case '=':
1460 scp->term.esc = 3;
1461 scp->term.last_param = -1;
1462 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
1463 scp->term.param[i] = 1;
1464 scp->term.num_param = 0;
1465 return;
1466
1467 case 'A': /* up n rows */
1468 n = scp->term.param[0]; if (n < 1) n = 1;
1469 move_crsr(scp, scp->xpos, scp->ypos - n);
1470 break;
1471
1472 case 'B': /* down n rows */
1473 n = scp->term.param[0]; if (n < 1) n = 1;
1474 move_crsr(scp, scp->xpos, scp->ypos + n);
1475 break;
1476
1477 case 'C': /* right n columns */
1478 n = scp->term.param[0]; if (n < 1) n = 1;
1479 move_crsr(scp, scp->xpos + n, scp->ypos);
1480 break;
1481
1482 case 'D': /* left n columns */
1483 n = scp->term.param[0]; if (n < 1) n = 1;
1484 move_crsr(scp, scp->xpos - n, scp->ypos);
1485 break;
1486
1487 case 'E': /* cursor to start of line n lines down */
1488 n = scp->term.param[0]; if (n < 1) n = 1;
1489 move_crsr(scp, 0, scp->ypos + n);
1490 break;
1491
1492 case 'F': /* cursor to start of line n lines up */
1493 n = scp->term.param[0]; if (n < 1) n = 1;
1494 move_crsr(scp, 0, scp->ypos - n);
1495 break;
1496
1497 case 'f': /* Cursor move */
1498 case 'H':
1499 if (scp->term.num_param == 0)
1500 move_crsr(scp, 0, 0);
1501 else if (scp->term.num_param == 2)
1502 move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
1503 break;
1504
1505 case 'J': /* Clear all or part of display */
1506 if (scp->term.num_param == 0)
1507 n = 0;
1508 else
1509 n = scp->term.param[0];
1510 switch (n) {
1511 case 0: /* clear form cursor to end of display */
1512 fillw(scp->term.cur_color | scr_map[0x20],
1513 scp->cursor_pos,
1514 scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos);
1515 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1516 mark_for_update(scp, scp->xsize * scp->ysize);
1517 break;
1518 case 1: /* clear from beginning of display to cursor */
1519 fillw(scp->term.cur_color | scr_map[0x20],
1520 scp->scr_buf,
1521 scp->cursor_pos - scp->scr_buf);
1522 mark_for_update(scp, 0);
1523 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1524 break;
1525 case 2: /* clear entire display */
1526 clear_screen(scp);
1527 break;
1528 }
1529 break;
1530
1531 case 'K': /* Clear all or part of line */
1532 if (scp->term.num_param == 0)
1533 n = 0;
1534 else
1535 n = scp->term.param[0];
1536 switch (n) {
1537 case 0: /* clear form cursor to end of line */
1538 fillw(scp->term.cur_color | scr_map[0x20],
1539 scp->cursor_pos,
1540 scp->xsize - scp->xpos);
1541 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1542 mark_for_update(scp, scp->cursor_pos - scp->scr_buf +
1543 scp->xsize - scp->xpos);
1544 break;
1545 case 1: /* clear from beginning of line to cursor */
1546 fillw(scp->term.cur_color | scr_map[0x20],
1547 scp->cursor_pos - (scp->xsize - scp->xpos),
1548 (scp->xsize - scp->xpos) + 1);
1549 mark_for_update(scp, scp->ypos * scp->xsize);
1550 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1551 break;
1552 case 2: /* clear entire line */
1553 fillw(scp->term.cur_color | scr_map[0x20],
1554 scp->cursor_pos - (scp->xsize - scp->xpos),
1555 scp->xsize);
1556 mark_for_update(scp, scp->ypos * scp->xsize);
1557 mark_for_update(scp, (scp->ypos + 1) * scp->xsize);
1558 break;
1559 }
1560 break;
1561
1562 case 'L': /* Insert n lines */
1563 n = scp->term.param[0]; if (n < 1) n = 1;
1564 if (n > scp->ysize - scp->ypos)
1565 n = scp->ysize - scp->ypos;
1566 src = scp->scr_buf + scp->ypos * scp->xsize;
1567 dst = src + n * scp->xsize;
1568 count = scp->ysize - (scp->ypos + n);
1569 bcopyw(src, dst, count * scp->xsize * sizeof(u_short));
1570 fillw(scp->term.cur_color | scr_map[0x20], src,
1571 n * scp->xsize);
1572 mark_for_update(scp, scp->ypos * scp->xsize);
1573 mark_for_update(scp, scp->xsize * scp->ysize);
1574 break;
1575
1576 case 'M': /* Delete n lines */
1577 n = scp->term.param[0]; if (n < 1) n = 1;
1578 if (n > scp->ysize - scp->ypos)
1579 n = scp->ysize - scp->ypos;
1580 dst = scp->scr_buf + scp->ypos * scp->xsize;
1581 src = dst + n * scp->xsize;
1582 count = scp->ysize - (scp->ypos + n);
1583 bcopyw(src, dst, count * scp->xsize * sizeof(u_short));
1584 src = dst + count * scp->xsize;
1585 fillw(scp->term.cur_color | scr_map[0x20], src,
1586 n * scp->xsize);
1587 mark_for_update(scp, scp->ypos * scp->xsize);
1588 mark_for_update(scp, scp->xsize * scp->ysize);
1589 break;
1590
1591 case 'P': /* Delete n chars */
1592 n = scp->term.param[0]; if (n < 1) n = 1;
1593 if (n > scp->xsize - scp->xpos)
1594 n = scp->xsize - scp->xpos;
1595 dst = scp->cursor_pos;
1596 src = dst + n;
1597 count = scp->xsize - (scp->xpos + n);
1598 bcopyw(src, dst, count * sizeof(u_short));
1599 src = dst + count;
1600 fillw(scp->term.cur_color | scr_map[0x20], src, n);
1601 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1602 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
1603 break;
1604
1605 case '@': /* Insert n chars */
1606 n = scp->term.param[0]; if (n < 1) n = 1;
1607 if (n > scp->xsize - scp->xpos)
1608 n = scp->xsize - scp->xpos;
1609 src = scp->cursor_pos;
1610 dst = src + n;
1611 count = scp->xsize - (scp->xpos + n);
1612 bcopyw(src, dst, count * sizeof(u_short));
1613 fillw(scp->term.cur_color | scr_map[0x20], src, n);
1614 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1615 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
1616 break;
1617
1618 case 'S': /* scroll up n lines */
1619 n = scp->term.param[0]; if (n < 1) n = 1;
1620 if (n > scp->ysize)
1621 n = scp->ysize;
1622 bcopyw(scp->scr_buf + (scp->xsize * n),
1623 scp->scr_buf,
1624 scp->xsize * (scp->ysize - n) * sizeof(u_short));
1625 fillw(scp->term.cur_color | scr_map[0x20],
1626 scp->scr_buf + scp->xsize * (scp->ysize - n),
1627 scp->xsize * n);
1628 mark_all(scp);
1629 break;
1630
1631 case 'T': /* scroll down n lines */
1632 n = scp->term.param[0]; if (n < 1) n = 1;
1633 if (n > scp->ysize)
1634 n = scp->ysize;
1635 bcopyw(scp->scr_buf,
1636 scp->scr_buf + (scp->xsize * n),
1637 scp->xsize * (scp->ysize - n) *
1638 sizeof(u_short));
1639 fillw(scp->term.cur_color | scr_map[0x20],
1640 scp->scr_buf, scp->xsize * n);
1641 mark_all(scp);
1642 break;
1643
1644 case 'X': /* erase n characters in line */
1645 n = scp->term.param[0]; if (n < 1) n = 1;
1646 if (n > scp->xsize - scp->xpos)
1647 n = scp->xsize - scp->xpos;
1648 fillw(scp->term.cur_color | scr_map[0x20],
1649 scp->scr_buf + scp->xpos +
1650 ((scp->xsize*scp->ypos) * sizeof(u_short)), n);
1651 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1652 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n);
1653 break;
1654
1655 case 'Z': /* move n tabs backwards */
1656 n = scp->term.param[0]; if (n < 1) n = 1;
1657 if ((i = scp->xpos & 0xf8) == scp->xpos)
1658 i -= 8*n;
1659 else
1660 i -= 8*(n-1);
1661 if (i < 0)
1662 i = 0;
1663 move_crsr(scp, i, scp->ypos);
1664 break;
1665
1666 case '`': /* move cursor to column n */
1667 n = scp->term.param[0]; if (n < 1) n = 1;
1668 move_crsr(scp, n - 1, scp->ypos);
1669 break;
1670
1671 case 'a': /* move cursor n columns to the right */
1672 n = scp->term.param[0]; if (n < 1) n = 1;
1673 move_crsr(scp, scp->xpos + n, scp->ypos);
1674 break;
1675
1676 case 'd': /* move cursor to row n */
1677 n = scp->term.param[0]; if (n < 1) n = 1;
1678 move_crsr(scp, scp->xpos, n - 1);
1679 break;
1680
1681 case 'e': /* move cursor n rows down */
1682 n = scp->term.param[0]; if (n < 1) n = 1;
1683 move_crsr(scp, scp->xpos, scp->ypos + n);
1684 break;
1685
1686 case 'm': /* change attribute */
1687 if (scp->term.num_param == 0) {
1688 scp->term.attr_mask = NORMAL_ATTR;
1689 scp->term.cur_attr =
1690 scp->term.cur_color = scp->term.std_color;
1691 break;
1692 }
1693 for (i = 0; i < scp->term.num_param; i++) {
1694 switch (n = scp->term.param[i]) {
1695 case 0: /* back to normal */
1696 scp->term.attr_mask = NORMAL_ATTR;
1697 scp->term.cur_attr =
1698 scp->term.cur_color = scp->term.std_color;
1699 break;
1700 case 1: /* bold */
1701 scp->term.attr_mask |= BOLD_ATTR;
1702 scp->term.cur_attr = mask2attr(&scp->term);
1703 break;
1704 case 4: /* underline */
1705 scp->term.attr_mask |= UNDERLINE_ATTR;
1706 scp->term.cur_attr = mask2attr(&scp->term);
1707 break;
1708 case 5: /* blink */
1709 scp->term.attr_mask |= BLINK_ATTR;
1710 scp->term.cur_attr = mask2attr(&scp->term);
1711 break;
1712 case 7: /* reverse video */
1713 scp->term.attr_mask |= REVERSE_ATTR;
1714 scp->term.cur_attr = mask2attr(&scp->term);
1715 break;
1716 case 30: case 31: /* set fg color */
1717 case 32: case 33: case 34:
1718 case 35: case 36: case 37:
1719 scp->term.attr_mask |= FOREGROUND_CHANGED;
1720 scp->term.cur_color =
1721 (scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
1722 scp->term.cur_attr = mask2attr(&scp->term);
1723 break;
1724 case 40: case 41: /* set bg color */
1725 case 42: case 43: case 44:
1726 case 45: case 46: case 47:
1727 scp->term.attr_mask |= BACKGROUND_CHANGED;
1728 scp->term.cur_color =
1729 (scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
1730 scp->term.cur_attr = mask2attr(&scp->term);
1731 break;
1732 }
1733 }
1734 break;
1735
1736 case 'x':
1737 if (scp->term.num_param == 0)
1738 n = 0;
1739 else
1740 n = scp->term.param[0];
1741 switch (n) {
1742 case 0: /* reset attributes */
1743 scp->term.attr_mask = NORMAL_ATTR;
1744 scp->term.cur_attr =
1745 scp->term.cur_color = scp->term.std_color =
1746 current_default->std_color;
1747 scp->term.rev_color = current_default->rev_color;
1748 break;
1749 case 1: /* set ansi background */
1750 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
1751 scp->term.cur_color = scp->term.std_color =
1752 (scp->term.std_color & 0x0F00) |
1753 (ansi_col[(scp->term.param[1])&0x0F]<<12);
1754 scp->term.cur_attr = mask2attr(&scp->term);
1755 break;
1756 case 2: /* set ansi foreground */
1757 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
1758 scp->term.cur_color = scp->term.std_color =
1759 (scp->term.std_color & 0xF000) |
1760 (ansi_col[(scp->term.param[1])&0x0F]<<8);
1761 scp->term.cur_attr = mask2attr(&scp->term);
1762 break;
1763 case 3: /* set ansi attribute directly */
1764 scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
1765 scp->term.cur_color = scp->term.std_color =
1766 (scp->term.param[1]&0xFF)<<8;
1767 scp->term.cur_attr = mask2attr(&scp->term);
1768 break;
1769 case 5: /* set ansi reverse video background */
1770 scp->term.rev_color =
1771 (scp->term.rev_color & 0x0F00) |
1772 (ansi_col[(scp->term.param[1])&0x0F]<<12);
1773 scp->term.cur_attr = mask2attr(&scp->term);
1774 break;
1775 case 6: /* set ansi reverse video foreground */
1776 scp->term.rev_color =
1777 (scp->term.rev_color & 0xF000) |
1778 (ansi_col[(scp->term.param[1])&0x0F]<<8);
1779 scp->term.cur_attr = mask2attr(&scp->term);
1780 break;
1781 case 7: /* set ansi reverse video directly */
1782 scp->term.rev_color =
1783 (scp->term.param[1]&0xFF)<<8;
1784 scp->term.cur_attr = mask2attr(&scp->term);
1785 break;
1786 }
1787 break;
1788
1789 case 'z': /* switch to (virtual) console n */
1790 if (scp->term.num_param == 1)
1791 switch_scr(scp, scp->term.param[0]);
1792 break;
1793 }
1794 }
1795 else if (scp->term.esc == 3) {
1796 if (c >= '0' && c <= '9') {
1797 if (scp->term.num_param < MAX_ESC_PAR) {
1798 if (scp->term.last_param != scp->term.num_param) {
1799 scp->term.last_param = scp->term.num_param;
1800 scp->term.param[scp->term.num_param] = 0;
1801 }
1802 else
1803 scp->term.param[scp->term.num_param] *= 10;
1804 scp->term.param[scp->term.num_param] += c - '0';
1805 return;
1806 }
1807 }
1808 scp->term.num_param = scp->term.last_param + 1;
1809 switch (c) {
1810
1811 case ';':
1812 if (scp->term.num_param < MAX_ESC_PAR)
1813 return;
1814 break;
1815
1816 case 'A': /* set display border color */
1817 if (scp->term.num_param == 1)
1818 scp->border=scp->term.param[0] & 0xff;
1819 if (scp == cur_console)
1820 set_border(scp->border);
1821 break;
1822
1823 case 'B': /* set bell pitch and duration */
1824 if (scp->term.num_param == 2) {
1825 scp->bell_pitch = scp->term.param[0];
1826 scp->bell_duration = scp->term.param[1]*10;
1827 }
1828 break;
1829
1830 case 'C': /* set cursor type & shape */
1831 if (scp->term.num_param == 1) {
1832 if (scp->term.param[0] & 0x01)
1833 configuration |= BLINK_CURSOR;
1834 else
1835 configuration &= ~BLINK_CURSOR;
1836 if (scp->term.param[0] & 0x02) {
1837 configuration |= CHAR_CURSOR;
1838 set_destructive_cursor(scp, TRUE);
1839 } else
1840 configuration &= ~CHAR_CURSOR;
1841 }
1842 else if (scp->term.num_param == 2) {
1843 scp->cursor_start = scp->term.param[0] & 0x1F;
1844 scp->cursor_end = scp->term.param[1] & 0x1F;
1845 if (configuration & CHAR_CURSOR)
1846 set_destructive_cursor(scp, TRUE);
1847 }
1848 break;
1849
1850 case 'F': /* set ansi foreground */
1851 if (scp->term.num_param == 1) {
1852 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
1853 scp->term.cur_color = scp->term.std_color =
1854 (scp->term.std_color & 0xF000)
1855 | ((scp->term.param[0] & 0x0F) << 8);
1856 scp->term.cur_attr = mask2attr(&scp->term);
1857 }
1858 break;
1859
1860 case 'G': /* set ansi background */
1861 if (scp->term.num_param == 1) {
1862 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
1863 scp->term.cur_color = scp->term.std_color =
1864 (scp->term.std_color & 0x0F00)
1865 | ((scp->term.param[0] & 0x0F) << 12);
1866 scp->term.cur_attr = mask2attr(&scp->term);
1867 }
1868 break;
1869
1870 case 'H': /* set ansi reverse video foreground */
1871 if (scp->term.num_param == 1) {
1872 scp->term.rev_color =
1873 (scp->term.rev_color & 0xF000)
1874 | ((scp->term.param[0] & 0x0F) << 8);
1875 scp->term.cur_attr = mask2attr(&scp->term);
1876 }
1877 break;
1878
1879 case 'I': /* set ansi reverse video background */
1880 if (scp->term.num_param == 1) {
1881 scp->term.rev_color =
1882 (scp->term.rev_color & 0x0F00)
1883 | ((scp->term.param[0] & 0x0F) << 12);
1884 scp->term.cur_attr = mask2attr(&scp->term);
1885 }
1886 break;
1887 }
1888 }
1889 scp->term.esc = 0;
1890}
1891
1892static inline void
1893draw_cursor(scr_stat *scp, int show)
1894{
1895 if (show && !(scp->status & CURSOR_SHOWN)) {
1896 u_short cursor_image = *(Crtat + (scp->cursor_pos - scp->scr_buf));
1897
1898 scp->cursor_saveunder = cursor_image;
1899 if (configuration & CHAR_CURSOR) {
1900 set_destructive_cursor(scp, FALSE);
1901 cursor_image = (cursor_image & 0xff00) | DEAD_CHAR;
1902 }
1903 else {
1904 if ((cursor_image & 0x7000) == 0x7000) {
1905 cursor_image &= 0x8fff;
1906 if(!(cursor_image & 0x0700))
1907 cursor_image |= 0x0700;
1908 } else {
1909 cursor_image |= 0x7000;
1910 if ((cursor_image & 0x0700) == 0x0700)
1911 cursor_image &= 0xf0ff;
1912 }
1913 }
1914 *(Crtat + (scp->cursor_pos - scp->scr_buf)) = cursor_image;
1915 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1916 scp->status |= CURSOR_SHOWN;
1917 }
1918 if (!show && (scp->status & CURSOR_SHOWN)) {
1919 *(Crtat + (scp->cursor_pos - scp->scr_buf)) = scp->cursor_saveunder;
1920 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1921 scp->status &= ~CURSOR_SHOWN;
1922 }
1923}
1924
1925static void
1926ansi_put(scr_stat *scp, u_char *buf, int len)
1927{
1928 u_char *ptr = buf;
1929
1930 if (scp->status & UNKNOWN_MODE)
1931 return;
1932
1933 /* make screensaver happy */
1934 if (scp == cur_console) {
1935 scrn_time_stamp = time.tv_sec;
1936 if (scrn_blanked) {
1937 (*current_saver)(FALSE);
1938 cur_console->start = 0;
1939 cur_console->end = cur_console->xsize * cur_console->ysize;
1940 }
1941 }
1942 write_in_progress++;
1943outloop:
1944 if (scp->term.esc) {
1945 scan_esc(scp, *ptr++);
1946 len--;
1947 }
1948 else if (PRINTABLE(*ptr)) { /* Print only printables */
1949 int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos);
1950 u_short cur_attr = scp->term.cur_attr;
1951 u_short *cursor_pos = scp->cursor_pos;
1952 do {
1953 /*
1954 * gcc-2.6.3 generates poor (un)sign extension code. Casting the
1955 * pointers in the following to volatile should have no effect,
1956 * but in fact speeds up this inner loop from 26 to 18 cycles
1957 * (+ cache misses) on i486's.
1958 */
1959#define UCVP(ucp) ((u_char volatile *)(ucp))
1960 *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr;
1961 ptr++;
1962 cnt--;
1963 } while (cnt && PRINTABLE(*ptr));
1964 len -= (cursor_pos - scp->cursor_pos);
1965 scp->xpos += (cursor_pos - scp->cursor_pos);
1966 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1967 mark_for_update(scp, cursor_pos - scp->scr_buf);
1968 scp->cursor_pos = cursor_pos;
1969 if (scp->xpos >= scp->xsize) {
1970 scp->xpos = 0;
1971 scp->ypos++;
1972 }
1973 }
1974 else {
1975 switch(*ptr) {
1976 case 0x07:
1977 do_bell(scp, scp->bell_pitch, scp->bell_duration);
1978 break;
1979
1980 case 0x08: /* non-destructive backspace */
1981 if (scp->cursor_pos > scp->scr_buf) {
1982 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1983 scp->cursor_pos--;
1984 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1985 if (scp->xpos > 0)
1986 scp->xpos--;
1987 else {
1988 scp->xpos += scp->xsize - 1;
1989 scp->ypos--;
1990 }
1991 }
1992 break;
1993
1994 case 0x09: /* non-destructive tab */
1995 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1996 scp->cursor_pos += (8 - scp->xpos % 8u);
1997 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1998 if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
1999 scp->xpos = 0;
2000 scp->ypos++;
2001 }
2002 break;
2003
2004 case 0x0a: /* newline, same pos */
2005 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2006 scp->cursor_pos += scp->xsize;
2007 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2008 scp->ypos++;
2009 break;
2010
2011 case 0x0c: /* form feed, clears screen */
2012 clear_screen(scp);
2013 break;
2014
2015 case 0x0d: /* return, return to pos 0 */
2016 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2017 scp->cursor_pos -= scp->xpos;
2018 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2019 scp->xpos = 0;
2020 break;
2021
2022 case 0x1b: /* start escape sequence */
2023 scp->term.esc = 1;
2024 scp->term.num_param = 0;
2025 break;
2026 }
2027 ptr++; len--;
2028 }
2029 /* do we have to scroll ?? */
2030 if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) {
2031 if (scp->history) {
2032 bcopyw(scp->scr_buf, scp->history_head,
2033 scp->xsize * sizeof(u_short));
2034 scp->history_head += scp->xsize;
2035 if (scp->history_head + scp->xsize >
2036 scp->history + scp->history_size)
2037 scp->history_head = scp->history;
2038 }
2039 bcopyw(scp->scr_buf + scp->xsize, scp->scr_buf,
2040 scp->xsize * (scp->ysize - 1) * sizeof(u_short));
2041 fillw(scp->term.cur_color | scr_map[0x20],
2042 scp->scr_buf + scp->xsize * (scp->ysize - 1),
2043 scp->xsize);
2044 scp->cursor_pos -= scp->xsize;
2045 scp->ypos--;
2046 mark_all(scp);
2047 }
2048 if (len)
2049 goto outloop;
2050 write_in_progress--;
2051 if (delayed_next_scr)
2052 switch_scr(scp, delayed_next_scr - 1);
2053}
2054
2055static void
2056scinit(void)
2057{
2058 u_short volatile *cp;
2059 u_short was;
2060 unsigned hw_cursor;
2061 int i;
2062
2063 if (init_done)
2064 return;
2065 init_done = TRUE;
2066 /*
2067 * Finish defaulting crtc variables for a mono screen. Crtat is a
2068 * bogus common variable so that it can be shared with pcvt, so it
2069 * can't be statically initialized. XXX.
2070 */
2071 Crtat = (u_short *)MONO_BUF;
2072 /*
2073 * If CGA memory seems to work, switch to color.
2074 */
2075 cp = (u_short *)CGA_BUF;
2076 was = *cp;
2077 *cp = (u_short) 0xA55A;
2078 if (*cp == 0xA55A) {
2079 Crtat = (u_short *)cp;
2080 crtc_addr = COLOR_BASE;
2081 }
2082 *cp = was;
2083
2084 /*
2085 * Ensure a zero start address. This is mainly to recover after
2086 * switching from pcvt using userconfig(). The registers are w/o
2087 * for old hardware so it's too hard to relocate the active screen
2088 * memory.
2089 */
2090 outb(crtc_addr, 12);
2091 outb(crtc_addr + 1, 0);
2092 outb(crtc_addr, 13);
2093 outb(crtc_addr + 1, 0);
2094
2095 /* extract cursor location */
2096 outb(crtc_addr, 14);
2097 hw_cursor = inb(crtc_addr + 1) << 8;
2098 outb(crtc_addr, 15);
2099 hw_cursor |= inb(crtc_addr + 1);
2100
2101 /* move hardware cursor out of the way */
2102 outb(crtc_addr, 14);
2103 outb(crtc_addr + 1, 0xff);
2104 outb(crtc_addr, 15);
2105 outb(crtc_addr + 1, 0xff);
2106
2107 /* is this a VGA or higher ? */
2108 outb(crtc_addr, 7);
2109 if (inb(crtc_addr) == 7) {
2110 u_long pa;
2111 u_long segoff;
2112
2113 crtc_vga = TRUE;
2114 /*
2115 * Get the BIOS video mode pointer.
2116 */
2117 segoff = *(u_long *)pa_to_va(0x4a8);
2118 pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
2119 if (ISMAPPED(pa, sizeof(u_long))) {
2120 segoff = *(u_long *)pa_to_va(pa);
2121 pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
2122 if (ISMAPPED(pa, 64))
2123 video_mode_ptr = (char *)pa_to_va(pa);
2124 }
2125 }
2126 current_default = &user_default;
2127 console[0] = &main_console;
2128 init_scp(console[0]);
2129 console[0]->scr_buf = console[0]->mouse_pos = Crtat;
2130 console[0]->cursor_pos = Crtat + hw_cursor;
2131 console[0]->xpos = hw_cursor % COL;
2132 console[0]->ypos = hw_cursor / COL;
2133 cur_console = console[0];
2134 for (i=1; i<MAXCONS; i++)
2135 console[i] = NULL;
2136 kernel_console.esc = 0;
2137 kernel_console.attr_mask = NORMAL_ATTR;
2138 kernel_console.cur_attr =
2139 kernel_console.cur_color = kernel_console.std_color =
2140 kernel_default.std_color;
2141 kernel_console.rev_color = kernel_default.rev_color;
2142 /* initialize mapscrn array to a one to one map */
2143 for (i=0; i<sizeof(scr_map); i++)
2144 scr_map[i] = i;
2145}
2146
2147static scr_stat
2148*alloc_scp()
2149{
2150 scr_stat *scp;
2151
2152 scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
2153 init_scp(scp);
2154 scp->scr_buf = scp->cursor_pos = scp->scr_buf = scp->mouse_pos =
2155 (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
2156 M_DEVBUF, M_WAITOK);
2157 scp->history_head = scp->history_pos = scp->history =
2158 (u_short *)malloc(scp->history_size*sizeof(u_short),
2159 M_DEVBUF, M_WAITOK);
2160 bzero(scp->history_head, scp->history_size*sizeof(u_short));
2161 if (crtc_vga && video_mode_ptr)
2162 set_mode(scp);
2163 clear_screen(scp);
2164 return scp;
2165}
2166
2167static void
2168init_scp(scr_stat *scp)
2169{
2170 scp->mode = M_VGA_C80x25;
2171 scp->font = FONT_16;
2172 scp->xsize = COL;
2173 scp->ysize = ROW;
2174 scp->start = COL * ROW;
2175 scp->end = 0;
2176 scp->term.esc = 0;
2177 scp->term.attr_mask = NORMAL_ATTR;
2178 scp->term.cur_attr =
2179 scp->term.cur_color = scp->term.std_color =
2180 current_default->std_color;
2181 scp->term.rev_color = current_default->rev_color;
2182 scp->border = BG_BLACK;
2183 scp->cursor_start = *(char *)pa_to_va(0x461);
2184 scp->cursor_end = *(char *)pa_to_va(0x460);
2185 scp->mouse_xpos = scp->mouse_ypos = 0;
2186 scp->bell_pitch = BELL_PITCH;
2187 scp->bell_duration = BELL_DURATION;
2188 scp->status = (*(char *)pa_to_va(0x417) & 0x20) ? NLKED : 0;
2189 scp->status |= CURSOR_ENABLED;
2190 scp->pid = 0;
2191 scp->proc = NULL;
2192 scp->smode.mode = VT_AUTO;
2193 scp->history_head = scp->history_pos = scp->history = NULL;
2194 scp->history_size = HISTORY_SIZE;
2195}
2196
2197static u_char
2198*get_fstr(u_int c, u_int *len)
2199{
2200 u_int i;
2201
2202 if (!(c & FKEY))
2203 return(NULL);
2204 i = (c & 0xFF) - F_FN;
2205 if (i > n_fkey_tab)
2206 return(NULL);
2207 *len = fkey_tab[i].len;
2208 return(fkey_tab[i].str);
2209}
2210
2211static void
2212update_leds(int which)
2213{
2214 int s;
2215 static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
2216
2217 /* replace CAPS led with ALTGR led for ALTGR keyboards */
2218 if (key_map.n_keys > ALTGR_OFFSET) {
2219 if (which & ALKED)
2220 which |= CLKED;
2221 else
2222 which &= ~CLKED;
2223 }
2224 s = spltty();
2225 kbd_cmd(KB_SETLEDS);
2226 kbd_cmd(xlate_leds[which & LED_MASK]);
2227 splx(s);
2228}
2229
2230static void
2231history_to_screen(scr_stat *scp)
2232{
2233 int i;
2234
2235 for (i=0; i<scp->ysize; i++)
2236 bcopyw(scp->history + (((scp->history_pos - scp->history) +
2237 scp->history_size-((i+1)*scp->xsize))%scp->history_size),
2238 scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)),
2239 scp->xsize * sizeof(u_short));
2240 mark_all(scp);
2241}
2242
2243static int
2244history_up_line(scr_stat *scp)
2245{
2246 if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) !=
2247 scp->history_head) {
2248 scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize);
2249 history_to_screen(scp);
2250 return 0;
2251 }
2252 else
2253 return -1;
2254}
2255
2256static int
2257history_down_line(scr_stat *scp)
2258{
2259 if (scp->history_pos != scp->history_head) {
2260 scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize);
2261 history_to_screen(scp);
2262 return 0;
2263 }
2264 else
2265 return -1;
2266}
2267
2268/*
2269 * scgetc(noblock) - get character from keyboard.
2270 * If noblock = 0 wait until a key is pressed.
2271 * Else return NOKEY.
2272 */
2273u_int
2274scgetc(int noblock)
2275{
2276 u_char scancode, keycode;
2277 u_int state, action;
2278 struct key_t *key;
2279 static u_char esc_flag = 0, compose = 0;
2280 static u_int chr = 0;
2281
2282next_code:
2283 kbd_wait();
2284 /* First see if there is something in the keyboard port */
2285 if (inb(KB_STAT) & KB_BUF_FULL)
2286 scancode = inb(KB_DATA);
2287 else if (noblock)
2288 return(NOKEY);
2289 else
2290 goto next_code;
2291
2292 add_keyboard_randomness(scancode);
2293
2294 if (cur_console->status & KBD_RAW_MODE)
2295 return scancode;
2296#if ASYNCH
2297 if (scancode == KB_ACK || scancode == KB_RESEND) {
2298 kbd_reply = scancode;
2299 if (noblock)
2300 return(NOKEY);
2301 goto next_code;
2302 }
2303#endif
2304 keycode = scancode & 0x7F;
2305 switch (esc_flag) {
2306 case 0x00: /* normal scancode */
2307 switch(scancode) {
2308 case 0xB8: /* left alt (compose key) */
2309 if (compose) {
2310 compose = 0;
2311 if (chr > 255) {
2312 do_bell(cur_console,
2313 BELL_PITCH, BELL_DURATION);
2314 chr = 0;
2315 }
2316 }
2317 break;
2318 case 0x38:
2319 if (!compose) {
2320 compose = 1;
2321 chr = 0;
2322 }
2323 break;
2324 case 0xE0:
2325 case 0xE1:
2326 esc_flag = scancode;
2327 goto next_code;
2328 }
2329 break;
2330 case 0xE0: /* 0xE0 prefix */
2331 esc_flag = 0;
2332 switch (keycode) {
2333 case 0x1C: /* right enter key */
2334 keycode = 0x59;
2335 break;
2336 case 0x1D: /* right ctrl key */
2337 keycode = 0x5A;
2338 break;
2339 case 0x35: /* keypad divide key */
2340 keycode = 0x5B;
2341 break;
2342 case 0x37: /* print scrn key */
2343 keycode = 0x5C;
2344 break;
2345 case 0x38: /* right alt key (alt gr) */
2346 keycode = 0x5D;
2347 break;
2348 case 0x47: /* grey home key */
2349 keycode = 0x5E;
2350 break;
2351 case 0x48: /* grey up arrow key */
2352 keycode = 0x5F;
2353 break;
2354 case 0x49: /* grey page up key */
2355 keycode = 0x60;
2356 break;
2357 case 0x4B: /* grey left arrow key */
2358 keycode = 0x61;
2359 break;
2360 case 0x4D: /* grey right arrow key */
2361 keycode = 0x62;
2362 break;
2363 case 0x4F: /* grey end key */
2364 keycode = 0x63;
2365 break;
2366 case 0x50: /* grey down arrow key */
2367 keycode = 0x64;
2368 break;
2369 case 0x51: /* grey page down key */
2370 keycode = 0x65;
2371 break;
2372 case 0x52: /* grey insert key */
2373 keycode = 0x66;
2374 break;
2375 case 0x53: /* grey delete key */
2376 keycode = 0x67;
2377 break;
2378
2379 /* the following 3 are only used on the MS "Natural" keyboard */
2380 case 0x5b: /* left Window key */
2381 keycode = 0x69;
2382 break;
2383 case 0x5c: /* right Window key */
2384 keycode = 0x6a;
2385 break;
2386 case 0x5d: /* menu key */
2387 keycode = 0x6b;
2388 break;
2389 default: /* ignore everything else */
2390 goto next_code;
2391 }
2392 break;
2393 case 0xE1: /* 0xE1 prefix */
2394 esc_flag = 0;
2395 if (keycode == 0x1D)
2396 esc_flag = 0x1D;
2397 goto next_code;
2398 /* NOT REACHED */
2399 case 0x1D: /* pause / break */
2400 esc_flag = 0;
2401 if (keycode != 0x45)
2402 goto next_code;
2403 keycode = 0x68;
2404 break;
2405 }
2406
2407 /* if scroll-lock pressed allow history browsing */
2408 if (cur_console->history && cur_console->status & SLKED) {
2409 int i;
2410
2411 cur_console->status &= ~CURSOR_ENABLED;
2412 if (!(cur_console->status & BUFFER_SAVED)) {
2413 cur_console->status |= BUFFER_SAVED;
2414 cur_console->history_save = cur_console->history_head;
2415
2416 /* copy screen into top of history buffer */
2417 for (i=0; i<cur_console->ysize; i++) {
2418 bcopyw(cur_console->scr_buf + (cur_console->xsize * i),
2419 cur_console->history_head,
2420 cur_console->xsize * sizeof(u_short));
2421 cur_console->history_head += cur_console->xsize;
2422 if (cur_console->history_head + cur_console->xsize >
2423 cur_console->history + cur_console->history_size)
2424 cur_console->history_head=cur_console->history;
2425 }
2426 cur_console->history_pos = cur_console->history_head;
2427 history_to_screen(cur_console);
2428 }
2429 switch (scancode) {
2430 case 0x47: /* home key */
2431 cur_console->history_pos = cur_console->history_head;
2432 history_to_screen(cur_console);
2433 goto next_code;
2434
2435 case 0x4F: /* end key */
2436 cur_console->history_pos =
2437 WRAPHIST(cur_console, cur_console->history_head,
2438 cur_console->xsize*cur_console->ysize);
2439 history_to_screen(cur_console);
2440 goto next_code;
2441
2442 case 0x48: /* up arrow key */
2443 if (history_up_line(cur_console))
2444 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2445 goto next_code;
2446
2447 case 0x50: /* down arrow key */
2448 if (history_down_line(cur_console))
2449 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2450 goto next_code;
2451
2452 case 0x49: /* page up key */
2453 for (i=0; i<cur_console->ysize; i++)
2454 if (history_up_line(cur_console)) {
2455 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2456 break;
2457 }
2458 goto next_code;
2459
2460 case 0x51: /* page down key */
2461 for (i=0; i<cur_console->ysize; i++)
2462 if (history_down_line(cur_console)) {
2463 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2464 break;
2465 }
2466 goto next_code;
2467 }
2468 }
2469
2470 if (compose) {
2471 switch (scancode) {
2472 /* key pressed process it */
2473 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
2474 chr = (scancode - 0x40) + chr*10;
2475 goto next_code;
2476 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
2477 chr = (scancode - 0x47) + chr*10;
2478 goto next_code;
2479 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
2480 chr = (scancode - 0x4E) + chr*10;
2481 goto next_code;
2482 case 0x52: /* keypad 0 */
2483 chr *= 10;
2484 goto next_code;
2485
2486 /* key release, no interest here */
2487 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
2488 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
2489 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
2490 case 0xD2: /* keypad 0 */
2491 goto next_code;
2492
2493 case 0x38: /* left alt key */
2494 break;
2495 default:
2496 if (chr) {
2497 compose = chr = 0;
2498 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2499 goto next_code;
2500 }
2501 break;
2502 }
2503 }
2504
2505 state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
2506 if ((!agrs && (cur_console->status & ALKED))
2507 || (agrs && !(cur_console->status & ALKED)))
2508 keycode += ALTGR_OFFSET;
2509 key = &key_map.key[keycode];
2510 if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
2511 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
2512 state ^= 1;
2513
2514 /* Check for make/break */
2515 action = key->map[state];
2516 if (scancode & 0x80) { /* key released */
2517 if (key->spcl & 0x80) {
2518 switch (action) {
2519 case LSH:
2520 shfts &= ~1;
2521 break;
2522 case RSH:
2523 shfts &= ~2;
2524 break;
2525 case LCTR:
2526 ctls &= ~1;
2527 break;
2528 case RCTR:
2529 ctls &= ~2;
2530 break;
2531 case LALT:
2532 alts &= ~1;
2533 break;
2534 case RALT:
2535 alts &= ~2;
2536 break;
2537 case NLK:
2538 nlkcnt = 0;
2539 break;
2540 case CLK:
2541 clkcnt = 0;
2542 break;
2543 case SLK:
2544 slkcnt = 0;
2545 break;
2546 case ASH:
2547 agrs = 0;
2548 break;
2549 case ALK:
2550 alkcnt = 0;
2551 break;
2552 case META:
2553 metas = 0;
2554 break;
2555 }
2556 }
2557 if (chr && !compose) {
2558 action = chr;
2559 chr = 0;
2560 return(action);
2561 }
2562 } else {
2563 /* key pressed */
2564 if (key->spcl & (0x80>>state)) {
2565 switch (action) {
2566 /* LOCKING KEYS */
2567 case NLK:
2568 if (!nlkcnt) {
2569 nlkcnt++;
2570 if (cur_console->status & NLKED)
2571 cur_console->status &= ~NLKED;
2572 else
2573 cur_console->status |= NLKED;
2574 update_leds(cur_console->status);
2575 }
2576 break;
2577 case CLK:
2578 if (!clkcnt) {
2579 clkcnt++;
2580 if (cur_console->status & CLKED)
2581 cur_console->status &= ~CLKED;
2582 else
2583 cur_console->status |= CLKED;
2584 update_leds(cur_console->status);
2585 }
2586 break;
2587 case SLK:
2588 if (!slkcnt) {
2589 slkcnt++;
2590 if (cur_console->status & SLKED) {
2591 cur_console->status &= ~SLKED;
2592 if (cur_console->status & BUFFER_SAVED){
2593 int i;
2594 u_short *ptr = cur_console->history_save;
2595
2596 for (i=0; i<cur_console->ysize; i++) {
2597 bcopyw(ptr,
2598 cur_console->scr_buf +
2599 (cur_console->xsize*i),
2600 cur_console->xsize * sizeof(u_short));
2601 ptr += cur_console->xsize;
2602 if (ptr + cur_console->xsize >
2603 cur_console->history +
2604 cur_console->history_size)
2605 ptr = cur_console->history;
2606 }
2607 cur_console->status &= ~BUFFER_SAVED;
2608 cur_console->history_head=cur_console->history_save;
2609 cur_console->status |= CURSOR_ENABLED;
2610 mark_all(cur_console);
2611 }
2612 scstart(VIRTUAL_TTY(get_scr_num()));
2613 }
2614 else
2615 cur_console->status |= SLKED;
2616 update_leds(cur_console->status);
2617 }
2618 break;
2619 case ALK:
2620 if (!alkcnt) {
2621 alkcnt++;
2622 if (cur_console->status & ALKED)
2623 cur_console->status &= ~ALKED;
2624 else
2625 cur_console->status |= ALKED;
2626 update_leds(cur_console->status);
2627 }
2628 break;
2629
2630 /* NON-LOCKING KEYS */
2631 case NOP:
2632 break;
2633 case RBT:
2634 shutdown_nice();
2635 break;
2636 case SUSP:
2637#if NAPM > 0
2638 apm_suspend();
2639#endif
2640 break;
2641
2642 case DBG:
2643#ifdef DDB /* try to switch to console 0 */
2644 if (cur_console->smode.mode == VT_AUTO &&
2645 console[0]->smode.mode == VT_AUTO)
2646 switch_scr(cur_console, 0);
2647 Debugger("manual escape to debugger");
2648 return(NOKEY);
2649#else
2650 printf("No debugger in kernel\n");
2651#endif
2652 break;
2653 case LSH:
2654 shfts |= 1;
2655 break;
2656 case RSH:
2657 shfts |= 2;
2658 break;
2659 case LCTR:
2660 ctls |= 1;
2661 break;
2662 case RCTR:
2663 ctls |= 2;
2664 break;
2665 case LALT:
2666 alts |= 1;
2667 break;
2668 case RALT:
2669 alts |= 2;
2670 break;
2671 case ASH:
2672 agrs = 1;
2673 break;
2674 case META:
2675 metas = 1;
2676 break;
2677 case NEXT:
2678 switch_scr(cur_console, (get_scr_num() + 1) % MAXCONS);
2679 break;
2680 case BTAB:
2681 return(BKEY);
2682 default:
2683 if (action >= F_SCR && action <= L_SCR) {
2684 switch_scr(cur_console, action - F_SCR);
2685 break;
2686 }
2687 if (action >= F_FN && action <= L_FN)
2688 action |= FKEY;
2689 return(action);
2690 }
2691 }
2692 else {
2693 if (metas)
2694 action |= MKEY;
2695 return(action);
2696 }
2697 }
2698 goto next_code;
2699}
2700
2701int
2702scmmap(dev_t dev, int offset, int nprot)
2703{
2704 if (offset > 0x20000 - PAGE_SIZE)
2705 return -1;
2706 return i386_btop((VIDEOMEM + offset));
2707}
2708
2709static void
2710kbd_wait(void)
2711{
2712 int i = 1000;
2713
2714 while (i--) {
2715 if ((inb(KB_STAT) & KB_READY) == 0)
2716 break;
2717 DELAY (10);
2718 }
2719}
2720
2721static void
2722kbd_cmd(u_char command)
2723{
2724 int retry = 5;
2725 do {
2726 int i = 100000;
2727
2728 kbd_wait();
2729#if ASYNCH
2730 kbd_reply = 0;
2731 outb(KB_DATA, command);
2732 while (i--) {
2733 if (kbd_reply == KB_ACK)
2734 return;
2735 if (kbd_reply == KB_RESEND)
2736 break;
2737 }
2738#else
2739 outb(KB_DATA, command);
2740 while (i--) {
2741 if (inb(KB_STAT) & KB_BUF_FULL) {
2742 int val;
2743 DELAY(10);
2744 val = inb(KB_DATA);
2745 if (val == KB_ACK)
2746 return;
2747 if (val == KB_RESEND)
2748 break;
2749 }
2750 }
2751#endif
2752 } while (retry--);
2753}
2754
2755static void
2756set_mode(scr_stat *scp)
2757{
2758 char *modetable;
2759 char special_modetable[64];
2760 int font_size;
2761
2762 if (scp != cur_console)
2763 return;
2764
2765 /* setup video hardware for the given mode */
2766 switch (scp->mode) {
2767 case M_VGA_M80x60:
2768 bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64);
2769 goto special_80x60;
2770
2771 case M_VGA_C80x60:
2772 bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64);
2773special_80x60:
2774 special_modetable[2] = 0x08;
2775 special_modetable[19] = 0x47;
2776 goto special_480l;
2777
2778 case M_VGA_M80x30:
2779 bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64);
2780 goto special_80x30;
2781
2782 case M_VGA_C80x30:
2783 bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64);
2784special_80x30:
2785 special_modetable[19] = 0x4f;
2786special_480l:
2787 special_modetable[9] |= 0xc0;
2788 special_modetable[16] = 0x08;
2789 special_modetable[17] = 0x3e;
2790 special_modetable[26] = 0xea;
2791 special_modetable[28] = 0xdf;
2792 special_modetable[31] = 0xe7;
2793 special_modetable[32] = 0x04;
2794 modetable = special_modetable;
2795 goto setup_mode;
2796
2797 case M_ENH_B80x43:
2798 bcopyw(video_mode_ptr+(64*M_ENH_B80x25),&special_modetable, 64);
2799 goto special_80x43;
2800
2801 case M_ENH_C80x43:
2802 bcopyw(video_mode_ptr+(64*M_ENH_C80x25),&special_modetable, 64);
2803special_80x43:
2804 special_modetable[28] = 87;
2805 goto special_80x50;
2806
2807 case M_VGA_M80x50:
2808 bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64);
2809 goto special_80x50;
2810
2811 case M_VGA_C80x50:
2812 bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64);
2813special_80x50:
2814 special_modetable[2] = 8;
2815 special_modetable[19] = 7;
2816 modetable = special_modetable;
2817 goto setup_mode;
2818
2819 case M_VGA_C40x25: case M_VGA_C80x25:
2820 case M_VGA_M80x25:
2821 case M_B40x25: case M_C40x25:
2822 case M_B80x25: case M_C80x25:
2823 case M_ENH_B40x25: case M_ENH_C40x25:
2824 case M_ENH_B80x25: case M_ENH_C80x25:
2825
2826 modetable = video_mode_ptr + (scp->mode * 64);
2827setup_mode:
2828 set_vgaregs(modetable);
2829 font_size = *(modetable + 2);
2830
2831 /* set font type (size) */
2832 switch (font_size) {
2833 case 0x10:
2834 outb(TSIDX, 0x03); outb(TSREG, 0x00); /* font 0 */
2835 scp->font = FONT_16;
2836 break;
2837 case 0x0E:
2838 outb(TSIDX, 0x03); outb(TSREG, 0x05); /* font 1 */
2839 scp->font = FONT_14;
2840 break;
2841 default:
2842 case 0x08:
2843 outb(TSIDX, 0x03); outb(TSREG, 0x0A); /* font 2 */
2844 scp->font = FONT_8;
2845 break;
2846 }
2847 if (configuration & CHAR_CURSOR)
2848 set_destructive_cursor(scp, TRUE);
2849 break;
2850
2851 case M_BG320: case M_CG320: case M_BG640:
2852 case M_CG320_D: case M_CG640_E:
2853 case M_CG640x350: case M_ENH_CG640:
2854 case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
2855
2856 set_vgaregs(video_mode_ptr + (scp->mode * 64));
2857 break;
2858
2859 default:
2860 /* call user defined function XXX */
2861 break;
2862 }
2863
2864 /* set border color for this (virtual) console */
2865 set_border(scp->border);
2866 return;
2867}
2868
2869void
2870set_border(int color)
2871{
2872 inb(crtc_addr+6); /* reset flip-flop */
2873 outb(ATC, 0x11); outb(ATC, color);
2874 inb(crtc_addr+6); /* reset flip-flop */
2875 outb(ATC, 0x20); /* enable Palette */
2876}
2877
2878static void
2879set_vgaregs(char *modetable)
2880{
2881 int i, s = splhigh();
2882
2883 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */
2884 outb(TSIDX, 0x07); outb(TSREG, 0x00); /* unlock registers */
2885 for (i=0; i<4; i++) { /* program sequencer */
2886 outb(TSIDX, i+1);
2887 outb(TSREG, modetable[i+5]);
2888 }
2889 outb(MISC, modetable[9]); /* set dot-clock */
2890 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */
2891 outb(crtc_addr, 0x11);
2892 outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F);
2893 for (i=0; i<25; i++) { /* program crtc */
2894 outb(crtc_addr, i);
2895 if (i == 14 || i == 15) /* no hardware cursor */
2896 outb(crtc_addr+1, 0xff);
2897 else
2898 outb(crtc_addr+1, modetable[i+10]);
2899 }
2900 inb(crtc_addr+6); /* reset flip-flop */
2901 for (i=0; i<20; i++) { /* program attribute ctrl */
2902 outb(ATC, i);
2903 outb(ATC, modetable[i+35]);
2904 }
2905 for (i=0; i<9; i++) { /* program graph data ctrl */
2906 outb(GDCIDX, i);
2907 outb(GDCREG, modetable[i+55]);
2908 }
2909 inb(crtc_addr+6); /* reset flip-flop */
2910 outb(ATC ,0x20); /* enable palette */
2911 splx(s);
2912}
2913
2914static void
2915set_font_mode()
2916{
2917 /* setup vga for loading fonts (graphics plane mode) */
2918 inb(crtc_addr+6);
2919 outb(ATC, 0x30); outb(ATC, 0x01);
2920#if SLOW_VGA
2921 outb(TSIDX, 0x02); outb(TSREG, 0x04);
2922 outb(TSIDX, 0x04); outb(TSREG, 0x06);
2923 outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
2924 outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
2925 outb(GDCIDX, 0x06); outb(GDCREG, 0x05);
2926#else
2927 outw(TSIDX, 0x0402);
2928 outw(TSIDX, 0x0604);
2929 outw(GDCIDX, 0x0204);
2930 outw(GDCIDX, 0x0005);
2931 outw(GDCIDX, 0x0506); /* addr = a0000, 64kb */
2932#endif
2933}
2934
2935static void
2936set_normal_mode()
2937{
2938 int s = splhigh();
2939
2940 /* setup vga for normal operation mode again */
2941 inb(crtc_addr+6);
2942 outb(ATC, 0x30); outb(ATC, 0x0C);
2943#if SLOW_VGA
2944 outb(TSIDX, 0x02); outb(TSREG, 0x03);
2945 outb(TSIDX, 0x04); outb(TSREG, 0x02);
2946 outb(GDCIDX, 0x04); outb(GDCREG, 0x00);
2947 outb(GDCIDX, 0x05); outb(GDCREG, 0x10);
2948 if (crtc_addr == MONO_BASE) {
2949 outb(GDCIDX, 0x06); outb(GDCREG, 0x0A); /* addr = b0000, 32kb */
2950 }
2951 else {
2952 outb(GDCIDX, 0x06); outb(GDCREG, 0x0E); /* addr = b8000, 32kb */
2953 }
2954#else
2955 outw(TSIDX, 0x0302);
2956 outw(TSIDX, 0x0204);
2957 outw(GDCIDX, 0x0004);
2958 outw(GDCIDX, 0x1005);
2959 if (crtc_addr == MONO_BASE)
2960 outw(GDCIDX, 0x0A06); /* addr = b0000, 32kb */
2961 else
2962 outw(GDCIDX, 0x0E06); /* addr = b8000, 32kb */
2963#endif
2964 splx(s);
2965}
2966
2967static void
2968copy_font(int operation, int font_type, char* font_image)
2969{
2970 int ch, line, segment, fontsize;
2971 u_char val;
2972
2973 switch (font_type) {
2974 default:
2975 case FONT_8:
2976 segment = 0x8000;
2977 fontsize = 8;
2978 break;
2979 case FONT_14:
2980 segment = 0x4000;
2981 fontsize = 14;
2982 break;
2983 case FONT_16:
2984 segment = 0x0000;
2985 fontsize = 16;
2986 break;
2987 }
2988 outb(TSIDX, 0x01); val = inb(TSREG); /* disable screen */
2989 outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
2990 set_font_mode();
2991 for (ch=0; ch < 256; ch++)
2992 for (line=0; line < fontsize; line++)
2993 if (operation)
2994 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line) =
2995 font_image[(ch*fontsize)+line];
2996 else
2997 font_image[(ch*fontsize)+line] =
2998 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line);
2999 set_normal_mode();
3000 outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); /* enable screen */
3001}
3002
3003static void
3004set_destructive_cursor(scr_stat *scp, int force)
3005{
3006 u_char cursor[32];
3007 caddr_t address;
3008 int i, font_size;
3009 char *font_buffer;
3010 static u_char old_saveunder = DEAD_CHAR;
3011
3012 if (!force && (scp->cursor_saveunder & 0xFF) == old_saveunder)
3013 return;
3014 old_saveunder = force ? DEAD_CHAR : scp->cursor_saveunder & 0xFF;
3015 switch (scp->font) {
3016 default:
3017 case FONT_8:
3018 font_size = 8;
3019 font_buffer = font_8;
3020 address = (caddr_t)VIDEOMEM + 0x8000;
3021 break;
3022 case FONT_14:
3023 font_size = 14;
3024 font_buffer = font_14;
3025 address = (caddr_t)VIDEOMEM + 0x4000;
3026 break;
3027 case FONT_16:
3028 font_size = 16;
3029 font_buffer = font_16;
3030 address = (caddr_t)VIDEOMEM;
3031 break;
3032 }
3033 bcopyw(font_buffer + ((scp->cursor_saveunder & 0xff) * font_size),
3034 cursor, font_size);
3035 for (i=0; i<32; i++)
3036 if ((i >= scp->cursor_start && i <= scp->cursor_end) ||
3037 (scp->cursor_start >= font_size && i == font_size - 1))
3038 cursor[i] |= 0xff;
3039 while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
3040 set_font_mode();
3041 bcopy(cursor, (char *)pa_to_va(address) + DEAD_CHAR * 32, 32);
3042 set_normal_mode();
3043}
3044
3045static void
3046draw_mouse_image(scr_stat *scp)
3047{
3048 caddr_t address;
3049 int i, font_size;
3050 char *font_buffer;
3051 u_short buffer[32];
3052 u_short xoffset, yoffset;
3053 u_short *crt_pos = Crtat + (scp->mouse_pos - scp->scr_buf);
3054
3055 xoffset = scp->mouse_xpos % 8;
3056 switch (scp->font) {
3057 default:
3058 case FONT_8:
3059 font_size = 8;
3060 font_buffer = font_8;
3061 yoffset = scp->mouse_ypos % 8;
3062 address = (caddr_t)VIDEOMEM + 0x8000;
3063 break;
3064 case FONT_14:
3065 font_size = 14;
3066 font_buffer = font_14;
3067 yoffset = scp->mouse_ypos % 14;
3068 address = (caddr_t)VIDEOMEM + 0x4000;
3069 break;
3070 case FONT_16:
3071 font_size = 16;
3072 font_buffer = font_16;
3073 yoffset = scp->mouse_ypos % 16;
3074 address = (caddr_t)VIDEOMEM;
3075 break;
3076 }
3077
3078 bcopyw(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size),
3079 &scp->mouse_cursor[0], font_size);
3080 bcopyw(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size),
3081 &scp->mouse_cursor[32], font_size);
3082 bcopyw(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size),
3083 &scp->mouse_cursor[64], font_size);
3084 bcopyw(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size),
3085 &scp->mouse_cursor[96], font_size);
3086
3087 for (i=0; i<font_size; i++) {
3088 buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32];
3089 buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96];
3090 }
3091 for (i=0; i<16; i++) {
3092 buffer[i+yoffset] =
3093 ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset))
3094 | (mouse_or_mask[i] >> xoffset);
3095 }
3096 for (i=0; i<font_size; i++) {
3097 scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8;
3098 scp->mouse_cursor[i+32] = buffer[i] & 0xff;
3099 scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8;
3100 scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff;
3101 }
3102 if (scp->status & UPDATE_MOUSE) {
3103 u_short *ptr = scp->scr_buf + (scp->mouse_oldpos - Crtat);
3104
3105 if (crt_pos != scp->mouse_oldpos) {
3106 *(scp->mouse_oldpos) = scp->mouse_saveunder[0];
3107 *(scp->mouse_oldpos+1) = scp->mouse_saveunder[1];
3108 *(scp->mouse_oldpos+scp->xsize) = scp->mouse_saveunder[2];
3109 *(scp->mouse_oldpos+scp->xsize+1) = scp->mouse_saveunder[3];
3110 }
3111 scp->mouse_saveunder[0] = *(scp->mouse_pos);
3112 scp->mouse_saveunder[1] = *(scp->mouse_pos+1);
3113 scp->mouse_saveunder[2] = *(scp->mouse_pos+scp->xsize);
3114 scp->mouse_saveunder[3] = *(scp->mouse_pos+scp->xsize+1);
3115 if ((scp->cursor_pos == (ptr)) ||
3116 (scp->cursor_pos == (ptr+1)) ||
3117 (scp->cursor_pos == (ptr+scp->xsize)) ||
3118 (scp->cursor_pos == (ptr+scp->xsize+1)) ||
3119 (scp->cursor_pos == (scp->mouse_pos)) ||
3120 (scp->cursor_pos == (scp->mouse_pos+1)) ||
3121 (scp->cursor_pos == (scp->mouse_pos+scp->xsize)) ||
3122 (scp->cursor_pos == (scp->mouse_pos+scp->xsize+1)))
3123 scp->status &= ~CURSOR_SHOWN;
3124 }
3125 scp->mouse_oldpos = crt_pos;
3126 while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
3127 *(crt_pos) = (*(scp->mouse_pos)&0xff00)|0xd0;
3128 *(crt_pos+1) = (*(scp->mouse_pos+1)&0xff00)|0xd1;
3129 *(crt_pos+scp->xsize) = (*(scp->mouse_pos+scp->xsize)&0xff00)|0xd2;
3130 *(crt_pos+scp->xsize+1) = (*(scp->mouse_pos+scp->xsize+1)&0xff00)|0xd3;
3131 set_font_mode();
3132 bcopy(scp->mouse_cursor, (char *)pa_to_va(address) + 0xd0 * 32, 128);
3133 set_normal_mode();
3134}
3135
3136static void
3137save_palette(void)
3138{
3139 int i;
3140
3141 outb(PALRADR, 0x00);
3142 for (i=0x00; i<0x300; i++)
3143 palette[i] = inb(PALDATA);
3144 inb(crtc_addr+6); /* reset flip/flop */
3145}
3146
3147void
3148load_palette(void)
3149{
3150 int i;
3151
3152 outb(PIXMASK, 0xFF); /* no pixelmask */
3153 outb(PALWADR, 0x00);
3154 for (i=0x00; i<0x300; i++)
3155 outb(PALDATA, palette[i]);
3156 inb(crtc_addr+6); /* reset flip/flop */
3157 outb(ATC, 0x20); /* enable palette */
3158}
3159
3160static void
3161do_bell(scr_stat *scp, int pitch, int duration)
3162{
3163 if (scp == cur_console) {
3164 if (configuration & VISUAL_BELL) {
3165 if (blink_in_progress)
3166 return;
3167 blink_in_progress = 4;
3168 blink_screen(scp);
3169 timeout((timeout_func_t)blink_screen, scp, hz/10);
3170 }
3171 else
3172 sysbeep(pitch, duration);
3173 }
3174}
3175
3176static void
3177blink_screen(scr_stat *scp)
3178{
3179 if (blink_in_progress > 1) {
3180 if (blink_in_progress & 1)
3181 fillw(kernel_default.std_color | scr_map[0x20],
3182 Crtat, scp->xsize * scp->ysize);
3183 else
3184 fillw(kernel_default.rev_color | scr_map[0x20],
3185 Crtat, scp->xsize * scp->ysize);
3186 blink_in_progress--;
3187 timeout((timeout_func_t)blink_screen, scp, hz/10);
3188 }
3189 else {
3190 blink_in_progress = FALSE;
3191 mark_all(scp);
3192 if (delayed_next_scr)
3193 switch_scr(scp, delayed_next_scr - 1);
3194 }
3195}
3196
3197#endif /* NSC */
35#if NSC > 0
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/conf.h>
39#include <sys/ioctl.h>
40#include <sys/proc.h>
41#include <sys/signalvar.h>
42#include <sys/tty.h>
43#include <sys/uio.h>
44#include <sys/callout.h>
45#include <sys/kernel.h>
46#include <sys/syslog.h>
47#include <sys/errno.h>
48#include <sys/malloc.h>
49#include <sys/devconf.h>
50#ifdef DEVFS
51#include <sys/devfsext.h>
52#endif
53
54#include <machine/clock.h>
55#include <machine/cons.h>
56#include <machine/console.h>
57#include <machine/psl.h>
58#include <machine/frame.h>
59#include <machine/pc/display.h>
60#include <machine/apm_bios.h>
61#include <machine/random.h>
62
63#include <vm/vm.h>
64#include <vm/vm_param.h>
65#include <vm/pmap.h>
66
67#include <i386/isa/isa.h>
68#include <i386/isa/isa_device.h>
69#include <i386/isa/timerreg.h>
70#include <i386/isa/kbdtables.h>
71#include <i386/isa/syscons.h>
72
73#if !defined(MAXCONS)
74#define MAXCONS 16
75#endif
76
77
78/* this may break on older VGA's but is usefull on real 32 bit systems */
79#define bcopyw bcopy
80
81static default_attr user_default = {
82 (FG_LIGHTGREY | BG_BLACK) << 8,
83 (FG_BLACK | BG_LIGHTGREY) << 8
84};
85
86static default_attr kernel_default = {
87 (FG_WHITE | BG_BLACK) << 8,
88 (FG_BLACK | BG_LIGHTGREY) << 8
89};
90
91static scr_stat main_console;
92static scr_stat *console[MAXCONS];
93static void *sc_devfs_token[MAXCONS];
94 scr_stat *cur_console;
95static scr_stat *new_scp, *old_scp;
96static term_stat kernel_console;
97static default_attr *current_default;
98static char init_done = FALSE;
99static int configuration = 0;
100static char switch_in_progress = FALSE;
101static char blink_in_progress = FALSE;
102static char write_in_progress = FALSE;
103 u_int crtc_addr = MONO_BASE;
104static char crtc_vga = FALSE;
105static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
106static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
107static char *font_8 = NULL, *font_14 = NULL, *font_16 = NULL;
108static int fonts_loaded = 0;
109 char palette[3*256];
110static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
111static int delayed_next_scr = FALSE;
112static long scrn_blank_time = 0; /* screen saver timeout value */
113 int scrn_blanked = FALSE; /* screen saver active flag */
114static long scrn_time_stamp;
115 u_char scr_map[256];
116static char *video_mode_ptr = NULL;
117#if ASYNCH
118static u_char kbd_reply = 0;
119#endif
120
121static u_short mouse_and_mask[16] = {
122 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
123 0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
124};
125static u_short mouse_or_mask[16] = {
126 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
127 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
128};
129
130static void none_saver(int blank) { }
131
132void (*current_saver) __P((int blank)) = none_saver;
133
134static int scattach(struct isa_device *dev);
135static int scparam(struct tty *tp, struct termios *t);
136static int scprobe(struct isa_device *dev);
137static void scstart(struct tty *tp);
138
139/* OS specific stuff */
140#ifdef not_yet_done
141#define VIRTUAL_TTY(x) (sccons[x] = ttymalloc(sccons[x]))
142struct CONSOLE_TTY (sccons[MAXCONS] = ttymalloc(sccons[MAXCONS]))
143struct tty *sccons[MAXCONS+1];
144#else
145#define VIRTUAL_TTY(x) &sccons[x]
146#define CONSOLE_TTY &sccons[MAXCONS]
147static struct tty sccons[MAXCONS+1];
148#endif
149#define MONO_BUF pa_to_va(0xB0000)
150#define CGA_BUF pa_to_va(0xB8000)
151u_short *Crtat;
152
153#define WRAPHIST(scp, pointer, offset)\
154 ((scp->history) + ((((pointer) - (scp->history)) + (scp->history_size)\
155 + (offset)) % (scp->history_size)))
156
157struct isa_driver scdriver = {
158 scprobe, scattach, "sc", 1
159};
160
161static d_open_t scopen;
162static d_close_t scclose;
163static d_read_t scread;
164static d_write_t scwrite;
165static d_ioctl_t scioctl;
166static d_devtotty_t scdevtotty;
167static d_mmap_t scmmap;
168
169#define CDEV_MAJOR 12
170static struct cdevsw scdevsw = {
171 scopen, scclose, scread, scwrite,
172 scioctl, nullstop, noreset, scdevtotty,
173 ttselect, scmmap, nostrategy, "sc", NULL, -1 };
174
175/*
176 * Calculate hardware attributes word using logical attributes mask and
177 * hardware colors
178 */
179
180static int
181mask2attr(struct term_stat *term)
182{
183 int attr, mask = term->attr_mask;
184
185 if (mask & REVERSE_ATTR) {
186 attr = ((mask & FOREGROUND_CHANGED) ?
187 ((term->cur_color & 0xF000) >> 4) :
188 (term->rev_color & 0x0F00)) |
189 ((mask & BACKGROUND_CHANGED) ?
190 ((term->cur_color & 0x0F00) << 4) :
191 (term->rev_color & 0xF000));
192 } else
193 attr = term->cur_color;
194
195 /* XXX: underline mapping for Hercules adapter can be better */
196 if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
197 attr ^= 0x0800;
198 if (mask & BLINK_ATTR)
199 attr ^= 0x8000;
200
201 return attr;
202}
203
204static int
205scprobe(struct isa_device *dev)
206{
207 int i, retries = 5;
208 unsigned char val;
209
210 /* Enable interrupts and keyboard controller */
211 kbd_wait();
212 outb(KB_STAT, KB_WRITE);
213 kbd_wait();
214 outb(KB_DATA, KB_MODE);
215
216 /* flush any noise in the buffer */
217 while (inb(KB_STAT) & KB_BUF_FULL) {
218 DELAY(10);
219 (void) inb(KB_DATA);
220 }
221
222 /* Reset keyboard hardware */
223 while (retries--) {
224 kbd_wait();
225 outb(KB_DATA, KB_RESET);
226 for (i=0; i<100000; i++) {
227 DELAY(10);
228 val = inb(KB_DATA);
229 if (val == KB_ACK || val == KB_ECHO)
230 goto gotres;
231 if (val == KB_RESEND)
232 break;
233 }
234 }
235gotres:
236 if (!retries)
237 printf("scprobe: keyboard won't accept RESET command\n");
238 else {
239gotack:
240 DELAY(10);
241 while ((inb(KB_STAT) & KB_BUF_FULL) == 0) DELAY(10);
242 DELAY(10);
243 val = inb(KB_DATA);
244 if (val == KB_ACK)
245 goto gotack;
246 if (val != KB_RESET_DONE)
247 printf("scprobe: keyboard RESET failed %02x\n", val);
248 }
249#ifdef XT_KEYBOARD
250 kbd_wait();
251 outb(KB_DATA, 0xF0);
252 kbd_wait();
253 outb(KB_DATA, 1);
254 kbd_wait();
255#endif /* XT_KEYBOARD */
256 return (IO_KBDSIZE);
257}
258
259static struct kern_devconf kdc_sc[NSC] = {
260 0, 0, 0, /* filled in by dev_attach */
261 "sc", 0, { MDDT_ISA, 0, "tty" },
262 isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
263 &kdc_isa0, /* parent */
264 0, /* parentdata */
265 DC_BUSY, /* the console is almost always busy */
266 "Graphics console",
267 DC_CLS_DISPLAY /* class */
268};
269
270static inline void
271sc_registerdev(struct isa_device *id)
272{
273 if(id->id_unit)
274 kdc_sc[id->id_unit] = kdc_sc[0];
275 kdc_sc[id->id_unit].kdc_unit = id->id_unit;
276 kdc_sc[id->id_unit].kdc_isa = id;
277 dev_attach(&kdc_sc[id->id_unit]);
278}
279
280#if NAPM > 0
281static int
282scresume(void *dummy)
283{
284 shfts = 0;
285 ctls = 0;
286 alts = 0;
287 agrs = 0;
288 metas = 0;
289 return 0;
290}
291#endif
292
293static int
294scattach(struct isa_device *dev)
295{
296 scr_stat *scp;
297 int vc;
298 char name[32];
299
300 scinit();
301 configuration = dev->id_flags;
302
303 scp = console[0];
304
305 if (crtc_vga) {
306 font_8 = (char *)malloc(8*256, M_DEVBUF, M_NOWAIT);
307 font_14 = (char *)malloc(14*256, M_DEVBUF, M_NOWAIT);
308 font_16 = (char *)malloc(16*256, M_DEVBUF, M_NOWAIT);
309 copy_font(SAVE, FONT_16, font_16);
310 fonts_loaded = FONT_16;
311 scp->font = FONT_16;
312 save_palette();
313 }
314
315 scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
316 M_DEVBUF, M_NOWAIT);
317 /* copy screen to buffer */
318 bcopyw(Crtat, scp->scr_buf, scp->xsize * scp->ysize * sizeof(u_short));
319 scp->cursor_pos = scp->scr_buf + scp->xpos + scp->ypos * scp->xsize;
320 scp->mouse_pos = scp->scr_buf;
321
322 /* initialize history buffer & pointers */
323 scp->history_head = scp->history_pos = scp->history =
324 (u_short *)malloc(scp->history_size*sizeof(u_short),
325 M_DEVBUF, M_NOWAIT);
326 bzero(scp->history_head, scp->history_size*sizeof(u_short));
327
328 /* initialize cursor stuff */
329 draw_cursor(scp, TRUE);
330 if (crtc_vga && (configuration & CHAR_CURSOR))
331 set_destructive_cursor(scp, TRUE);
332
333 /* get screen update going */
334 scrn_timer();
335
336 update_leds(scp->status);
337 sc_registerdev(dev);
338
339 printf("sc%d: ", dev->id_unit);
340 if (crtc_vga)
341 if (crtc_addr == MONO_BASE)
342 printf("VGA mono");
343 else
344 printf("VGA color");
345 else
346 if (crtc_addr == MONO_BASE)
347 printf("MDA/hercules");
348 else
349 printf("CGA/EGA");
350 printf(" <%d virtual consoles, flags=0x%x>\n", MAXCONS, configuration);
351
352#if NAPM > 0
353 scp->r_hook.ah_fun = scresume;
354 scp->r_hook.ah_arg = NULL;
355 scp->r_hook.ah_name = "system keyboard";
356 scp->r_hook.ah_order = APM_MID_ORDER;
357 apm_hook_establish(APM_HOOK_RESUME , &scp->r_hook);
358#endif
359
360#ifdef DEVFS
361 for ( vc = 0 ; vc < MAXCONS; vc++) {
362 sprintf(name,"ttyv%x", vc);
363 sc_devfs_token[vc] = devfs_add_devsw("/" ,name, &scdevsw, vc,
364 DV_CHR, 0, 0, 0600 );
365 }
366#endif
367 {
368 dev_t dev = makedev(CDEV_MAJOR, 0);
369
370 cdevsw_add(&dev, &scdevsw, NULL);
371 }
372
373 return 0;
374}
375
376struct tty
377*scdevtotty(dev_t dev)
378{
379 int unit = minor(dev);
380
381 if (unit > MAXCONS || unit < 0)
382 return(NULL);
383 if (unit == MAXCONS)
384 return CONSOLE_TTY;
385 return VIRTUAL_TTY(unit);
386}
387
388static scr_stat
389*get_scr_stat(dev_t dev)
390{
391 int unit = minor(dev);
392
393 if (unit > MAXCONS || unit < 0)
394 return(NULL);
395 if (unit == MAXCONS)
396 return console[0];
397 return console[unit];
398}
399
400static int
401get_scr_num()
402{
403 int i = 0;
404
405 while ((i < MAXCONS) && (cur_console != console[i]))
406 i++;
407 return i < MAXCONS ? i : 0;
408}
409
410int
411scopen(dev_t dev, int flag, int mode, struct proc *p)
412{
413 struct tty *tp = scdevtotty(dev);
414
415 if (!tp)
416 return(ENXIO);
417
418 tp->t_oproc = scstart;
419 tp->t_param = scparam;
420 tp->t_dev = dev;
421 if (!(tp->t_state & TS_ISOPEN)) {
422 ttychars(tp);
423 tp->t_iflag = TTYDEF_IFLAG;
424 tp->t_oflag = TTYDEF_OFLAG;
425 tp->t_cflag = TTYDEF_CFLAG;
426 tp->t_lflag = TTYDEF_LFLAG;
427 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
428 scparam(tp, &tp->t_termios);
429 ttsetwater(tp);
430 (*linesw[tp->t_line].l_modem)(tp, 1);
431 }
432 else
433 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
434 return(EBUSY);
435 if (!console[minor(dev)])
436 console[minor(dev)] = alloc_scp();
437 return((*linesw[tp->t_line].l_open)(dev, tp));
438}
439
440int
441scclose(dev_t dev, int flag, int mode, struct proc *p)
442{
443 struct tty *tp = scdevtotty(dev);
444 struct scr_stat *scp;
445
446 if (!tp)
447 return(ENXIO);
448 if (minor(dev) < MAXCONS) {
449 scp = get_scr_stat(tp->t_dev);
450 if (scp->status & SWITCH_WAIT_ACQ)
451 wakeup((caddr_t)&scp->smode);
452#if not_yet_done
453 if (scp == &main_console) {
454 scp->pid = 0;
455 scp->proc = NULL;
456 scp->smode.mode = VT_AUTO;
457 }
458 else {
459 free(scp->scr_buf, M_DEVBUF);
460 free(scp->history, M_DEVBUF);
461 free(scp, M_DEVBUF);
462 console[minor(dev)] = NULL;
463 }
464#else
465 scp->pid = 0;
466 scp->proc = NULL;
467 scp->smode.mode = VT_AUTO;
468#endif
469 }
470 (*linesw[tp->t_line].l_close)(tp, flag);
471 ttyclose(tp);
472 return(0);
473}
474
475int
476scread(dev_t dev, struct uio *uio, int flag)
477{
478 struct tty *tp = scdevtotty(dev);
479
480 if (!tp)
481 return(ENXIO);
482 return((*linesw[tp->t_line].l_read)(tp, uio, flag));
483}
484
485int
486scwrite(dev_t dev, struct uio *uio, int flag)
487{
488 struct tty *tp = scdevtotty(dev);
489
490 if (!tp)
491 return(ENXIO);
492 return((*linesw[tp->t_line].l_write)(tp, uio, flag));
493}
494
495void
496scintr(int unit)
497{
498 static struct tty *cur_tty;
499 int c, len;
500 u_char *cp;
501
502 /* make screensaver happy */
503 scrn_time_stamp = time.tv_sec;
504 if (scrn_blanked) {
505 (*current_saver)(FALSE);
506 cur_console->start = 0;
507 cur_console->end = cur_console->xsize * cur_console->ysize;
508 }
509
510 c = scgetc(1);
511
512 cur_tty = VIRTUAL_TTY(get_scr_num());
513 if (!(cur_tty->t_state & TS_ISOPEN))
514 if (!((cur_tty = CONSOLE_TTY)->t_state & TS_ISOPEN))
515 return;
516
517 switch (c & 0xff00) {
518 case 0x0000: /* normal key */
519 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
520 break;
521 case NOKEY: /* nothing there */
522 break;
523 case FKEY: /* function key, return string */
524 if (cp = get_fstr((u_int)c, (u_int *)&len)) {
525 while (len-- > 0)
526 (*linesw[cur_tty->t_line].l_rint)(*cp++ & 0xFF, cur_tty);
527 }
528 break;
529 case MKEY: /* meta is active, prepend ESC */
530 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
531 (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
532 break;
533 case BKEY: /* backtab fixed sequence (esc [ Z) */
534 (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
535 (*linesw[cur_tty->t_line].l_rint)('[', cur_tty);
536 (*linesw[cur_tty->t_line].l_rint)('Z', cur_tty);
537 break;
538 }
539}
540
541static int
542scparam(struct tty *tp, struct termios *t)
543{
544 tp->t_ispeed = t->c_ispeed;
545 tp->t_ospeed = t->c_ospeed;
546 tp->t_cflag = t->c_cflag;
547 return 0;
548}
549
550int
551scioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
552{
553 int i, error;
554 struct tty *tp;
555 struct trapframe *fp;
556 scr_stat *scp;
557
558 tp = scdevtotty(dev);
559 if (!tp)
560 return ENXIO;
561 scp = get_scr_stat(tp->t_dev);
562
563 switch (cmd) { /* process console hardware related ioctl's */
564
565 case GIO_ATTR: /* get current attributes */
566 *(int*)data = scp->term.cur_attr;
567 return 0;
568
569 case GIO_COLOR: /* is this a color console ? */
570 if (crtc_addr == COLOR_BASE)
571 *(int*)data = 1;
572 else
573 *(int*)data = 0;
574 return 0;
575
576 case CONS_CURRENT: /* get current adapter type */
577 if (crtc_vga)
578 *(int*)data = KD_VGA;
579 else
580 if (crtc_addr == MONO_BASE)
581 *(int*)data = KD_MONO;
582 else
583 *(int*)data = KD_CGA;
584 return 0;
585
586 case CONS_GET: /* get current video mode */
587 *(int*)data = scp->mode;
588 return 0;
589
590 case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
591 scrn_blank_time = *(int*)data;
592 return 0;
593
594 case CONS_CURSORTYPE: /* set cursor type blink/noblink */
595 if ((*(int*)data) & 0x01)
596 configuration |= BLINK_CURSOR;
597 else
598 configuration &= ~BLINK_CURSOR;
599 if ((*(int*)data) & 0x02) {
600 configuration |= CHAR_CURSOR;
601 set_destructive_cursor(scp, TRUE);
602 } else
603 configuration &= ~CHAR_CURSOR;
604 return 0;
605
606 case CONS_BELLTYPE: /* set bell type sound/visual */
607 if (*data)
608 configuration |= VISUAL_BELL;
609 else
610 configuration &= ~VISUAL_BELL;
611 return 0;
612
613 case CONS_HISTORY: /* set history size */
614 if (*data) {
615 free(scp->history, M_DEVBUF);
616 scp->history_size = *(int*)data;
617 if (scp->history_size < scp->ysize)
618 scp->history = NULL;
619 else {
620 scp->history_size *= scp->xsize;
621 scp->history_head = scp->history_pos = scp->history =
622 (u_short *)malloc(scp->history_size*sizeof(u_short),
623 M_DEVBUF, M_WAITOK);
624 bzero(scp->history_head, scp->history_size*sizeof(u_short));
625 }
626 return 0;
627 }
628 else
629 return EINVAL;
630
631 case CONS_MOUSECTL: /* control mouse arrow */
632 {
633 mouse_info_t *mouse = (mouse_info_t*)data;
634 int fontsize;
635
636 switch (scp->font) {
637 default:
638 case FONT_8:
639 fontsize = 8; break;
640 case FONT_14:
641 fontsize = 14; break;
642 case FONT_16:
643 fontsize = 16; break;
644 }
645 switch (mouse->operation) {
646 case MOUSE_SHOW:
647 if (!(scp->status & MOUSE_ENABLED)) {
648 scp->mouse_oldpos = Crtat + (scp->mouse_pos - scp->scr_buf);
649 scp->status |= (UPDATE_MOUSE | MOUSE_ENABLED);
650 }
651 else
652 return EINVAL;
653 break;
654
655 case MOUSE_HIDE:
656 if (scp->status & MOUSE_ENABLED) {
657 scp->status &= ~MOUSE_ENABLED;
658 scp->status |= UPDATE_MOUSE;
659 }
660 else
661 return EINVAL;
662 break;
663
664 case MOUSE_MOVEABS:
665 scp->mouse_xpos = mouse->x;
666 scp->mouse_ypos = mouse->y;
667 goto set_mouse_pos;
668
669 case MOUSE_MOVEREL:
670 scp->mouse_xpos += mouse->x;
671 scp->mouse_ypos += mouse->y;
672set_mouse_pos:
673 if (scp->mouse_xpos < 0)
674 scp->mouse_xpos = 0;
675 if (scp->mouse_ypos < 0)
676 scp->mouse_ypos = 0;
677 if (scp->mouse_xpos >= scp->xsize*8)
678 scp->mouse_xpos = (scp->xsize*8)-1;
679 if (scp->mouse_ypos >= scp->ysize*fontsize)
680 scp->mouse_ypos = (scp->ysize*fontsize)-1;
681 scp->mouse_pos = scp->scr_buf +
682 (scp->mouse_ypos/fontsize)*scp->xsize + scp->mouse_xpos/8;
683 if (scp->status & MOUSE_ENABLED)
684 scp->status |= UPDATE_MOUSE;
685 break;
686
687 case MOUSE_GETPOS:
688 mouse->x = scp->mouse_xpos;
689 mouse->y = scp->mouse_ypos;
690 return 0;
691
692 default:
693 return EINVAL;
694 }
695 /* make screensaver happy */
696 if (scp == cur_console) {
697 scrn_time_stamp = time.tv_sec;
698 if (scrn_blanked) {
699 (*current_saver)(FALSE);
700 cur_console->start = 0;
701 cur_console->end = cur_console->xsize * cur_console->ysize;
702 }
703 }
704 return 0;
705 }
706
707 case CONS_GETINFO: /* get current (virtual) console info */
708 {
709 vid_info_t *ptr = (vid_info_t*)data;
710 if (ptr->size == sizeof(struct vid_info)) {
711 ptr->m_num = get_scr_num();
712 ptr->mv_col = scp->xpos;
713 ptr->mv_row = scp->ypos;
714 ptr->mv_csz = scp->xsize;
715 ptr->mv_rsz = scp->ysize;
716 ptr->mv_norm.fore = (scp->term.std_color & 0x0f00)>>8;
717 ptr->mv_norm.back = (scp->term.std_color & 0xf000)>>12;
718 ptr->mv_rev.fore = (scp->term.rev_color & 0x0f00)>>8;
719 ptr->mv_rev.back = (scp->term.rev_color & 0xf000)>>12;
720 ptr->mv_grfc.fore = 0; /* not supported */
721 ptr->mv_grfc.back = 0; /* not supported */
722 ptr->mv_ovscan = scp->border;
723 ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
724 return 0;
725 }
726 return EINVAL;
727 }
728
729 case CONS_GETVERS: /* get version number */
730 *(int*)data = 0x200; /* version 2.0 */
731 return 0;
732
733 /* VGA TEXT MODES */
734 case SW_VGA_C40x25:
735 case SW_VGA_C80x25: case SW_VGA_M80x25:
736 case SW_VGA_C80x30: case SW_VGA_M80x30:
737 case SW_VGA_C80x50: case SW_VGA_M80x50:
738 case SW_VGA_C80x60: case SW_VGA_M80x60:
739 case SW_B40x25: case SW_C40x25:
740 case SW_B80x25: case SW_C80x25:
741 case SW_ENH_B40x25: case SW_ENH_C40x25:
742 case SW_ENH_B80x25: case SW_ENH_C80x25:
743 case SW_ENH_B80x43: case SW_ENH_C80x43:
744
745 if (!crtc_vga || video_mode_ptr == NULL)
746 return ENXIO;
747 switch (cmd & 0xff) {
748 case M_VGA_C80x60: case M_VGA_M80x60:
749 if (!(fonts_loaded & FONT_8))
750 return EINVAL;
751 scp->xsize = 80;
752 scp->ysize = 60;
753 break;
754 case M_VGA_C80x50: case M_VGA_M80x50:
755 if (!(fonts_loaded & FONT_8))
756 return EINVAL;
757 scp->xsize = 80;
758 scp->ysize = 50;
759 break;
760 case M_ENH_B80x43: case M_ENH_C80x43:
761 if (!(fonts_loaded & FONT_8))
762 return EINVAL;
763 scp->xsize = 80;
764 scp->ysize = 43;
765 break;
766 case M_VGA_C80x30: case M_VGA_M80x30:
767 scp->xsize = 80;
768 scp->ysize = 30;
769 break;
770 default:
771 if ((cmd & 0xff) > M_VGA_CG320)
772 return EINVAL;
773 else
774 scp->xsize = *(video_mode_ptr+((cmd&0xff)*64));
775 scp->ysize = *(video_mode_ptr+((cmd&0xff)*64)+1)+1;
776 break;
777 }
778 scp->mode = cmd & 0xff;
779 scp->status &= ~UNKNOWN_MODE; /* text mode */
780 free(scp->scr_buf, M_DEVBUF);
781 scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
782 M_DEVBUF, M_WAITOK);
783 if (scp == cur_console)
784 set_mode(scp);
785 clear_screen(scp);
786 if (tp->t_winsize.ws_col != scp->xsize
787 || tp->t_winsize.ws_row != scp->ysize) {
788 tp->t_winsize.ws_col = scp->xsize;
789 tp->t_winsize.ws_row = scp->ysize;
790 pgsignal(tp->t_pgrp, SIGWINCH, 1);
791 }
792 return 0;
793
794 /* GRAPHICS MODES */
795 case SW_BG320: case SW_BG640:
796 case SW_CG320: case SW_CG320_D: case SW_CG640_E:
797 case SW_CG640x350: case SW_ENH_CG640:
798 case SW_BG640x480: case SW_CG640x480: case SW_VGA_CG320:
799
800 if (!crtc_vga || video_mode_ptr == NULL)
801 return ENXIO;
802 scp->mode = cmd & 0xFF;
803 scp->status |= UNKNOWN_MODE; /* graphics mode */
804 scp->xsize = (*(video_mode_ptr + (scp->mode*64))) * 8;
805 scp->ysize = (*(video_mode_ptr + (scp->mode*64) + 1) + 1) *
806 (*(video_mode_ptr + (scp->mode*64) + 2));
807 set_mode(scp);
808 /* clear_graphics();*/
809
810 if (tp->t_winsize.ws_xpixel != scp->xsize
811 || tp->t_winsize.ws_ypixel != scp->ysize) {
812 tp->t_winsize.ws_xpixel = scp->xsize;
813 tp->t_winsize.ws_ypixel = scp->ysize;
814 pgsignal(tp->t_pgrp, SIGWINCH, 1);
815 }
816 return 0;
817
818 case VT_SETMODE: /* set screen switcher mode */
819 bcopy(data, &scp->smode, sizeof(struct vt_mode));
820 if (scp->smode.mode == VT_PROCESS) {
821 scp->proc = p;
822 scp->pid = scp->proc->p_pid;
823 }
824 return 0;
825
826 case VT_GETMODE: /* get screen switcher mode */
827 bcopy(&scp->smode, data, sizeof(struct vt_mode));
828 return 0;
829
830 case VT_RELDISP: /* screen switcher ioctl */
831 switch(*data) {
832 case VT_FALSE: /* user refuses to release screen, abort */
833 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
834 old_scp->status &= ~SWITCH_WAIT_REL;
835 switch_in_progress = FALSE;
836 return 0;
837 }
838 return EINVAL;
839
840 case VT_TRUE: /* user has released screen, go on */
841 if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
842 scp->status &= ~SWITCH_WAIT_REL;
843 exchange_scr();
844 if (new_scp->smode.mode == VT_PROCESS) {
845 new_scp->status |= SWITCH_WAIT_ACQ;
846 psignal(new_scp->proc, new_scp->smode.acqsig);
847 }
848 else
849 switch_in_progress = FALSE;
850 return 0;
851 }
852 return EINVAL;
853
854 case VT_ACKACQ: /* acquire acknowledged, switch completed */
855 if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
856 scp->status &= ~SWITCH_WAIT_ACQ;
857 switch_in_progress = FALSE;
858 return 0;
859 }
860 return EINVAL;
861
862 default:
863 return EINVAL;
864 }
865 /* NOT REACHED */
866
867 case VT_OPENQRY: /* return free virtual console */
868 for (i = 0; i < MAXCONS; i++) {
869 tp = VIRTUAL_TTY(i);
870 if (!(tp->t_state & TS_ISOPEN)) {
871 *data = i + 1;
872 return 0;
873 }
874 }
875 return EINVAL;
876
877 case VT_ACTIVATE: /* switch to screen *data */
878 return switch_scr(scp, (*data) - 1);
879
880 case VT_WAITACTIVE: /* wait for switch to occur */
881 if (*data > MAXCONS || *data < 0)
882 return EINVAL;
883 if (minor(dev) == (*data) - 1)
884 return 0;
885 if (*data == 0) {
886 if (scp == cur_console)
887 return 0;
888 }
889 else
890 scp = console[(*data) - 1];
891 while ((error=tsleep((caddr_t)&scp->smode, PZERO|PCATCH,
892 "waitvt", 0)) == ERESTART) ;
893 return error;
894
895 case VT_GETACTIVE:
896 *data = get_scr_num()+1;
897 return 0;
898
899 case KDENABIO: /* allow io operations */
900 error = suser(p->p_ucred, &p->p_acflag);
901 if (error != 0)
902 return error;
903 fp = (struct trapframe *)p->p_md.md_regs;
904 fp->tf_eflags |= PSL_IOPL;
905 return 0;
906
907 case KDDISABIO: /* disallow io operations (default) */
908 fp = (struct trapframe *)p->p_md.md_regs;
909 fp->tf_eflags &= ~PSL_IOPL;
910 return 0;
911
912 case KDSETMODE: /* set current mode of this (virtual) console */
913 switch (*data) {
914 case KD_TEXT: /* switch to TEXT (known) mode */
915 /* restore fonts & palette ! */
916 if (crtc_vga) {
917 if (fonts_loaded & FONT_8)
918 copy_font(LOAD, FONT_8, font_8);
919 if (fonts_loaded & FONT_14)
920 copy_font(LOAD, FONT_14, font_14);
921 if (fonts_loaded & FONT_16)
922 copy_font(LOAD, FONT_16, font_16);
923 if (configuration & CHAR_CURSOR)
924 set_destructive_cursor(scp, TRUE);
925 load_palette();
926 }
927 /* FALL THROUGH */
928
929 case KD_TEXT1: /* switch to TEXT (known) mode */
930 /* no restore fonts & palette */
931 scp->status &= ~UNKNOWN_MODE;
932 if (crtc_vga && video_mode_ptr)
933 set_mode(scp);
934 clear_screen(scp);
935 return 0;
936
937 case KD_GRAPHICS: /* switch to GRAPHICS (unknown) mode */
938 scp->status |= UNKNOWN_MODE;
939 return 0;
940 default:
941 return EINVAL;
942 }
943 /* NOT REACHED */
944
945 case KDGETMODE: /* get current mode of this (virtual) console */
946 *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
947 return 0;
948
949 case KDSBORDER: /* set border color of this (virtual) console */
950 if (!crtc_vga)
951 return ENXIO;
952 scp->border = *data;
953 if (scp == cur_console)
954 set_border(scp->border);
955 return 0;
956
957 case KDSKBSTATE: /* set keyboard state (locks) */
958 if (*data >= 0 && *data <= LOCK_KEY_MASK) {
959 scp->status &= ~LOCK_KEY_MASK;
960 scp->status |= *data;
961 if (scp == cur_console)
962 update_leds(scp->status);
963 return 0;
964 }
965 return EINVAL;
966
967 case KDGKBSTATE: /* get keyboard state (locks) */
968 *data = scp->status & LOCK_KEY_MASK;
969 return 0;
970
971 case KDSETRAD: /* set keyboard repeat & delay rates */
972 if (*data & 0x80)
973 return EINVAL;
974 i = spltty();
975 kbd_cmd(KB_SETRAD);
976 kbd_cmd(*data);
977 splx(i);
978 return 0;
979
980 case KDSKBMODE: /* set keyboard mode */
981 switch (*data) {
982 case K_RAW: /* switch to RAW scancode mode */
983 scp->status |= KBD_RAW_MODE;
984 return 0;
985
986 case K_XLATE: /* switch to XLT ascii mode */
987 if (scp == cur_console && scp->status == KBD_RAW_MODE)
988 shfts = ctls = alts = agrs = metas = 0;
989 scp->status &= ~KBD_RAW_MODE;
990 return 0;
991 default:
992 return EINVAL;
993 }
994 /* NOT REACHED */
995
996 case KDGKBMODE: /* get keyboard mode */
997 *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE;
998 return 0;
999
1000 case KDMKTONE: /* sound the bell */
1001 if (*(int*)data)
1002 do_bell(scp, (*(int*)data)&0xffff,
1003 (((*(int*)data)>>16)&0xffff)*hz/1000);
1004 else
1005 do_bell(scp, scp->bell_pitch, scp->bell_duration);
1006 return 0;
1007
1008 case KIOCSOUND: /* make tone (*data) hz */
1009 if (scp == cur_console) {
1010 if (*(int*)data) {
1011 int pitch = TIMER_FREQ/(*(int*)data);
1012
1013 /* set command for counter 2, 2 byte write */
1014 if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE))
1015 return EBUSY;
1016
1017 /* set pitch */
1018 outb(TIMER_CNTR2, pitch);
1019 outb(TIMER_CNTR2, (pitch>>8));
1020
1021 /* enable counter 2 output to speaker */
1022 outb(IO_PPI, inb(IO_PPI) | 3);
1023 }
1024 else {
1025 /* disable counter 2 output to speaker */
1026 outb(IO_PPI, inb(IO_PPI) & 0xFC);
1027 release_timer2();
1028 }
1029 }
1030 return 0;
1031
1032 case KDGKBTYPE: /* get keyboard type */
1033 *data = 0; /* type not known (yet) */
1034 return 0;
1035
1036 case KDSETLED: /* set keyboard LED status */
1037 if (*data >= 0 && *data <= LED_MASK) {
1038 scp->status &= ~LED_MASK;
1039 scp->status |= *data;
1040 if (scp == cur_console)
1041 update_leds(scp->status);
1042 return 0;
1043 }
1044 return EINVAL;
1045
1046 case KDGETLED: /* get keyboard LED status */
1047 *data = scp->status & LED_MASK;
1048 return 0;
1049
1050 case GETFKEY: /* get functionkey string */
1051 if (*(u_short*)data < n_fkey_tab) {
1052 fkeyarg_t *ptr = (fkeyarg_t*)data;
1053 bcopy(&fkey_tab[ptr->keynum].str, ptr->keydef,
1054 fkey_tab[ptr->keynum].len);
1055 ptr->flen = fkey_tab[ptr->keynum].len;
1056 return 0;
1057 }
1058 else
1059 return EINVAL;
1060
1061 case SETFKEY: /* set functionkey string */
1062 if (*(u_short*)data < n_fkey_tab) {
1063 fkeyarg_t *ptr = (fkeyarg_t*)data;
1064 bcopy(ptr->keydef, &fkey_tab[ptr->keynum].str,
1065 min(ptr->flen, MAXFK));
1066 fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
1067 return 0;
1068 }
1069 else
1070 return EINVAL;
1071
1072 case GIO_SCRNMAP: /* get output translation table */
1073 bcopy(&scr_map, data, sizeof(scr_map));
1074 return 0;
1075
1076 case PIO_SCRNMAP: /* set output translation table */
1077 bcopy(data, &scr_map, sizeof(scr_map));
1078 return 0;
1079
1080 case GIO_KEYMAP: /* get keyboard translation table */
1081 bcopy(&key_map, data, sizeof(key_map));
1082 return 0;
1083
1084 case PIO_KEYMAP: /* set keyboard translation table */
1085 bcopy(data, &key_map, sizeof(key_map));
1086 return 0;
1087
1088 case PIO_FONT8x8: /* set 8x8 dot font */
1089 if (!crtc_vga)
1090 return ENXIO;
1091 bcopy(data, font_8, 8*256);
1092 fonts_loaded |= FONT_8;
1093 copy_font(LOAD, FONT_8, font_8);
1094 if (configuration & CHAR_CURSOR)
1095 set_destructive_cursor(scp, TRUE);
1096 return 0;
1097
1098 case GIO_FONT8x8: /* get 8x8 dot font */
1099 if (!crtc_vga)
1100 return ENXIO;
1101 if (fonts_loaded & FONT_8) {
1102 bcopy(font_8, data, 8*256);
1103 return 0;
1104 }
1105 else
1106 return ENXIO;
1107
1108 case PIO_FONT8x14: /* set 8x14 dot font */
1109 if (!crtc_vga)
1110 return ENXIO;
1111 bcopy(data, font_14, 14*256);
1112 fonts_loaded |= FONT_14;
1113 copy_font(LOAD, FONT_14, font_14);
1114 if (configuration & CHAR_CURSOR)
1115 set_destructive_cursor(scp, TRUE);
1116 return 0;
1117
1118 case GIO_FONT8x14: /* get 8x14 dot font */
1119 if (!crtc_vga)
1120 return ENXIO;
1121 if (fonts_loaded & FONT_14) {
1122 bcopy(font_14, data, 14*256);
1123 return 0;
1124 }
1125 else
1126 return ENXIO;
1127
1128 case PIO_FONT8x16: /* set 8x16 dot font */
1129 if (!crtc_vga)
1130 return ENXIO;
1131 bcopy(data, font_16, 16*256);
1132 fonts_loaded |= FONT_16;
1133 copy_font(LOAD, FONT_16, font_16);
1134 if (configuration & CHAR_CURSOR)
1135 set_destructive_cursor(scp, TRUE);
1136 return 0;
1137
1138 case GIO_FONT8x16: /* get 8x16 dot font */
1139 if (!crtc_vga)
1140 return ENXIO;
1141 if (fonts_loaded & FONT_16) {
1142 bcopy(font_16, data, 16*256);
1143 return 0;
1144 }
1145 else
1146 return ENXIO;
1147 default:
1148 break;
1149 }
1150
1151 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1152 if (error >= 0)
1153 return(error);
1154 error = ttioctl(tp, cmd, data, flag);
1155 if (error >= 0)
1156 return(error);
1157 return(ENOTTY);
1158}
1159
1160static void
1161scstart(struct tty *tp)
1162{
1163 struct clist *rbp;
1164 int s, len;
1165 u_char buf[PCBURST];
1166 scr_stat *scp = get_scr_stat(tp->t_dev);
1167
1168 /* XXX who repeats the call when the above flags are cleared? */
1169 if (scp->status & SLKED || blink_in_progress)
1170 return;
1171 s = spltty();
1172 if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
1173 tp->t_state |= TS_BUSY;
1174 rbp = &tp->t_outq;
1175 while (rbp->c_cc) {
1176 len = q_to_b(rbp, buf, PCBURST);
1177 splx(s);
1178 ansi_put(scp, buf, len);
1179 s = spltty();
1180 }
1181 tp->t_state &= ~TS_BUSY;
1182 ttwwakeup(tp);
1183 }
1184 splx(s);
1185}
1186
1187void
1188sccnprobe(struct consdev *cp)
1189{
1190 struct isa_device *dvp;
1191
1192 /*
1193 * Take control if we are the highest priority enabled display device.
1194 */
1195 dvp = find_display();
1196 if (dvp != NULL && dvp->id_driver != &scdriver) {
1197 cp->cn_pri = CN_DEAD;
1198 return;
1199 }
1200
1201 /* initialize required fields */
1202 cp->cn_dev = makedev(CDEV_MAJOR, MAXCONS);
1203 cp->cn_pri = CN_INTERNAL;
1204}
1205
1206void
1207sccninit(struct consdev *cp)
1208{
1209 scinit();
1210}
1211
1212void
1213sccnputc(dev_t dev, int c)
1214{
1215 u_char buf[1];
1216 scr_stat *scp = console[0];
1217 term_stat save = scp->term;
1218
1219 scp->term = kernel_console;
1220 current_default = &kernel_default;
1221 if (scp->scr_buf == Crtat)
1222 draw_cursor(scp, FALSE);
1223 buf[0] = c;
1224 ansi_put(scp, buf, 1);
1225 kernel_console = scp->term;
1226 current_default = &user_default;
1227 scp->term = save;
1228 if (scp == cur_console /* && scrn_timer not running */) {
1229 if (scp->scr_buf != Crtat && (scp->start <= scp->end)) {
1230 bcopyw(scp->scr_buf + scp->start, Crtat + scp->start,
1231 (1 + scp->end - scp->start) * sizeof(u_short));
1232 scp->start = scp->xsize * scp->ysize;
1233 scp->end = 0;
1234 scp->status &= ~CURSOR_SHOWN;
1235 }
1236 draw_cursor(scp, TRUE);
1237 }
1238}
1239
1240int
1241sccngetc(dev_t dev)
1242{
1243 int s = spltty(); /* block scintr while we poll */
1244 int c = scgetc(0);
1245 splx(s);
1246 return(c);
1247}
1248
1249int
1250sccncheckc(dev_t dev)
1251{
1252 return (scgetc(1) & 0xff);
1253}
1254
1255static void
1256scrn_timer()
1257{
1258 static int cursor_blinkrate;
1259 scr_stat *scp = cur_console;
1260
1261 /* should we just return ? */
1262 if ((scp->status&UNKNOWN_MODE) || blink_in_progress || switch_in_progress) {
1263 timeout((timeout_func_t)scrn_timer, 0, hz/10);
1264 return;
1265 }
1266
1267 if (!scrn_blanked) {
1268 /* update screen image */
1269 if (scp->start <= scp->end) {
1270 bcopyw(scp->scr_buf + scp->start, Crtat + scp->start,
1271 (1 + scp->end - scp->start) * sizeof(u_short));
1272 scp->status &= ~CURSOR_SHOWN;
1273 scp->start = scp->xsize * scp->ysize;
1274 scp->end = 0;
1275 }
1276 /* update "pseudo" mouse arrow */
1277 if ((scp->status & MOUSE_ENABLED) && (scp->status & UPDATE_MOUSE))
1278 draw_mouse_image(scp);
1279
1280 /* update cursor image */
1281 if (scp->status & CURSOR_ENABLED)
1282 draw_cursor(scp,
1283 !(configuration&BLINK_CURSOR) || !(cursor_blinkrate++&0x04));
1284 }
1285 if (scrn_blank_time && (time.tv_sec>scrn_time_stamp+scrn_blank_time))
1286 (*current_saver)(TRUE);
1287 timeout((timeout_func_t)scrn_timer, 0, hz/25);
1288}
1289
1290static void
1291clear_screen(scr_stat *scp)
1292{
1293 move_crsr(scp, 0, 0);
1294 fillw(scp->term.cur_color | scr_map[0x20], scp->scr_buf,
1295 scp->xsize * scp->ysize);
1296 mark_all(scp);
1297}
1298
1299static int
1300switch_scr(scr_stat *scp, u_int next_scr)
1301{
1302 if (switch_in_progress && (cur_console->proc != pfind(cur_console->pid)))
1303 switch_in_progress = FALSE;
1304
1305 if (next_scr >= MAXCONS || switch_in_progress ||
1306 (cur_console->smode.mode == VT_AUTO
1307 && cur_console->status & UNKNOWN_MODE)) {
1308 do_bell(scp, BELL_PITCH, BELL_DURATION);
1309 return EINVAL;
1310 }
1311
1312 /* is the wanted virtual console open ? */
1313 if (next_scr) {
1314 struct tty *tp = VIRTUAL_TTY(next_scr);
1315 if (!(tp->t_state & TS_ISOPEN)) {
1316 do_bell(scp, BELL_PITCH, BELL_DURATION);
1317 return EINVAL;
1318 }
1319 }
1320 /* delay switch if actively updating screen */
1321 if (write_in_progress || blink_in_progress) {
1322 delayed_next_scr = next_scr+1;
1323 return 0;
1324 }
1325 switch_in_progress = TRUE;
1326 old_scp = cur_console;
1327 new_scp = console[next_scr];
1328 wakeup((caddr_t)&new_scp->smode);
1329 if (new_scp == old_scp) {
1330 switch_in_progress = FALSE;
1331 delayed_next_scr = FALSE;
1332 return 0;
1333 }
1334
1335 /* has controlling process died? */
1336 if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
1337 old_scp->smode.mode = VT_AUTO;
1338 if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
1339 new_scp->smode.mode = VT_AUTO;
1340
1341 /* check the modes and switch approbiatly */
1342 if (old_scp->smode.mode == VT_PROCESS) {
1343 old_scp->status |= SWITCH_WAIT_REL;
1344 psignal(old_scp->proc, old_scp->smode.relsig);
1345 }
1346 else {
1347 exchange_scr();
1348 if (new_scp->smode.mode == VT_PROCESS) {
1349 new_scp->status |= SWITCH_WAIT_ACQ;
1350 psignal(new_scp->proc, new_scp->smode.acqsig);
1351 }
1352 else
1353 switch_in_progress = FALSE;
1354 }
1355 return 0;
1356}
1357
1358static void
1359exchange_scr(void)
1360{
1361 move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
1362 cur_console = new_scp;
1363 if (old_scp->mode != new_scp->mode || (old_scp->status & UNKNOWN_MODE)){
1364 if (crtc_vga && video_mode_ptr)
1365 set_mode(new_scp);
1366 }
1367 move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
1368 if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
1369 if (fonts_loaded & FONT_8)
1370 copy_font(LOAD, FONT_8, font_8);
1371 if (fonts_loaded & FONT_14)
1372 copy_font(LOAD, FONT_14, font_14);
1373 if (fonts_loaded & FONT_16)
1374 copy_font(LOAD, FONT_16, font_16);
1375 if (configuration & CHAR_CURSOR)
1376 set_destructive_cursor(new_scp, TRUE);
1377 load_palette();
1378 }
1379 if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
1380 shfts = ctls = alts = agrs = metas = 0;
1381 update_leds(new_scp->status);
1382 delayed_next_scr = FALSE;
1383 bcopyw(new_scp->scr_buf, Crtat,
1384 (new_scp->xsize*new_scp->ysize)*sizeof(u_short));
1385 new_scp->status &= ~CURSOR_SHOWN;
1386}
1387
1388static inline void
1389move_crsr(scr_stat *scp, int x, int y)
1390{
1391 if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize)
1392 return;
1393 scp->xpos = x;
1394 scp->ypos = y;
1395 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1396 scp->cursor_pos = scp->scr_buf + scp->ypos * scp->xsize + scp->xpos;
1397 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1398}
1399
1400static void
1401scan_esc(scr_stat *scp, u_char c)
1402{
1403 static u_char ansi_col[16] =
1404 {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
1405 int i, n;
1406 u_short *src, *dst, count;
1407
1408 if (scp->term.esc == 1) {
1409 switch (c) {
1410
1411 case '[': /* Start ESC [ sequence */
1412 scp->term.esc = 2;
1413 scp->term.last_param = -1;
1414 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
1415 scp->term.param[i] = 1;
1416 scp->term.num_param = 0;
1417 return;
1418
1419 case 'M': /* Move cursor up 1 line, scroll if at top */
1420 if (scp->ypos > 0)
1421 move_crsr(scp, scp->xpos, scp->ypos - 1);
1422 else {
1423 bcopyw(scp->scr_buf, scp->scr_buf + scp->xsize,
1424 (scp->ysize - 1) * scp->xsize * sizeof(u_short));
1425 fillw(scp->term.cur_color | scr_map[0x20],
1426 scp->scr_buf, scp->xsize);
1427 mark_all(scp);
1428 }
1429 break;
1430#if notyet
1431 case 'Q':
1432 scp->term.esc = 4;
1433 break;
1434#endif
1435 case 'c': /* Clear screen & home */
1436 clear_screen(scp);
1437 break;
1438 }
1439 }
1440 else if (scp->term.esc == 2) {
1441 if (c >= '0' && c <= '9') {
1442 if (scp->term.num_param < MAX_ESC_PAR) {
1443 if (scp->term.last_param != scp->term.num_param) {
1444 scp->term.last_param = scp->term.num_param;
1445 scp->term.param[scp->term.num_param] = 0;
1446 }
1447 else
1448 scp->term.param[scp->term.num_param] *= 10;
1449 scp->term.param[scp->term.num_param] += c - '0';
1450 return;
1451 }
1452 }
1453 scp->term.num_param = scp->term.last_param + 1;
1454 switch (c) {
1455
1456 case ';':
1457 if (scp->term.num_param < MAX_ESC_PAR)
1458 return;
1459 break;
1460
1461 case '=':
1462 scp->term.esc = 3;
1463 scp->term.last_param = -1;
1464 for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
1465 scp->term.param[i] = 1;
1466 scp->term.num_param = 0;
1467 return;
1468
1469 case 'A': /* up n rows */
1470 n = scp->term.param[0]; if (n < 1) n = 1;
1471 move_crsr(scp, scp->xpos, scp->ypos - n);
1472 break;
1473
1474 case 'B': /* down n rows */
1475 n = scp->term.param[0]; if (n < 1) n = 1;
1476 move_crsr(scp, scp->xpos, scp->ypos + n);
1477 break;
1478
1479 case 'C': /* right n columns */
1480 n = scp->term.param[0]; if (n < 1) n = 1;
1481 move_crsr(scp, scp->xpos + n, scp->ypos);
1482 break;
1483
1484 case 'D': /* left n columns */
1485 n = scp->term.param[0]; if (n < 1) n = 1;
1486 move_crsr(scp, scp->xpos - n, scp->ypos);
1487 break;
1488
1489 case 'E': /* cursor to start of line n lines down */
1490 n = scp->term.param[0]; if (n < 1) n = 1;
1491 move_crsr(scp, 0, scp->ypos + n);
1492 break;
1493
1494 case 'F': /* cursor to start of line n lines up */
1495 n = scp->term.param[0]; if (n < 1) n = 1;
1496 move_crsr(scp, 0, scp->ypos - n);
1497 break;
1498
1499 case 'f': /* Cursor move */
1500 case 'H':
1501 if (scp->term.num_param == 0)
1502 move_crsr(scp, 0, 0);
1503 else if (scp->term.num_param == 2)
1504 move_crsr(scp, scp->term.param[1] - 1, scp->term.param[0] - 1);
1505 break;
1506
1507 case 'J': /* Clear all or part of display */
1508 if (scp->term.num_param == 0)
1509 n = 0;
1510 else
1511 n = scp->term.param[0];
1512 switch (n) {
1513 case 0: /* clear form cursor to end of display */
1514 fillw(scp->term.cur_color | scr_map[0x20],
1515 scp->cursor_pos,
1516 scp->scr_buf + scp->xsize * scp->ysize - scp->cursor_pos);
1517 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1518 mark_for_update(scp, scp->xsize * scp->ysize);
1519 break;
1520 case 1: /* clear from beginning of display to cursor */
1521 fillw(scp->term.cur_color | scr_map[0x20],
1522 scp->scr_buf,
1523 scp->cursor_pos - scp->scr_buf);
1524 mark_for_update(scp, 0);
1525 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1526 break;
1527 case 2: /* clear entire display */
1528 clear_screen(scp);
1529 break;
1530 }
1531 break;
1532
1533 case 'K': /* Clear all or part of line */
1534 if (scp->term.num_param == 0)
1535 n = 0;
1536 else
1537 n = scp->term.param[0];
1538 switch (n) {
1539 case 0: /* clear form cursor to end of line */
1540 fillw(scp->term.cur_color | scr_map[0x20],
1541 scp->cursor_pos,
1542 scp->xsize - scp->xpos);
1543 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1544 mark_for_update(scp, scp->cursor_pos - scp->scr_buf +
1545 scp->xsize - scp->xpos);
1546 break;
1547 case 1: /* clear from beginning of line to cursor */
1548 fillw(scp->term.cur_color | scr_map[0x20],
1549 scp->cursor_pos - (scp->xsize - scp->xpos),
1550 (scp->xsize - scp->xpos) + 1);
1551 mark_for_update(scp, scp->ypos * scp->xsize);
1552 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1553 break;
1554 case 2: /* clear entire line */
1555 fillw(scp->term.cur_color | scr_map[0x20],
1556 scp->cursor_pos - (scp->xsize - scp->xpos),
1557 scp->xsize);
1558 mark_for_update(scp, scp->ypos * scp->xsize);
1559 mark_for_update(scp, (scp->ypos + 1) * scp->xsize);
1560 break;
1561 }
1562 break;
1563
1564 case 'L': /* Insert n lines */
1565 n = scp->term.param[0]; if (n < 1) n = 1;
1566 if (n > scp->ysize - scp->ypos)
1567 n = scp->ysize - scp->ypos;
1568 src = scp->scr_buf + scp->ypos * scp->xsize;
1569 dst = src + n * scp->xsize;
1570 count = scp->ysize - (scp->ypos + n);
1571 bcopyw(src, dst, count * scp->xsize * sizeof(u_short));
1572 fillw(scp->term.cur_color | scr_map[0x20], src,
1573 n * scp->xsize);
1574 mark_for_update(scp, scp->ypos * scp->xsize);
1575 mark_for_update(scp, scp->xsize * scp->ysize);
1576 break;
1577
1578 case 'M': /* Delete n lines */
1579 n = scp->term.param[0]; if (n < 1) n = 1;
1580 if (n > scp->ysize - scp->ypos)
1581 n = scp->ysize - scp->ypos;
1582 dst = scp->scr_buf + scp->ypos * scp->xsize;
1583 src = dst + n * scp->xsize;
1584 count = scp->ysize - (scp->ypos + n);
1585 bcopyw(src, dst, count * scp->xsize * sizeof(u_short));
1586 src = dst + count * scp->xsize;
1587 fillw(scp->term.cur_color | scr_map[0x20], src,
1588 n * scp->xsize);
1589 mark_for_update(scp, scp->ypos * scp->xsize);
1590 mark_for_update(scp, scp->xsize * scp->ysize);
1591 break;
1592
1593 case 'P': /* Delete n chars */
1594 n = scp->term.param[0]; if (n < 1) n = 1;
1595 if (n > scp->xsize - scp->xpos)
1596 n = scp->xsize - scp->xpos;
1597 dst = scp->cursor_pos;
1598 src = dst + n;
1599 count = scp->xsize - (scp->xpos + n);
1600 bcopyw(src, dst, count * sizeof(u_short));
1601 src = dst + count;
1602 fillw(scp->term.cur_color | scr_map[0x20], src, n);
1603 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1604 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
1605 break;
1606
1607 case '@': /* Insert n chars */
1608 n = scp->term.param[0]; if (n < 1) n = 1;
1609 if (n > scp->xsize - scp->xpos)
1610 n = scp->xsize - scp->xpos;
1611 src = scp->cursor_pos;
1612 dst = src + n;
1613 count = scp->xsize - (scp->xpos + n);
1614 bcopyw(src, dst, count * sizeof(u_short));
1615 fillw(scp->term.cur_color | scr_map[0x20], src, n);
1616 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1617 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n + count);
1618 break;
1619
1620 case 'S': /* scroll up n lines */
1621 n = scp->term.param[0]; if (n < 1) n = 1;
1622 if (n > scp->ysize)
1623 n = scp->ysize;
1624 bcopyw(scp->scr_buf + (scp->xsize * n),
1625 scp->scr_buf,
1626 scp->xsize * (scp->ysize - n) * sizeof(u_short));
1627 fillw(scp->term.cur_color | scr_map[0x20],
1628 scp->scr_buf + scp->xsize * (scp->ysize - n),
1629 scp->xsize * n);
1630 mark_all(scp);
1631 break;
1632
1633 case 'T': /* scroll down n lines */
1634 n = scp->term.param[0]; if (n < 1) n = 1;
1635 if (n > scp->ysize)
1636 n = scp->ysize;
1637 bcopyw(scp->scr_buf,
1638 scp->scr_buf + (scp->xsize * n),
1639 scp->xsize * (scp->ysize - n) *
1640 sizeof(u_short));
1641 fillw(scp->term.cur_color | scr_map[0x20],
1642 scp->scr_buf, scp->xsize * n);
1643 mark_all(scp);
1644 break;
1645
1646 case 'X': /* erase n characters in line */
1647 n = scp->term.param[0]; if (n < 1) n = 1;
1648 if (n > scp->xsize - scp->xpos)
1649 n = scp->xsize - scp->xpos;
1650 fillw(scp->term.cur_color | scr_map[0x20],
1651 scp->scr_buf + scp->xpos +
1652 ((scp->xsize*scp->ypos) * sizeof(u_short)), n);
1653 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1654 mark_for_update(scp, scp->cursor_pos - scp->scr_buf + n);
1655 break;
1656
1657 case 'Z': /* move n tabs backwards */
1658 n = scp->term.param[0]; if (n < 1) n = 1;
1659 if ((i = scp->xpos & 0xf8) == scp->xpos)
1660 i -= 8*n;
1661 else
1662 i -= 8*(n-1);
1663 if (i < 0)
1664 i = 0;
1665 move_crsr(scp, i, scp->ypos);
1666 break;
1667
1668 case '`': /* move cursor to column n */
1669 n = scp->term.param[0]; if (n < 1) n = 1;
1670 move_crsr(scp, n - 1, scp->ypos);
1671 break;
1672
1673 case 'a': /* move cursor n columns to the right */
1674 n = scp->term.param[0]; if (n < 1) n = 1;
1675 move_crsr(scp, scp->xpos + n, scp->ypos);
1676 break;
1677
1678 case 'd': /* move cursor to row n */
1679 n = scp->term.param[0]; if (n < 1) n = 1;
1680 move_crsr(scp, scp->xpos, n - 1);
1681 break;
1682
1683 case 'e': /* move cursor n rows down */
1684 n = scp->term.param[0]; if (n < 1) n = 1;
1685 move_crsr(scp, scp->xpos, scp->ypos + n);
1686 break;
1687
1688 case 'm': /* change attribute */
1689 if (scp->term.num_param == 0) {
1690 scp->term.attr_mask = NORMAL_ATTR;
1691 scp->term.cur_attr =
1692 scp->term.cur_color = scp->term.std_color;
1693 break;
1694 }
1695 for (i = 0; i < scp->term.num_param; i++) {
1696 switch (n = scp->term.param[i]) {
1697 case 0: /* back to normal */
1698 scp->term.attr_mask = NORMAL_ATTR;
1699 scp->term.cur_attr =
1700 scp->term.cur_color = scp->term.std_color;
1701 break;
1702 case 1: /* bold */
1703 scp->term.attr_mask |= BOLD_ATTR;
1704 scp->term.cur_attr = mask2attr(&scp->term);
1705 break;
1706 case 4: /* underline */
1707 scp->term.attr_mask |= UNDERLINE_ATTR;
1708 scp->term.cur_attr = mask2attr(&scp->term);
1709 break;
1710 case 5: /* blink */
1711 scp->term.attr_mask |= BLINK_ATTR;
1712 scp->term.cur_attr = mask2attr(&scp->term);
1713 break;
1714 case 7: /* reverse video */
1715 scp->term.attr_mask |= REVERSE_ATTR;
1716 scp->term.cur_attr = mask2attr(&scp->term);
1717 break;
1718 case 30: case 31: /* set fg color */
1719 case 32: case 33: case 34:
1720 case 35: case 36: case 37:
1721 scp->term.attr_mask |= FOREGROUND_CHANGED;
1722 scp->term.cur_color =
1723 (scp->term.cur_color&0xF000) | (ansi_col[(n-30)&7]<<8);
1724 scp->term.cur_attr = mask2attr(&scp->term);
1725 break;
1726 case 40: case 41: /* set bg color */
1727 case 42: case 43: case 44:
1728 case 45: case 46: case 47:
1729 scp->term.attr_mask |= BACKGROUND_CHANGED;
1730 scp->term.cur_color =
1731 (scp->term.cur_color&0x0F00) | (ansi_col[(n-40)&7]<<12);
1732 scp->term.cur_attr = mask2attr(&scp->term);
1733 break;
1734 }
1735 }
1736 break;
1737
1738 case 'x':
1739 if (scp->term.num_param == 0)
1740 n = 0;
1741 else
1742 n = scp->term.param[0];
1743 switch (n) {
1744 case 0: /* reset attributes */
1745 scp->term.attr_mask = NORMAL_ATTR;
1746 scp->term.cur_attr =
1747 scp->term.cur_color = scp->term.std_color =
1748 current_default->std_color;
1749 scp->term.rev_color = current_default->rev_color;
1750 break;
1751 case 1: /* set ansi background */
1752 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
1753 scp->term.cur_color = scp->term.std_color =
1754 (scp->term.std_color & 0x0F00) |
1755 (ansi_col[(scp->term.param[1])&0x0F]<<12);
1756 scp->term.cur_attr = mask2attr(&scp->term);
1757 break;
1758 case 2: /* set ansi foreground */
1759 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
1760 scp->term.cur_color = scp->term.std_color =
1761 (scp->term.std_color & 0xF000) |
1762 (ansi_col[(scp->term.param[1])&0x0F]<<8);
1763 scp->term.cur_attr = mask2attr(&scp->term);
1764 break;
1765 case 3: /* set ansi attribute directly */
1766 scp->term.attr_mask &= ~(FOREGROUND_CHANGED|BACKGROUND_CHANGED);
1767 scp->term.cur_color = scp->term.std_color =
1768 (scp->term.param[1]&0xFF)<<8;
1769 scp->term.cur_attr = mask2attr(&scp->term);
1770 break;
1771 case 5: /* set ansi reverse video background */
1772 scp->term.rev_color =
1773 (scp->term.rev_color & 0x0F00) |
1774 (ansi_col[(scp->term.param[1])&0x0F]<<12);
1775 scp->term.cur_attr = mask2attr(&scp->term);
1776 break;
1777 case 6: /* set ansi reverse video foreground */
1778 scp->term.rev_color =
1779 (scp->term.rev_color & 0xF000) |
1780 (ansi_col[(scp->term.param[1])&0x0F]<<8);
1781 scp->term.cur_attr = mask2attr(&scp->term);
1782 break;
1783 case 7: /* set ansi reverse video directly */
1784 scp->term.rev_color =
1785 (scp->term.param[1]&0xFF)<<8;
1786 scp->term.cur_attr = mask2attr(&scp->term);
1787 break;
1788 }
1789 break;
1790
1791 case 'z': /* switch to (virtual) console n */
1792 if (scp->term.num_param == 1)
1793 switch_scr(scp, scp->term.param[0]);
1794 break;
1795 }
1796 }
1797 else if (scp->term.esc == 3) {
1798 if (c >= '0' && c <= '9') {
1799 if (scp->term.num_param < MAX_ESC_PAR) {
1800 if (scp->term.last_param != scp->term.num_param) {
1801 scp->term.last_param = scp->term.num_param;
1802 scp->term.param[scp->term.num_param] = 0;
1803 }
1804 else
1805 scp->term.param[scp->term.num_param] *= 10;
1806 scp->term.param[scp->term.num_param] += c - '0';
1807 return;
1808 }
1809 }
1810 scp->term.num_param = scp->term.last_param + 1;
1811 switch (c) {
1812
1813 case ';':
1814 if (scp->term.num_param < MAX_ESC_PAR)
1815 return;
1816 break;
1817
1818 case 'A': /* set display border color */
1819 if (scp->term.num_param == 1)
1820 scp->border=scp->term.param[0] & 0xff;
1821 if (scp == cur_console)
1822 set_border(scp->border);
1823 break;
1824
1825 case 'B': /* set bell pitch and duration */
1826 if (scp->term.num_param == 2) {
1827 scp->bell_pitch = scp->term.param[0];
1828 scp->bell_duration = scp->term.param[1]*10;
1829 }
1830 break;
1831
1832 case 'C': /* set cursor type & shape */
1833 if (scp->term.num_param == 1) {
1834 if (scp->term.param[0] & 0x01)
1835 configuration |= BLINK_CURSOR;
1836 else
1837 configuration &= ~BLINK_CURSOR;
1838 if (scp->term.param[0] & 0x02) {
1839 configuration |= CHAR_CURSOR;
1840 set_destructive_cursor(scp, TRUE);
1841 } else
1842 configuration &= ~CHAR_CURSOR;
1843 }
1844 else if (scp->term.num_param == 2) {
1845 scp->cursor_start = scp->term.param[0] & 0x1F;
1846 scp->cursor_end = scp->term.param[1] & 0x1F;
1847 if (configuration & CHAR_CURSOR)
1848 set_destructive_cursor(scp, TRUE);
1849 }
1850 break;
1851
1852 case 'F': /* set ansi foreground */
1853 if (scp->term.num_param == 1) {
1854 scp->term.attr_mask &= ~FOREGROUND_CHANGED;
1855 scp->term.cur_color = scp->term.std_color =
1856 (scp->term.std_color & 0xF000)
1857 | ((scp->term.param[0] & 0x0F) << 8);
1858 scp->term.cur_attr = mask2attr(&scp->term);
1859 }
1860 break;
1861
1862 case 'G': /* set ansi background */
1863 if (scp->term.num_param == 1) {
1864 scp->term.attr_mask &= ~BACKGROUND_CHANGED;
1865 scp->term.cur_color = scp->term.std_color =
1866 (scp->term.std_color & 0x0F00)
1867 | ((scp->term.param[0] & 0x0F) << 12);
1868 scp->term.cur_attr = mask2attr(&scp->term);
1869 }
1870 break;
1871
1872 case 'H': /* set ansi reverse video foreground */
1873 if (scp->term.num_param == 1) {
1874 scp->term.rev_color =
1875 (scp->term.rev_color & 0xF000)
1876 | ((scp->term.param[0] & 0x0F) << 8);
1877 scp->term.cur_attr = mask2attr(&scp->term);
1878 }
1879 break;
1880
1881 case 'I': /* set ansi reverse video background */
1882 if (scp->term.num_param == 1) {
1883 scp->term.rev_color =
1884 (scp->term.rev_color & 0x0F00)
1885 | ((scp->term.param[0] & 0x0F) << 12);
1886 scp->term.cur_attr = mask2attr(&scp->term);
1887 }
1888 break;
1889 }
1890 }
1891 scp->term.esc = 0;
1892}
1893
1894static inline void
1895draw_cursor(scr_stat *scp, int show)
1896{
1897 if (show && !(scp->status & CURSOR_SHOWN)) {
1898 u_short cursor_image = *(Crtat + (scp->cursor_pos - scp->scr_buf));
1899
1900 scp->cursor_saveunder = cursor_image;
1901 if (configuration & CHAR_CURSOR) {
1902 set_destructive_cursor(scp, FALSE);
1903 cursor_image = (cursor_image & 0xff00) | DEAD_CHAR;
1904 }
1905 else {
1906 if ((cursor_image & 0x7000) == 0x7000) {
1907 cursor_image &= 0x8fff;
1908 if(!(cursor_image & 0x0700))
1909 cursor_image |= 0x0700;
1910 } else {
1911 cursor_image |= 0x7000;
1912 if ((cursor_image & 0x0700) == 0x0700)
1913 cursor_image &= 0xf0ff;
1914 }
1915 }
1916 *(Crtat + (scp->cursor_pos - scp->scr_buf)) = cursor_image;
1917 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1918 scp->status |= CURSOR_SHOWN;
1919 }
1920 if (!show && (scp->status & CURSOR_SHOWN)) {
1921 *(Crtat + (scp->cursor_pos - scp->scr_buf)) = scp->cursor_saveunder;
1922 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1923 scp->status &= ~CURSOR_SHOWN;
1924 }
1925}
1926
1927static void
1928ansi_put(scr_stat *scp, u_char *buf, int len)
1929{
1930 u_char *ptr = buf;
1931
1932 if (scp->status & UNKNOWN_MODE)
1933 return;
1934
1935 /* make screensaver happy */
1936 if (scp == cur_console) {
1937 scrn_time_stamp = time.tv_sec;
1938 if (scrn_blanked) {
1939 (*current_saver)(FALSE);
1940 cur_console->start = 0;
1941 cur_console->end = cur_console->xsize * cur_console->ysize;
1942 }
1943 }
1944 write_in_progress++;
1945outloop:
1946 if (scp->term.esc) {
1947 scan_esc(scp, *ptr++);
1948 len--;
1949 }
1950 else if (PRINTABLE(*ptr)) { /* Print only printables */
1951 int cnt = len <= (scp->xsize-scp->xpos) ? len : (scp->xsize-scp->xpos);
1952 u_short cur_attr = scp->term.cur_attr;
1953 u_short *cursor_pos = scp->cursor_pos;
1954 do {
1955 /*
1956 * gcc-2.6.3 generates poor (un)sign extension code. Casting the
1957 * pointers in the following to volatile should have no effect,
1958 * but in fact speeds up this inner loop from 26 to 18 cycles
1959 * (+ cache misses) on i486's.
1960 */
1961#define UCVP(ucp) ((u_char volatile *)(ucp))
1962 *cursor_pos++ = UCVP(scr_map)[*UCVP(ptr)] | cur_attr;
1963 ptr++;
1964 cnt--;
1965 } while (cnt && PRINTABLE(*ptr));
1966 len -= (cursor_pos - scp->cursor_pos);
1967 scp->xpos += (cursor_pos - scp->cursor_pos);
1968 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1969 mark_for_update(scp, cursor_pos - scp->scr_buf);
1970 scp->cursor_pos = cursor_pos;
1971 if (scp->xpos >= scp->xsize) {
1972 scp->xpos = 0;
1973 scp->ypos++;
1974 }
1975 }
1976 else {
1977 switch(*ptr) {
1978 case 0x07:
1979 do_bell(scp, scp->bell_pitch, scp->bell_duration);
1980 break;
1981
1982 case 0x08: /* non-destructive backspace */
1983 if (scp->cursor_pos > scp->scr_buf) {
1984 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1985 scp->cursor_pos--;
1986 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1987 if (scp->xpos > 0)
1988 scp->xpos--;
1989 else {
1990 scp->xpos += scp->xsize - 1;
1991 scp->ypos--;
1992 }
1993 }
1994 break;
1995
1996 case 0x09: /* non-destructive tab */
1997 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
1998 scp->cursor_pos += (8 - scp->xpos % 8u);
1999 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2000 if ((scp->xpos += (8 - scp->xpos % 8u)) >= scp->xsize) {
2001 scp->xpos = 0;
2002 scp->ypos++;
2003 }
2004 break;
2005
2006 case 0x0a: /* newline, same pos */
2007 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2008 scp->cursor_pos += scp->xsize;
2009 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2010 scp->ypos++;
2011 break;
2012
2013 case 0x0c: /* form feed, clears screen */
2014 clear_screen(scp);
2015 break;
2016
2017 case 0x0d: /* return, return to pos 0 */
2018 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2019 scp->cursor_pos -= scp->xpos;
2020 mark_for_update(scp, scp->cursor_pos - scp->scr_buf);
2021 scp->xpos = 0;
2022 break;
2023
2024 case 0x1b: /* start escape sequence */
2025 scp->term.esc = 1;
2026 scp->term.num_param = 0;
2027 break;
2028 }
2029 ptr++; len--;
2030 }
2031 /* do we have to scroll ?? */
2032 if (scp->cursor_pos >= scp->scr_buf + scp->ysize * scp->xsize) {
2033 if (scp->history) {
2034 bcopyw(scp->scr_buf, scp->history_head,
2035 scp->xsize * sizeof(u_short));
2036 scp->history_head += scp->xsize;
2037 if (scp->history_head + scp->xsize >
2038 scp->history + scp->history_size)
2039 scp->history_head = scp->history;
2040 }
2041 bcopyw(scp->scr_buf + scp->xsize, scp->scr_buf,
2042 scp->xsize * (scp->ysize - 1) * sizeof(u_short));
2043 fillw(scp->term.cur_color | scr_map[0x20],
2044 scp->scr_buf + scp->xsize * (scp->ysize - 1),
2045 scp->xsize);
2046 scp->cursor_pos -= scp->xsize;
2047 scp->ypos--;
2048 mark_all(scp);
2049 }
2050 if (len)
2051 goto outloop;
2052 write_in_progress--;
2053 if (delayed_next_scr)
2054 switch_scr(scp, delayed_next_scr - 1);
2055}
2056
2057static void
2058scinit(void)
2059{
2060 u_short volatile *cp;
2061 u_short was;
2062 unsigned hw_cursor;
2063 int i;
2064
2065 if (init_done)
2066 return;
2067 init_done = TRUE;
2068 /*
2069 * Finish defaulting crtc variables for a mono screen. Crtat is a
2070 * bogus common variable so that it can be shared with pcvt, so it
2071 * can't be statically initialized. XXX.
2072 */
2073 Crtat = (u_short *)MONO_BUF;
2074 /*
2075 * If CGA memory seems to work, switch to color.
2076 */
2077 cp = (u_short *)CGA_BUF;
2078 was = *cp;
2079 *cp = (u_short) 0xA55A;
2080 if (*cp == 0xA55A) {
2081 Crtat = (u_short *)cp;
2082 crtc_addr = COLOR_BASE;
2083 }
2084 *cp = was;
2085
2086 /*
2087 * Ensure a zero start address. This is mainly to recover after
2088 * switching from pcvt using userconfig(). The registers are w/o
2089 * for old hardware so it's too hard to relocate the active screen
2090 * memory.
2091 */
2092 outb(crtc_addr, 12);
2093 outb(crtc_addr + 1, 0);
2094 outb(crtc_addr, 13);
2095 outb(crtc_addr + 1, 0);
2096
2097 /* extract cursor location */
2098 outb(crtc_addr, 14);
2099 hw_cursor = inb(crtc_addr + 1) << 8;
2100 outb(crtc_addr, 15);
2101 hw_cursor |= inb(crtc_addr + 1);
2102
2103 /* move hardware cursor out of the way */
2104 outb(crtc_addr, 14);
2105 outb(crtc_addr + 1, 0xff);
2106 outb(crtc_addr, 15);
2107 outb(crtc_addr + 1, 0xff);
2108
2109 /* is this a VGA or higher ? */
2110 outb(crtc_addr, 7);
2111 if (inb(crtc_addr) == 7) {
2112 u_long pa;
2113 u_long segoff;
2114
2115 crtc_vga = TRUE;
2116 /*
2117 * Get the BIOS video mode pointer.
2118 */
2119 segoff = *(u_long *)pa_to_va(0x4a8);
2120 pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
2121 if (ISMAPPED(pa, sizeof(u_long))) {
2122 segoff = *(u_long *)pa_to_va(pa);
2123 pa = (((segoff & 0xffff0000) >> 12) + (segoff & 0xffff));
2124 if (ISMAPPED(pa, 64))
2125 video_mode_ptr = (char *)pa_to_va(pa);
2126 }
2127 }
2128 current_default = &user_default;
2129 console[0] = &main_console;
2130 init_scp(console[0]);
2131 console[0]->scr_buf = console[0]->mouse_pos = Crtat;
2132 console[0]->cursor_pos = Crtat + hw_cursor;
2133 console[0]->xpos = hw_cursor % COL;
2134 console[0]->ypos = hw_cursor / COL;
2135 cur_console = console[0];
2136 for (i=1; i<MAXCONS; i++)
2137 console[i] = NULL;
2138 kernel_console.esc = 0;
2139 kernel_console.attr_mask = NORMAL_ATTR;
2140 kernel_console.cur_attr =
2141 kernel_console.cur_color = kernel_console.std_color =
2142 kernel_default.std_color;
2143 kernel_console.rev_color = kernel_default.rev_color;
2144 /* initialize mapscrn array to a one to one map */
2145 for (i=0; i<sizeof(scr_map); i++)
2146 scr_map[i] = i;
2147}
2148
2149static scr_stat
2150*alloc_scp()
2151{
2152 scr_stat *scp;
2153
2154 scp = (scr_stat *)malloc(sizeof(scr_stat), M_DEVBUF, M_WAITOK);
2155 init_scp(scp);
2156 scp->scr_buf = scp->cursor_pos = scp->scr_buf = scp->mouse_pos =
2157 (u_short *)malloc(scp->xsize*scp->ysize*sizeof(u_short),
2158 M_DEVBUF, M_WAITOK);
2159 scp->history_head = scp->history_pos = scp->history =
2160 (u_short *)malloc(scp->history_size*sizeof(u_short),
2161 M_DEVBUF, M_WAITOK);
2162 bzero(scp->history_head, scp->history_size*sizeof(u_short));
2163 if (crtc_vga && video_mode_ptr)
2164 set_mode(scp);
2165 clear_screen(scp);
2166 return scp;
2167}
2168
2169static void
2170init_scp(scr_stat *scp)
2171{
2172 scp->mode = M_VGA_C80x25;
2173 scp->font = FONT_16;
2174 scp->xsize = COL;
2175 scp->ysize = ROW;
2176 scp->start = COL * ROW;
2177 scp->end = 0;
2178 scp->term.esc = 0;
2179 scp->term.attr_mask = NORMAL_ATTR;
2180 scp->term.cur_attr =
2181 scp->term.cur_color = scp->term.std_color =
2182 current_default->std_color;
2183 scp->term.rev_color = current_default->rev_color;
2184 scp->border = BG_BLACK;
2185 scp->cursor_start = *(char *)pa_to_va(0x461);
2186 scp->cursor_end = *(char *)pa_to_va(0x460);
2187 scp->mouse_xpos = scp->mouse_ypos = 0;
2188 scp->bell_pitch = BELL_PITCH;
2189 scp->bell_duration = BELL_DURATION;
2190 scp->status = (*(char *)pa_to_va(0x417) & 0x20) ? NLKED : 0;
2191 scp->status |= CURSOR_ENABLED;
2192 scp->pid = 0;
2193 scp->proc = NULL;
2194 scp->smode.mode = VT_AUTO;
2195 scp->history_head = scp->history_pos = scp->history = NULL;
2196 scp->history_size = HISTORY_SIZE;
2197}
2198
2199static u_char
2200*get_fstr(u_int c, u_int *len)
2201{
2202 u_int i;
2203
2204 if (!(c & FKEY))
2205 return(NULL);
2206 i = (c & 0xFF) - F_FN;
2207 if (i > n_fkey_tab)
2208 return(NULL);
2209 *len = fkey_tab[i].len;
2210 return(fkey_tab[i].str);
2211}
2212
2213static void
2214update_leds(int which)
2215{
2216 int s;
2217 static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
2218
2219 /* replace CAPS led with ALTGR led for ALTGR keyboards */
2220 if (key_map.n_keys > ALTGR_OFFSET) {
2221 if (which & ALKED)
2222 which |= CLKED;
2223 else
2224 which &= ~CLKED;
2225 }
2226 s = spltty();
2227 kbd_cmd(KB_SETLEDS);
2228 kbd_cmd(xlate_leds[which & LED_MASK]);
2229 splx(s);
2230}
2231
2232static void
2233history_to_screen(scr_stat *scp)
2234{
2235 int i;
2236
2237 for (i=0; i<scp->ysize; i++)
2238 bcopyw(scp->history + (((scp->history_pos - scp->history) +
2239 scp->history_size-((i+1)*scp->xsize))%scp->history_size),
2240 scp->scr_buf + (scp->xsize * (scp->ysize-1 - i)),
2241 scp->xsize * sizeof(u_short));
2242 mark_all(scp);
2243}
2244
2245static int
2246history_up_line(scr_stat *scp)
2247{
2248 if (WRAPHIST(scp, scp->history_pos, -(scp->xsize*scp->ysize)) !=
2249 scp->history_head) {
2250 scp->history_pos = WRAPHIST(scp, scp->history_pos, -scp->xsize);
2251 history_to_screen(scp);
2252 return 0;
2253 }
2254 else
2255 return -1;
2256}
2257
2258static int
2259history_down_line(scr_stat *scp)
2260{
2261 if (scp->history_pos != scp->history_head) {
2262 scp->history_pos = WRAPHIST(scp, scp->history_pos, scp->xsize);
2263 history_to_screen(scp);
2264 return 0;
2265 }
2266 else
2267 return -1;
2268}
2269
2270/*
2271 * scgetc(noblock) - get character from keyboard.
2272 * If noblock = 0 wait until a key is pressed.
2273 * Else return NOKEY.
2274 */
2275u_int
2276scgetc(int noblock)
2277{
2278 u_char scancode, keycode;
2279 u_int state, action;
2280 struct key_t *key;
2281 static u_char esc_flag = 0, compose = 0;
2282 static u_int chr = 0;
2283
2284next_code:
2285 kbd_wait();
2286 /* First see if there is something in the keyboard port */
2287 if (inb(KB_STAT) & KB_BUF_FULL)
2288 scancode = inb(KB_DATA);
2289 else if (noblock)
2290 return(NOKEY);
2291 else
2292 goto next_code;
2293
2294 add_keyboard_randomness(scancode);
2295
2296 if (cur_console->status & KBD_RAW_MODE)
2297 return scancode;
2298#if ASYNCH
2299 if (scancode == KB_ACK || scancode == KB_RESEND) {
2300 kbd_reply = scancode;
2301 if (noblock)
2302 return(NOKEY);
2303 goto next_code;
2304 }
2305#endif
2306 keycode = scancode & 0x7F;
2307 switch (esc_flag) {
2308 case 0x00: /* normal scancode */
2309 switch(scancode) {
2310 case 0xB8: /* left alt (compose key) */
2311 if (compose) {
2312 compose = 0;
2313 if (chr > 255) {
2314 do_bell(cur_console,
2315 BELL_PITCH, BELL_DURATION);
2316 chr = 0;
2317 }
2318 }
2319 break;
2320 case 0x38:
2321 if (!compose) {
2322 compose = 1;
2323 chr = 0;
2324 }
2325 break;
2326 case 0xE0:
2327 case 0xE1:
2328 esc_flag = scancode;
2329 goto next_code;
2330 }
2331 break;
2332 case 0xE0: /* 0xE0 prefix */
2333 esc_flag = 0;
2334 switch (keycode) {
2335 case 0x1C: /* right enter key */
2336 keycode = 0x59;
2337 break;
2338 case 0x1D: /* right ctrl key */
2339 keycode = 0x5A;
2340 break;
2341 case 0x35: /* keypad divide key */
2342 keycode = 0x5B;
2343 break;
2344 case 0x37: /* print scrn key */
2345 keycode = 0x5C;
2346 break;
2347 case 0x38: /* right alt key (alt gr) */
2348 keycode = 0x5D;
2349 break;
2350 case 0x47: /* grey home key */
2351 keycode = 0x5E;
2352 break;
2353 case 0x48: /* grey up arrow key */
2354 keycode = 0x5F;
2355 break;
2356 case 0x49: /* grey page up key */
2357 keycode = 0x60;
2358 break;
2359 case 0x4B: /* grey left arrow key */
2360 keycode = 0x61;
2361 break;
2362 case 0x4D: /* grey right arrow key */
2363 keycode = 0x62;
2364 break;
2365 case 0x4F: /* grey end key */
2366 keycode = 0x63;
2367 break;
2368 case 0x50: /* grey down arrow key */
2369 keycode = 0x64;
2370 break;
2371 case 0x51: /* grey page down key */
2372 keycode = 0x65;
2373 break;
2374 case 0x52: /* grey insert key */
2375 keycode = 0x66;
2376 break;
2377 case 0x53: /* grey delete key */
2378 keycode = 0x67;
2379 break;
2380
2381 /* the following 3 are only used on the MS "Natural" keyboard */
2382 case 0x5b: /* left Window key */
2383 keycode = 0x69;
2384 break;
2385 case 0x5c: /* right Window key */
2386 keycode = 0x6a;
2387 break;
2388 case 0x5d: /* menu key */
2389 keycode = 0x6b;
2390 break;
2391 default: /* ignore everything else */
2392 goto next_code;
2393 }
2394 break;
2395 case 0xE1: /* 0xE1 prefix */
2396 esc_flag = 0;
2397 if (keycode == 0x1D)
2398 esc_flag = 0x1D;
2399 goto next_code;
2400 /* NOT REACHED */
2401 case 0x1D: /* pause / break */
2402 esc_flag = 0;
2403 if (keycode != 0x45)
2404 goto next_code;
2405 keycode = 0x68;
2406 break;
2407 }
2408
2409 /* if scroll-lock pressed allow history browsing */
2410 if (cur_console->history && cur_console->status & SLKED) {
2411 int i;
2412
2413 cur_console->status &= ~CURSOR_ENABLED;
2414 if (!(cur_console->status & BUFFER_SAVED)) {
2415 cur_console->status |= BUFFER_SAVED;
2416 cur_console->history_save = cur_console->history_head;
2417
2418 /* copy screen into top of history buffer */
2419 for (i=0; i<cur_console->ysize; i++) {
2420 bcopyw(cur_console->scr_buf + (cur_console->xsize * i),
2421 cur_console->history_head,
2422 cur_console->xsize * sizeof(u_short));
2423 cur_console->history_head += cur_console->xsize;
2424 if (cur_console->history_head + cur_console->xsize >
2425 cur_console->history + cur_console->history_size)
2426 cur_console->history_head=cur_console->history;
2427 }
2428 cur_console->history_pos = cur_console->history_head;
2429 history_to_screen(cur_console);
2430 }
2431 switch (scancode) {
2432 case 0x47: /* home key */
2433 cur_console->history_pos = cur_console->history_head;
2434 history_to_screen(cur_console);
2435 goto next_code;
2436
2437 case 0x4F: /* end key */
2438 cur_console->history_pos =
2439 WRAPHIST(cur_console, cur_console->history_head,
2440 cur_console->xsize*cur_console->ysize);
2441 history_to_screen(cur_console);
2442 goto next_code;
2443
2444 case 0x48: /* up arrow key */
2445 if (history_up_line(cur_console))
2446 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2447 goto next_code;
2448
2449 case 0x50: /* down arrow key */
2450 if (history_down_line(cur_console))
2451 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2452 goto next_code;
2453
2454 case 0x49: /* page up key */
2455 for (i=0; i<cur_console->ysize; i++)
2456 if (history_up_line(cur_console)) {
2457 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2458 break;
2459 }
2460 goto next_code;
2461
2462 case 0x51: /* page down key */
2463 for (i=0; i<cur_console->ysize; i++)
2464 if (history_down_line(cur_console)) {
2465 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2466 break;
2467 }
2468 goto next_code;
2469 }
2470 }
2471
2472 if (compose) {
2473 switch (scancode) {
2474 /* key pressed process it */
2475 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
2476 chr = (scancode - 0x40) + chr*10;
2477 goto next_code;
2478 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
2479 chr = (scancode - 0x47) + chr*10;
2480 goto next_code;
2481 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
2482 chr = (scancode - 0x4E) + chr*10;
2483 goto next_code;
2484 case 0x52: /* keypad 0 */
2485 chr *= 10;
2486 goto next_code;
2487
2488 /* key release, no interest here */
2489 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
2490 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
2491 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
2492 case 0xD2: /* keypad 0 */
2493 goto next_code;
2494
2495 case 0x38: /* left alt key */
2496 break;
2497 default:
2498 if (chr) {
2499 compose = chr = 0;
2500 do_bell(cur_console, BELL_PITCH, BELL_DURATION);
2501 goto next_code;
2502 }
2503 break;
2504 }
2505 }
2506
2507 state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
2508 if ((!agrs && (cur_console->status & ALKED))
2509 || (agrs && !(cur_console->status & ALKED)))
2510 keycode += ALTGR_OFFSET;
2511 key = &key_map.key[keycode];
2512 if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
2513 || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
2514 state ^= 1;
2515
2516 /* Check for make/break */
2517 action = key->map[state];
2518 if (scancode & 0x80) { /* key released */
2519 if (key->spcl & 0x80) {
2520 switch (action) {
2521 case LSH:
2522 shfts &= ~1;
2523 break;
2524 case RSH:
2525 shfts &= ~2;
2526 break;
2527 case LCTR:
2528 ctls &= ~1;
2529 break;
2530 case RCTR:
2531 ctls &= ~2;
2532 break;
2533 case LALT:
2534 alts &= ~1;
2535 break;
2536 case RALT:
2537 alts &= ~2;
2538 break;
2539 case NLK:
2540 nlkcnt = 0;
2541 break;
2542 case CLK:
2543 clkcnt = 0;
2544 break;
2545 case SLK:
2546 slkcnt = 0;
2547 break;
2548 case ASH:
2549 agrs = 0;
2550 break;
2551 case ALK:
2552 alkcnt = 0;
2553 break;
2554 case META:
2555 metas = 0;
2556 break;
2557 }
2558 }
2559 if (chr && !compose) {
2560 action = chr;
2561 chr = 0;
2562 return(action);
2563 }
2564 } else {
2565 /* key pressed */
2566 if (key->spcl & (0x80>>state)) {
2567 switch (action) {
2568 /* LOCKING KEYS */
2569 case NLK:
2570 if (!nlkcnt) {
2571 nlkcnt++;
2572 if (cur_console->status & NLKED)
2573 cur_console->status &= ~NLKED;
2574 else
2575 cur_console->status |= NLKED;
2576 update_leds(cur_console->status);
2577 }
2578 break;
2579 case CLK:
2580 if (!clkcnt) {
2581 clkcnt++;
2582 if (cur_console->status & CLKED)
2583 cur_console->status &= ~CLKED;
2584 else
2585 cur_console->status |= CLKED;
2586 update_leds(cur_console->status);
2587 }
2588 break;
2589 case SLK:
2590 if (!slkcnt) {
2591 slkcnt++;
2592 if (cur_console->status & SLKED) {
2593 cur_console->status &= ~SLKED;
2594 if (cur_console->status & BUFFER_SAVED){
2595 int i;
2596 u_short *ptr = cur_console->history_save;
2597
2598 for (i=0; i<cur_console->ysize; i++) {
2599 bcopyw(ptr,
2600 cur_console->scr_buf +
2601 (cur_console->xsize*i),
2602 cur_console->xsize * sizeof(u_short));
2603 ptr += cur_console->xsize;
2604 if (ptr + cur_console->xsize >
2605 cur_console->history +
2606 cur_console->history_size)
2607 ptr = cur_console->history;
2608 }
2609 cur_console->status &= ~BUFFER_SAVED;
2610 cur_console->history_head=cur_console->history_save;
2611 cur_console->status |= CURSOR_ENABLED;
2612 mark_all(cur_console);
2613 }
2614 scstart(VIRTUAL_TTY(get_scr_num()));
2615 }
2616 else
2617 cur_console->status |= SLKED;
2618 update_leds(cur_console->status);
2619 }
2620 break;
2621 case ALK:
2622 if (!alkcnt) {
2623 alkcnt++;
2624 if (cur_console->status & ALKED)
2625 cur_console->status &= ~ALKED;
2626 else
2627 cur_console->status |= ALKED;
2628 update_leds(cur_console->status);
2629 }
2630 break;
2631
2632 /* NON-LOCKING KEYS */
2633 case NOP:
2634 break;
2635 case RBT:
2636 shutdown_nice();
2637 break;
2638 case SUSP:
2639#if NAPM > 0
2640 apm_suspend();
2641#endif
2642 break;
2643
2644 case DBG:
2645#ifdef DDB /* try to switch to console 0 */
2646 if (cur_console->smode.mode == VT_AUTO &&
2647 console[0]->smode.mode == VT_AUTO)
2648 switch_scr(cur_console, 0);
2649 Debugger("manual escape to debugger");
2650 return(NOKEY);
2651#else
2652 printf("No debugger in kernel\n");
2653#endif
2654 break;
2655 case LSH:
2656 shfts |= 1;
2657 break;
2658 case RSH:
2659 shfts |= 2;
2660 break;
2661 case LCTR:
2662 ctls |= 1;
2663 break;
2664 case RCTR:
2665 ctls |= 2;
2666 break;
2667 case LALT:
2668 alts |= 1;
2669 break;
2670 case RALT:
2671 alts |= 2;
2672 break;
2673 case ASH:
2674 agrs = 1;
2675 break;
2676 case META:
2677 metas = 1;
2678 break;
2679 case NEXT:
2680 switch_scr(cur_console, (get_scr_num() + 1) % MAXCONS);
2681 break;
2682 case BTAB:
2683 return(BKEY);
2684 default:
2685 if (action >= F_SCR && action <= L_SCR) {
2686 switch_scr(cur_console, action - F_SCR);
2687 break;
2688 }
2689 if (action >= F_FN && action <= L_FN)
2690 action |= FKEY;
2691 return(action);
2692 }
2693 }
2694 else {
2695 if (metas)
2696 action |= MKEY;
2697 return(action);
2698 }
2699 }
2700 goto next_code;
2701}
2702
2703int
2704scmmap(dev_t dev, int offset, int nprot)
2705{
2706 if (offset > 0x20000 - PAGE_SIZE)
2707 return -1;
2708 return i386_btop((VIDEOMEM + offset));
2709}
2710
2711static void
2712kbd_wait(void)
2713{
2714 int i = 1000;
2715
2716 while (i--) {
2717 if ((inb(KB_STAT) & KB_READY) == 0)
2718 break;
2719 DELAY (10);
2720 }
2721}
2722
2723static void
2724kbd_cmd(u_char command)
2725{
2726 int retry = 5;
2727 do {
2728 int i = 100000;
2729
2730 kbd_wait();
2731#if ASYNCH
2732 kbd_reply = 0;
2733 outb(KB_DATA, command);
2734 while (i--) {
2735 if (kbd_reply == KB_ACK)
2736 return;
2737 if (kbd_reply == KB_RESEND)
2738 break;
2739 }
2740#else
2741 outb(KB_DATA, command);
2742 while (i--) {
2743 if (inb(KB_STAT) & KB_BUF_FULL) {
2744 int val;
2745 DELAY(10);
2746 val = inb(KB_DATA);
2747 if (val == KB_ACK)
2748 return;
2749 if (val == KB_RESEND)
2750 break;
2751 }
2752 }
2753#endif
2754 } while (retry--);
2755}
2756
2757static void
2758set_mode(scr_stat *scp)
2759{
2760 char *modetable;
2761 char special_modetable[64];
2762 int font_size;
2763
2764 if (scp != cur_console)
2765 return;
2766
2767 /* setup video hardware for the given mode */
2768 switch (scp->mode) {
2769 case M_VGA_M80x60:
2770 bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64);
2771 goto special_80x60;
2772
2773 case M_VGA_C80x60:
2774 bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64);
2775special_80x60:
2776 special_modetable[2] = 0x08;
2777 special_modetable[19] = 0x47;
2778 goto special_480l;
2779
2780 case M_VGA_M80x30:
2781 bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64);
2782 goto special_80x30;
2783
2784 case M_VGA_C80x30:
2785 bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64);
2786special_80x30:
2787 special_modetable[19] = 0x4f;
2788special_480l:
2789 special_modetable[9] |= 0xc0;
2790 special_modetable[16] = 0x08;
2791 special_modetable[17] = 0x3e;
2792 special_modetable[26] = 0xea;
2793 special_modetable[28] = 0xdf;
2794 special_modetable[31] = 0xe7;
2795 special_modetable[32] = 0x04;
2796 modetable = special_modetable;
2797 goto setup_mode;
2798
2799 case M_ENH_B80x43:
2800 bcopyw(video_mode_ptr+(64*M_ENH_B80x25),&special_modetable, 64);
2801 goto special_80x43;
2802
2803 case M_ENH_C80x43:
2804 bcopyw(video_mode_ptr+(64*M_ENH_C80x25),&special_modetable, 64);
2805special_80x43:
2806 special_modetable[28] = 87;
2807 goto special_80x50;
2808
2809 case M_VGA_M80x50:
2810 bcopyw(video_mode_ptr+(64*M_VGA_M80x25),&special_modetable, 64);
2811 goto special_80x50;
2812
2813 case M_VGA_C80x50:
2814 bcopyw(video_mode_ptr+(64*M_VGA_C80x25),&special_modetable, 64);
2815special_80x50:
2816 special_modetable[2] = 8;
2817 special_modetable[19] = 7;
2818 modetable = special_modetable;
2819 goto setup_mode;
2820
2821 case M_VGA_C40x25: case M_VGA_C80x25:
2822 case M_VGA_M80x25:
2823 case M_B40x25: case M_C40x25:
2824 case M_B80x25: case M_C80x25:
2825 case M_ENH_B40x25: case M_ENH_C40x25:
2826 case M_ENH_B80x25: case M_ENH_C80x25:
2827
2828 modetable = video_mode_ptr + (scp->mode * 64);
2829setup_mode:
2830 set_vgaregs(modetable);
2831 font_size = *(modetable + 2);
2832
2833 /* set font type (size) */
2834 switch (font_size) {
2835 case 0x10:
2836 outb(TSIDX, 0x03); outb(TSREG, 0x00); /* font 0 */
2837 scp->font = FONT_16;
2838 break;
2839 case 0x0E:
2840 outb(TSIDX, 0x03); outb(TSREG, 0x05); /* font 1 */
2841 scp->font = FONT_14;
2842 break;
2843 default:
2844 case 0x08:
2845 outb(TSIDX, 0x03); outb(TSREG, 0x0A); /* font 2 */
2846 scp->font = FONT_8;
2847 break;
2848 }
2849 if (configuration & CHAR_CURSOR)
2850 set_destructive_cursor(scp, TRUE);
2851 break;
2852
2853 case M_BG320: case M_CG320: case M_BG640:
2854 case M_CG320_D: case M_CG640_E:
2855 case M_CG640x350: case M_ENH_CG640:
2856 case M_BG640x480: case M_CG640x480: case M_VGA_CG320:
2857
2858 set_vgaregs(video_mode_ptr + (scp->mode * 64));
2859 break;
2860
2861 default:
2862 /* call user defined function XXX */
2863 break;
2864 }
2865
2866 /* set border color for this (virtual) console */
2867 set_border(scp->border);
2868 return;
2869}
2870
2871void
2872set_border(int color)
2873{
2874 inb(crtc_addr+6); /* reset flip-flop */
2875 outb(ATC, 0x11); outb(ATC, color);
2876 inb(crtc_addr+6); /* reset flip-flop */
2877 outb(ATC, 0x20); /* enable Palette */
2878}
2879
2880static void
2881set_vgaregs(char *modetable)
2882{
2883 int i, s = splhigh();
2884
2885 outb(TSIDX, 0x00); outb(TSREG, 0x01); /* stop sequencer */
2886 outb(TSIDX, 0x07); outb(TSREG, 0x00); /* unlock registers */
2887 for (i=0; i<4; i++) { /* program sequencer */
2888 outb(TSIDX, i+1);
2889 outb(TSREG, modetable[i+5]);
2890 }
2891 outb(MISC, modetable[9]); /* set dot-clock */
2892 outb(TSIDX, 0x00); outb(TSREG, 0x03); /* start sequencer */
2893 outb(crtc_addr, 0x11);
2894 outb(crtc_addr+1, inb(crtc_addr+1) & 0x7F);
2895 for (i=0; i<25; i++) { /* program crtc */
2896 outb(crtc_addr, i);
2897 if (i == 14 || i == 15) /* no hardware cursor */
2898 outb(crtc_addr+1, 0xff);
2899 else
2900 outb(crtc_addr+1, modetable[i+10]);
2901 }
2902 inb(crtc_addr+6); /* reset flip-flop */
2903 for (i=0; i<20; i++) { /* program attribute ctrl */
2904 outb(ATC, i);
2905 outb(ATC, modetable[i+35]);
2906 }
2907 for (i=0; i<9; i++) { /* program graph data ctrl */
2908 outb(GDCIDX, i);
2909 outb(GDCREG, modetable[i+55]);
2910 }
2911 inb(crtc_addr+6); /* reset flip-flop */
2912 outb(ATC ,0x20); /* enable palette */
2913 splx(s);
2914}
2915
2916static void
2917set_font_mode()
2918{
2919 /* setup vga for loading fonts (graphics plane mode) */
2920 inb(crtc_addr+6);
2921 outb(ATC, 0x30); outb(ATC, 0x01);
2922#if SLOW_VGA
2923 outb(TSIDX, 0x02); outb(TSREG, 0x04);
2924 outb(TSIDX, 0x04); outb(TSREG, 0x06);
2925 outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
2926 outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
2927 outb(GDCIDX, 0x06); outb(GDCREG, 0x05);
2928#else
2929 outw(TSIDX, 0x0402);
2930 outw(TSIDX, 0x0604);
2931 outw(GDCIDX, 0x0204);
2932 outw(GDCIDX, 0x0005);
2933 outw(GDCIDX, 0x0506); /* addr = a0000, 64kb */
2934#endif
2935}
2936
2937static void
2938set_normal_mode()
2939{
2940 int s = splhigh();
2941
2942 /* setup vga for normal operation mode again */
2943 inb(crtc_addr+6);
2944 outb(ATC, 0x30); outb(ATC, 0x0C);
2945#if SLOW_VGA
2946 outb(TSIDX, 0x02); outb(TSREG, 0x03);
2947 outb(TSIDX, 0x04); outb(TSREG, 0x02);
2948 outb(GDCIDX, 0x04); outb(GDCREG, 0x00);
2949 outb(GDCIDX, 0x05); outb(GDCREG, 0x10);
2950 if (crtc_addr == MONO_BASE) {
2951 outb(GDCIDX, 0x06); outb(GDCREG, 0x0A); /* addr = b0000, 32kb */
2952 }
2953 else {
2954 outb(GDCIDX, 0x06); outb(GDCREG, 0x0E); /* addr = b8000, 32kb */
2955 }
2956#else
2957 outw(TSIDX, 0x0302);
2958 outw(TSIDX, 0x0204);
2959 outw(GDCIDX, 0x0004);
2960 outw(GDCIDX, 0x1005);
2961 if (crtc_addr == MONO_BASE)
2962 outw(GDCIDX, 0x0A06); /* addr = b0000, 32kb */
2963 else
2964 outw(GDCIDX, 0x0E06); /* addr = b8000, 32kb */
2965#endif
2966 splx(s);
2967}
2968
2969static void
2970copy_font(int operation, int font_type, char* font_image)
2971{
2972 int ch, line, segment, fontsize;
2973 u_char val;
2974
2975 switch (font_type) {
2976 default:
2977 case FONT_8:
2978 segment = 0x8000;
2979 fontsize = 8;
2980 break;
2981 case FONT_14:
2982 segment = 0x4000;
2983 fontsize = 14;
2984 break;
2985 case FONT_16:
2986 segment = 0x0000;
2987 fontsize = 16;
2988 break;
2989 }
2990 outb(TSIDX, 0x01); val = inb(TSREG); /* disable screen */
2991 outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
2992 set_font_mode();
2993 for (ch=0; ch < 256; ch++)
2994 for (line=0; line < fontsize; line++)
2995 if (operation)
2996 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line) =
2997 font_image[(ch*fontsize)+line];
2998 else
2999 font_image[(ch*fontsize)+line] =
3000 *(char *)pa_to_va(VIDEOMEM+(segment)+(ch*32)+line);
3001 set_normal_mode();
3002 outb(TSIDX, 0x01); outb(TSREG, val & 0xDF); /* enable screen */
3003}
3004
3005static void
3006set_destructive_cursor(scr_stat *scp, int force)
3007{
3008 u_char cursor[32];
3009 caddr_t address;
3010 int i, font_size;
3011 char *font_buffer;
3012 static u_char old_saveunder = DEAD_CHAR;
3013
3014 if (!force && (scp->cursor_saveunder & 0xFF) == old_saveunder)
3015 return;
3016 old_saveunder = force ? DEAD_CHAR : scp->cursor_saveunder & 0xFF;
3017 switch (scp->font) {
3018 default:
3019 case FONT_8:
3020 font_size = 8;
3021 font_buffer = font_8;
3022 address = (caddr_t)VIDEOMEM + 0x8000;
3023 break;
3024 case FONT_14:
3025 font_size = 14;
3026 font_buffer = font_14;
3027 address = (caddr_t)VIDEOMEM + 0x4000;
3028 break;
3029 case FONT_16:
3030 font_size = 16;
3031 font_buffer = font_16;
3032 address = (caddr_t)VIDEOMEM;
3033 break;
3034 }
3035 bcopyw(font_buffer + ((scp->cursor_saveunder & 0xff) * font_size),
3036 cursor, font_size);
3037 for (i=0; i<32; i++)
3038 if ((i >= scp->cursor_start && i <= scp->cursor_end) ||
3039 (scp->cursor_start >= font_size && i == font_size - 1))
3040 cursor[i] |= 0xff;
3041 while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
3042 set_font_mode();
3043 bcopy(cursor, (char *)pa_to_va(address) + DEAD_CHAR * 32, 32);
3044 set_normal_mode();
3045}
3046
3047static void
3048draw_mouse_image(scr_stat *scp)
3049{
3050 caddr_t address;
3051 int i, font_size;
3052 char *font_buffer;
3053 u_short buffer[32];
3054 u_short xoffset, yoffset;
3055 u_short *crt_pos = Crtat + (scp->mouse_pos - scp->scr_buf);
3056
3057 xoffset = scp->mouse_xpos % 8;
3058 switch (scp->font) {
3059 default:
3060 case FONT_8:
3061 font_size = 8;
3062 font_buffer = font_8;
3063 yoffset = scp->mouse_ypos % 8;
3064 address = (caddr_t)VIDEOMEM + 0x8000;
3065 break;
3066 case FONT_14:
3067 font_size = 14;
3068 font_buffer = font_14;
3069 yoffset = scp->mouse_ypos % 14;
3070 address = (caddr_t)VIDEOMEM + 0x4000;
3071 break;
3072 case FONT_16:
3073 font_size = 16;
3074 font_buffer = font_16;
3075 yoffset = scp->mouse_ypos % 16;
3076 address = (caddr_t)VIDEOMEM;
3077 break;
3078 }
3079
3080 bcopyw(font_buffer + ((*(scp->mouse_pos) & 0xff) * font_size),
3081 &scp->mouse_cursor[0], font_size);
3082 bcopyw(font_buffer + ((*(scp->mouse_pos+1) & 0xff) * font_size),
3083 &scp->mouse_cursor[32], font_size);
3084 bcopyw(font_buffer + ((*(scp->mouse_pos+scp->xsize) & 0xff) * font_size),
3085 &scp->mouse_cursor[64], font_size);
3086 bcopyw(font_buffer + ((*(scp->mouse_pos+scp->xsize+1) & 0xff) * font_size),
3087 &scp->mouse_cursor[96], font_size);
3088
3089 for (i=0; i<font_size; i++) {
3090 buffer[i] = scp->mouse_cursor[i]<<8 | scp->mouse_cursor[i+32];
3091 buffer[i+font_size]=scp->mouse_cursor[i+64]<<8|scp->mouse_cursor[i+96];
3092 }
3093 for (i=0; i<16; i++) {
3094 buffer[i+yoffset] =
3095 ( buffer[i+yoffset] & ~(mouse_and_mask[i] >> xoffset))
3096 | (mouse_or_mask[i] >> xoffset);
3097 }
3098 for (i=0; i<font_size; i++) {
3099 scp->mouse_cursor[i] = (buffer[i] & 0xff00) >> 8;
3100 scp->mouse_cursor[i+32] = buffer[i] & 0xff;
3101 scp->mouse_cursor[i+64] = (buffer[i+font_size] & 0xff00) >> 8;
3102 scp->mouse_cursor[i+96] = buffer[i+font_size] & 0xff;
3103 }
3104 if (scp->status & UPDATE_MOUSE) {
3105 u_short *ptr = scp->scr_buf + (scp->mouse_oldpos - Crtat);
3106
3107 if (crt_pos != scp->mouse_oldpos) {
3108 *(scp->mouse_oldpos) = scp->mouse_saveunder[0];
3109 *(scp->mouse_oldpos+1) = scp->mouse_saveunder[1];
3110 *(scp->mouse_oldpos+scp->xsize) = scp->mouse_saveunder[2];
3111 *(scp->mouse_oldpos+scp->xsize+1) = scp->mouse_saveunder[3];
3112 }
3113 scp->mouse_saveunder[0] = *(scp->mouse_pos);
3114 scp->mouse_saveunder[1] = *(scp->mouse_pos+1);
3115 scp->mouse_saveunder[2] = *(scp->mouse_pos+scp->xsize);
3116 scp->mouse_saveunder[3] = *(scp->mouse_pos+scp->xsize+1);
3117 if ((scp->cursor_pos == (ptr)) ||
3118 (scp->cursor_pos == (ptr+1)) ||
3119 (scp->cursor_pos == (ptr+scp->xsize)) ||
3120 (scp->cursor_pos == (ptr+scp->xsize+1)) ||
3121 (scp->cursor_pos == (scp->mouse_pos)) ||
3122 (scp->cursor_pos == (scp->mouse_pos+1)) ||
3123 (scp->cursor_pos == (scp->mouse_pos+scp->xsize)) ||
3124 (scp->cursor_pos == (scp->mouse_pos+scp->xsize+1)))
3125 scp->status &= ~CURSOR_SHOWN;
3126 }
3127 scp->mouse_oldpos = crt_pos;
3128 while (!(inb(crtc_addr+6) & 0x08)) /* wait for vertical retrace */ ;
3129 *(crt_pos) = (*(scp->mouse_pos)&0xff00)|0xd0;
3130 *(crt_pos+1) = (*(scp->mouse_pos+1)&0xff00)|0xd1;
3131 *(crt_pos+scp->xsize) = (*(scp->mouse_pos+scp->xsize)&0xff00)|0xd2;
3132 *(crt_pos+scp->xsize+1) = (*(scp->mouse_pos+scp->xsize+1)&0xff00)|0xd3;
3133 set_font_mode();
3134 bcopy(scp->mouse_cursor, (char *)pa_to_va(address) + 0xd0 * 32, 128);
3135 set_normal_mode();
3136}
3137
3138static void
3139save_palette(void)
3140{
3141 int i;
3142
3143 outb(PALRADR, 0x00);
3144 for (i=0x00; i<0x300; i++)
3145 palette[i] = inb(PALDATA);
3146 inb(crtc_addr+6); /* reset flip/flop */
3147}
3148
3149void
3150load_palette(void)
3151{
3152 int i;
3153
3154 outb(PIXMASK, 0xFF); /* no pixelmask */
3155 outb(PALWADR, 0x00);
3156 for (i=0x00; i<0x300; i++)
3157 outb(PALDATA, palette[i]);
3158 inb(crtc_addr+6); /* reset flip/flop */
3159 outb(ATC, 0x20); /* enable palette */
3160}
3161
3162static void
3163do_bell(scr_stat *scp, int pitch, int duration)
3164{
3165 if (scp == cur_console) {
3166 if (configuration & VISUAL_BELL) {
3167 if (blink_in_progress)
3168 return;
3169 blink_in_progress = 4;
3170 blink_screen(scp);
3171 timeout((timeout_func_t)blink_screen, scp, hz/10);
3172 }
3173 else
3174 sysbeep(pitch, duration);
3175 }
3176}
3177
3178static void
3179blink_screen(scr_stat *scp)
3180{
3181 if (blink_in_progress > 1) {
3182 if (blink_in_progress & 1)
3183 fillw(kernel_default.std_color | scr_map[0x20],
3184 Crtat, scp->xsize * scp->ysize);
3185 else
3186 fillw(kernel_default.rev_color | scr_map[0x20],
3187 Crtat, scp->xsize * scp->ysize);
3188 blink_in_progress--;
3189 timeout((timeout_func_t)blink_screen, scp, hz/10);
3190 }
3191 else {
3192 blink_in_progress = FALSE;
3193 mark_all(scp);
3194 if (delayed_next_scr)
3195 switch_scr(scp, delayed_next_scr - 1);
3196 }
3197}
3198
3199#endif /* NSC */