vidconsole.c revision 225736
1/*-
2 * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
3 * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
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 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * 	Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/9/sys/boot/pc98/libpc98/vidconsole.c 146011 2005-05-08 14:17:28Z nyan $");
32
33#include <stand.h>
34#include <bootstrap.h>
35#include <btxv86.h>
36#include <machine/psl.h>
37#include <machine/cpufunc.h>
38#include "libi386.h"
39
40#if KEYBOARD_PROBE
41#include <machine/cpufunc.h>
42
43static int	probe_keyboard(void);
44#endif
45static void	vidc_probe(struct console *cp);
46static int	vidc_init(int arg);
47static void	vidc_putchar(int c);
48static int	vidc_getchar(void);
49static int	vidc_ischar(void);
50
51static int	vidc_started;
52
53#ifdef TERM_EMU
54#define MAXARGS		8
55#define DEFAULT_FGCOLOR	7
56#define DEFAULT_BGCOLOR	0
57
58void		end_term(void);
59void		bail_out(int c);
60void		vidc_term_emu(int c);
61void		get_pos(void);
62void		curs_move(int x, int y);
63void		write_char(int c, int fg, int bg);
64void		scroll_up(int rows, int fg, int bg);
65void		CD(void);
66void		CM(void);
67void		HO(void);
68
69static int	args[MAXARGS], argc;
70static int	fg_c, bg_c, curx, cury;
71static int	esc;
72#endif
73
74static unsigned short *crtat, *Crtat;
75static int row = 25, col = 80;
76#ifdef TERM_EMU
77static u_int8_t	ibmpc_to_pc98[256] = {
78	0x01, 0x21, 0x81, 0xa1, 0x41, 0x61, 0xc1, 0xe1,
79	0x09, 0x29, 0x89, 0xa9, 0x49, 0x69, 0xc9, 0xe9,
80	0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
81	0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
82	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
83	0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
84	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
85	0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
86	0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
87	0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
88	0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
89	0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
90	0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
91	0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
92	0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
93	0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5,
94
95	0x03, 0x23, 0x83, 0xa3, 0x43, 0x63, 0xc3, 0xe3,
96	0x0b, 0x2b, 0x8b, 0xab, 0x4b, 0x6b, 0xcb, 0xeb,
97	0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
98	0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
99	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
100	0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
101	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
102	0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
103	0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
104	0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
105	0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
106	0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
107	0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
108	0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
109	0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
110	0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef,
111};
112#define	at2pc98(fg_at, bg_at)	ibmpc_to_pc98[((bg_at) << 4) | (fg_at)]
113#endif /* TERM_EMU */
114
115struct console vidconsole = {
116    "vidconsole",
117    "internal video/keyboard",
118    0,
119    vidc_probe,
120    vidc_init,
121    vidc_putchar,
122    vidc_getchar,
123    vidc_ischar
124};
125
126static void
127vidc_probe(struct console *cp)
128{
129
130    /* look for a keyboard */
131#if KEYBOARD_PROBE
132    if (probe_keyboard())
133#endif
134    {
135
136	cp->c_flags |= C_PRESENTIN;
137    }
138
139    /* XXX for now, always assume we can do BIOS screen output */
140    cp->c_flags |= C_PRESENTOUT;
141}
142
143static int
144vidc_init(int arg)
145{
146    int		i, hw_cursor;
147
148    if (vidc_started && arg == 0)
149	return (0);
150    vidc_started = 1;
151    Crtat = (unsigned short *)PTOV(0xA0000);
152    while ((inb(0x60) & 0x04) == 0)
153	;
154    outb(0x62, 0xe0);
155    while ((inb(0x60) & 0x01) == 0)
156	;
157    hw_cursor = inb(0x62);
158    hw_cursor |= (inb(0x62) << 8);
159    inb(0x62);
160    inb(0x62);
161    inb(0x62);
162    crtat = Crtat + hw_cursor;
163#ifdef TERM_EMU
164    /* Init terminal emulator */
165    end_term();
166    get_pos();
167    curs_move(curx, cury);
168    fg_c = DEFAULT_FGCOLOR;
169    bg_c = DEFAULT_BGCOLOR;
170#endif
171    for (i = 0; i < 10 && vidc_ischar(); i++)
172	(void)vidc_getchar();
173    return (0);	/* XXX reinit? */
174}
175
176static void
177beep(void)
178{
179
180	outb(0x37, 6);
181	delay(40000);
182	outb(0x37, 7);
183}
184
185#if 0
186static void
187vidc_biosputchar(int c)
188{
189    unsigned short *cp;
190    int i, pos;
191
192#ifdef TERM_EMU
193    *crtat = (c == 0x5c ? 0xfc : c);
194    *(crtat + 0x1000) = at2pc98(fg, bg);
195#else
196    switch(c) {
197    case '\b':
198        crtat--;
199	break;
200    case '\r':
201        crtat -= (crtat - Crtat) % col;
202	break;
203    case '\n':
204        crtat += col;
205	break;
206    default:
207        *crtat = (c == 0x5c ? 0xfc : c);
208	*(crtat++ + 0x1000) = 0xe1;
209	break;
210    }
211
212    if (crtat >= Crtat + col * row) {
213        cp = Crtat;
214	for (i = 1; i < row; i++) {
215	    bcopy((void *)(cp + col), (void *)cp, col * 2);
216	    cp += col;
217	}
218	for (i = 0; i < col; i++) {
219	    *cp++ = ' ';
220	}
221	crtat -= col;
222    }
223    pos = crtat - Crtat;
224    while ((inb(0x60) & 0x04) == 0) {}
225    outb(0x62, 0x49);
226    outb(0x60, pos & 0xff);
227    outb(0x60, pos >> 8);
228#endif
229}
230#endif
231
232static void
233vidc_rawputchar(int c)
234{
235    int		i;
236
237    if (c == '\t')
238	/* lame tab expansion */
239	for (i = 0; i < 8; i++)
240	    vidc_rawputchar(' ');
241    else {
242	/* Emulate AH=0eh (teletype output) */
243	switch(c) {
244	case '\a':
245	    beep();
246	    return;
247	case '\r':
248	    curx = 0;
249	    curs_move(curx, cury);
250	    return;
251	case '\n':
252	    cury++;
253	    if (cury > 24) {
254		scroll_up(1, fg_c, bg_c);
255		cury--;
256	    } else {
257		curs_move(curx, cury);
258	    }
259	    return;
260	case '\b':
261	    if (curx > 0) {
262		curx--;
263		curs_move(curx, cury);
264		/* write_char(' ', fg_c, bg_c); XXX destructive(!) */
265		return;
266	    }
267	    return;
268	default:
269	    write_char(c, fg_c, bg_c);
270	    curx++;
271	    if (curx > 79) {
272		curx = 0;
273		cury++;
274	    }
275	    if (cury > 24) {
276		curx = 0;
277		scroll_up(1, fg_c, bg_c);
278		cury--;
279	    }
280	}
281	curs_move(curx, cury);
282    }
283}
284
285#ifdef TERM_EMU
286
287/* Get cursor position on the screen. Result is in edx. Sets
288 * curx and cury appropriately.
289 */
290void
291get_pos(void)
292{
293    int pos = crtat - Crtat;
294
295    curx = pos % col;
296    cury = pos / col;
297}
298
299/* Move cursor to x rows and y cols (0-based). */
300void
301curs_move(int x, int y)
302{
303    int pos;
304
305    pos = x + y * col;
306    crtat = Crtat + pos;
307    pos = crtat - Crtat;
308    while((inb(0x60) & 0x04) == 0) {}
309    outb(0x62, 0x49);
310    outb(0x60, pos & 0xff);
311    outb(0x60, pos >> 8);
312    curx = x;
313    cury = y;
314#define isvisible(c)	(((c) >= 32) && ((c) < 255))
315    if (!isvisible(*crtat & 0x00ff)) {
316	write_char(' ', fg_c, bg_c);
317    }
318}
319
320/* Scroll up the whole window by a number of rows. If rows==0,
321 * clear the window. fg and bg are attributes for the new lines
322 * inserted in the window.
323 */
324void
325scroll_up(int rows, int fgcol, int bgcol)
326{
327    unsigned short *cp;
328    int i;
329
330    if (rows == 0)
331	rows = 25;
332    cp = Crtat;
333    for (i = rows; i < row; i++) {
334	bcopy((void *)(cp + col), (void *)cp, col * 2);
335	cp += col;
336    }
337    for (i = 0; i < col; i++) {
338	*(cp + 0x1000) = at2pc98(fgcol, bgcol);
339	*cp++ = ' ';
340    }
341}
342
343/* Write character and attribute at cursor position. */
344void
345write_char(int c, int fgcol, int bgcol)
346{
347
348    *crtat = (c == 0x5c ? 0xfc : (c & 0xff));
349    *(crtat + 0x1000) = at2pc98(fgcol, bgcol);
350}
351
352/**************************************************************/
353/*
354 * Screen manipulation functions. They use accumulated data in
355 * args[] and argc variables.
356 *
357 */
358
359/* Clear display from current position to end of screen */
360void
361CD(void)
362{
363    int pos;
364
365    get_pos();
366    for (pos = 0; crtat + pos <= Crtat + col * row; pos++) {
367	*(crtat + pos) = ' ';
368	*(crtat + pos + 0x1000) = at2pc98(fg_c, bg_c);
369    }
370    end_term();
371}
372
373/* Absolute cursor move to args[0] rows and args[1] columns
374 * (the coordinates are 1-based).
375 */
376void
377CM(void)
378{
379
380    if (args[0] > 0)
381	args[0]--;
382    if (args[1] > 0)
383	args[1]--;
384    curs_move(args[1], args[0]);
385    end_term();
386}
387
388/* Home cursor (left top corner) */
389void
390HO(void)
391{
392
393    argc = 1;
394    args[0] = args[1] = 1;
395    CM();
396}
397
398/* Clear internal state of the terminal emulation code */
399void
400end_term(void)
401{
402
403    esc = 0;
404    argc = -1;
405}
406
407/* Gracefully exit ESC-sequence processing in case of misunderstanding */
408void
409bail_out(int c)
410{
411    char buf[16], *ch;
412    int i;
413
414    if (esc) {
415	vidc_rawputchar('\033');
416	if (esc != '\033')
417	    vidc_rawputchar(esc);
418	for (i = 0; i <= argc; ++i) {
419	    sprintf(buf, "%d", args[i]);
420	    ch = buf;
421	    while (*ch)
422		vidc_rawputchar(*ch++);
423	}
424    }
425    vidc_rawputchar(c);
426    end_term();
427}
428
429static void
430get_arg(int c)
431{
432
433    if (argc < 0)
434	argc = 0;
435    args[argc] *= 10;
436    args[argc] += c - '0';
437}
438
439/* Emulate basic capabilities of cons25 terminal */
440void
441vidc_term_emu(int c)
442{
443    static int ansi_col[] = {
444	0, 4, 2, 6, 1, 5, 3, 7,
445    };
446    int t;
447    int i;
448
449    switch (esc) {
450    case 0:
451	switch (c) {
452	case '\033':
453	    esc = c;
454	    break;
455	default:
456	    vidc_rawputchar(c);
457	    break;
458	}
459	break;
460
461    case '\033':
462	switch (c) {
463	case '[':
464	    esc = c;
465	    args[0] = 0;
466	    argc = -1;
467	    break;
468	default:
469	    bail_out(c);
470	    break;
471	}
472	break;
473
474    case '[':
475	switch (c) {
476	case ';':
477	    if (argc < 0)	/* XXX */
478		argc = 0;
479	    else if (argc + 1 >= MAXARGS)
480		bail_out(c);
481	    else
482		args[++argc] = 0;
483	    break;
484	case 'H':
485	    if (argc < 0)
486		HO();
487	    else if (argc == 1)
488		CM();
489	    else
490		bail_out(c);
491	    break;
492	case 'J':
493	    if (argc < 0)
494		CD();
495	    else
496		bail_out(c);
497	    break;
498	case 'm':
499	    if (argc < 0) {
500		fg_c = DEFAULT_FGCOLOR;
501		bg_c = DEFAULT_BGCOLOR;
502	    }
503	    for (i = 0; i <= argc; ++i) {
504		switch (args[i]) {
505		case 0:		/* back to normal */
506		    fg_c = DEFAULT_FGCOLOR;
507		    bg_c = DEFAULT_BGCOLOR;
508		    break;
509		case 1:		/* bold */
510		    fg_c |= 0x8;
511		    break;
512		case 4:		/* underline */
513		case 5:		/* blink */
514		    bg_c |= 0x8;
515		    break;
516		case 7:		/* reverse */
517		    t = fg_c;
518		    fg_c = bg_c;
519		    bg_c = t;
520		    break;
521		case 30: case 31: case 32: case 33:
522		case 34: case 35: case 36: case 37:
523		    fg_c = ansi_col[args[i] - 30];
524		    break;
525		case 39:	/* normal */
526		    fg_c = DEFAULT_FGCOLOR;
527		    break;
528		case 40: case 41: case 42: case 43:
529		case 44: case 45: case 46: case 47:
530		    bg_c = ansi_col[args[i] - 40];
531		    break;
532		case 49:	/* normal */
533		    bg_c = DEFAULT_BGCOLOR;
534		    break;
535		}
536	    }
537	    end_term();
538	    break;
539	default:
540	    if (isdigit(c))
541		get_arg(c);
542	    else
543		bail_out(c);
544	    break;
545	}
546	break;
547
548    default:
549	bail_out(c);
550	break;
551    }
552}
553#endif
554
555static void
556vidc_putchar(int c)
557{
558#ifdef TERM_EMU
559    vidc_term_emu(c);
560#else
561    vidc_rawputchar(c);
562#endif
563}
564
565static int
566vidc_getchar(void)
567{
568
569    if (vidc_ischar()) {
570	v86.ctl = 0;
571	v86.addr = 0x18;
572	v86.eax = 0x0;
573	v86int();
574	return (v86.eax & 0xff);
575    } else {
576	return (-1);
577    }
578}
579
580static int
581vidc_ischar(void)
582{
583
584    v86.ctl = 0;
585    v86.addr = 0x18;
586    v86.eax = 0x100;
587    v86int();
588    return ((v86.ebx >> 8) & 0x1);
589}
590
591#if KEYBOARD_PROBE
592static int
593probe_keyboard(void)
594{
595    return (*(u_char *)PTOV(0xA1481) & 0x48);
596}
597#endif /* KEYBOARD_PROBE */
598