1 /* Code and data for the IBM console driver.
3 * The 6845 video controller used by the IBM PC shares its video memory with
4 * the CPU somewhere in the 0xB0000 memory bank. To the 6845 this memory
5 * consists of 16-bit words. Each word has a character code in the low byte
6 * and a so-called attribute byte in the high byte. The CPU directly modifies
7 * video memory to display characters, and sets two registers on the 6845 that
8 * specify the video origin and the cursor position. The video origin is the
9 * place in video memory where the first character (upper left corner) can
10 * be found. Moving the origin is a fast way to scroll the screen. Some
11 * video adapters wrap around the top of video memory, so the origin can
12 * move without bounds. For other adapters screen memory must sometimes be
13 * moved to reset the origin. All computations on video memory use character
14 * (word) addresses for simplicity and assume there is no wrapping. The
15 * assembly support functions translate the word addresses to byte addresses
16 * and the scrolling function worries about wrapping.
19 #include "../drivers.h"
21 #include <sys/ioctl.h>
23 #include <sys/video.h>
25 #include <minix/tty.h>
26 #include <minix/callnr.h>
27 #include <minix/com.h>
28 #include <minix/sys_config.h>
32 /* Set this to 1 if you want console output duplicated on the first
35 #define DUP_CONS_TO_SER 0
37 /* The clock task should provide an interface for this */
38 #define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */
40 /* Global variables used by the console driver and assembly support. */
41 PUBLIC phys_bytes vid_size
; /* 0x2000 for color or 0x0800 for mono */
42 PUBLIC phys_bytes vid_base
;
43 PUBLIC
unsigned vid_mask
; /* 0x1FFF for color or 0x07FF for mono */
44 PUBLIC
unsigned blank_color
= BLANK_COLOR
; /* display code for blank */
46 /* Private variables used by the console driver. */
47 PRIVATE
int vid_port
; /* I/O port for accessing 6845 */
48 PRIVATE
int wrap
; /* hardware can wrap? */
49 PRIVATE
int softscroll
; /* 1 = software scrolling, 0 = hardware */
50 PRIVATE
int beeping
; /* speaker is beeping? */
51 PRIVATE
unsigned font_lines
; /* font lines per character */
52 PRIVATE
unsigned scr_width
; /* # characters on a line */
53 PRIVATE
unsigned scr_lines
; /* # lines on the screen */
54 PRIVATE
unsigned scr_size
; /* # characters on the screen */
56 /* tells mem_vid_copy() to blank the screen */
57 #define BLANK_MEM ((vir_bytes) 0)
59 PRIVATE
int disabled_vc
= -1; /* Virtual console that was active when
60 * disable_console was called.
62 PRIVATE
int disabled_sm
; /* Scroll mode to be restored when re-enabling
66 char *console_memory
= NULL
;
67 char *font_memory
= NULL
;
69 /* Per console data. */
70 typedef struct console
{
71 tty_t
*c_tty
; /* associated TTY struct */
72 int c_column
; /* current column number (0-origin) */
73 int c_row
; /* current row (0 at top of screen) */
74 int c_rwords
; /* number of WORDS (not bytes) in outqueue */
75 unsigned c_start
; /* start of video memory of this console */
76 unsigned c_limit
; /* limit of this console's video memory */
77 unsigned c_org
; /* location in RAM where 6845 base points */
78 unsigned c_cur
; /* current position of cursor in video RAM */
79 unsigned c_attr
; /* character attribute */
80 unsigned c_blank
; /* blank attribute */
81 char c_reverse
; /* reverse video */
82 char c_esc_state
; /* 0=normal, 1=ESC, 2=ESC[ */
83 char c_esc_intro
; /* Distinguishing character following ESC */
84 int *c_esc_parmp
; /* pointer to current escape parameter */
85 int c_esc_parmv
[MAX_ESC_PARMS
]; /* list of escape parameters */
86 u16_t c_ramqueue
[CONS_RAM_WORDS
]; /* buffer for video RAM */
87 int c_line
; /* line no */
90 #define UPDATE_CURSOR(ccons, cursor) { \
91 ccons->c_cur = cursor; \
92 if(curcons && ccons == curcons) \
93 set_6845(CURSOR, ccons->c_cur); \
96 #define UPDATE_ORIGIN(ccons, origin) { \
97 ccons->c_org = origin; \
98 if (curcons && ccons == curcons) \
99 set_6845(VID_ORG, ccons->c_org); \
102 PRIVATE
int nr_cons
= 1; /* actual number of consoles */
103 PRIVATE console_t cons_table
[NR_CONS
];
104 PRIVATE console_t
*curcons
= NULL
; /* currently visible */
106 PRIVATE
int shutting_down
= FALSE
; /* don't allow console switches */
108 /* Color if using a color controller. */
109 #define color (vid_port == C_6845)
111 /* Map from ANSI colors to the attributes used by the PC */
112 PRIVATE
int ansi_colors
[8] = {0, 4, 2, 6, 1, 5, 3, 7};
114 /* Structure used for font management */
116 unsigned short index
;
121 FORWARD
_PROTOTYPE( int cons_write
, (struct tty
*tp
, int try) );
122 FORWARD
_PROTOTYPE( void cons_echo
, (tty_t
*tp
, int c
) );
123 FORWARD
_PROTOTYPE( void out_char
, (console_t
*cons
, int c
) );
124 FORWARD
_PROTOTYPE( void cons_putk
, (int c
) );
125 FORWARD
_PROTOTYPE( void beep
, (void) );
126 FORWARD
_PROTOTYPE( void do_escape
, (console_t
*cons
, int c
) );
127 FORWARD
_PROTOTYPE( void flush
, (console_t
*cons
) );
128 FORWARD
_PROTOTYPE( void parse_escape
, (console_t
*cons
, int c
) );
129 FORWARD
_PROTOTYPE( void scroll_screen
, (console_t
*cons
, int dir
) );
130 FORWARD
_PROTOTYPE( void set_6845
, (int reg
, unsigned val
) );
131 FORWARD
_PROTOTYPE( void stop_beep
, (timer_t
*tmrp
) );
132 FORWARD
_PROTOTYPE( void cons_org0
, (void) );
133 FORWARD
_PROTOTYPE( void disable_console
, (void) );
134 FORWARD
_PROTOTYPE( void reenable_console
, (void) );
135 FORWARD
_PROTOTYPE( int ga_program
, (struct sequence
*seq
) );
136 FORWARD
_PROTOTYPE( int cons_ioctl
, (tty_t
*tp
, int) );
137 FORWARD
_PROTOTYPE( void mem_vid_copy
, (vir_bytes src
, int dst
, int count
) );
138 FORWARD
_PROTOTYPE( void vid_vid_copy
, (int src
, int dst
, int count
) );
141 FORWARD
_PROTOTYPE( void get_6845
, (int reg
, unsigned *val
) );
144 /*===========================================================================*
146 *===========================================================================*/
147 PRIVATE
int cons_write(tp
, try)
148 register struct tty
*tp
; /* tells which terminal is to be used */
151 /* Copy as much data as possible to the output queue, then start I/O. On
152 * memory-mapped terminals, such as the IBM console, the I/O will also be
153 * finished, and the counts updated. Keep repeating until all I/O done.
160 console_t
*cons
= tp
->tty_priv
;
162 if (try) return 1; /* we can always write to console */
164 /* Check quickly for nothing to do, so this can be called often without
165 * unmodular tests elsewhere.
167 if ((count
= tp
->tty_outleft
) == 0 || tp
->tty_inhibited
) return 0;
169 /* Copy the user bytes to buf[] for decent addressing. Loop over the
170 * copies, since the user buffer may be much larger than buf[].
173 if (count
> sizeof(buf
)) count
= sizeof(buf
);
174 if(tp
->tty_out_safe
) {
175 if ((result
= sys_safecopyfrom(tp
->tty_outproc
, tp
->tty_out_vir_g
,
176 tp
->tty_out_vir_offset
, (vir_bytes
) buf
, count
, D
)) != OK
)
178 tp
->tty_out_vir_offset
+= count
;
180 if ((result
= sys_vircopy(tp
->tty_outproc
, D
, tp
->tty_out_vir_g
,
181 SELF
, D
, (vir_bytes
) buf
, (vir_bytes
) count
)) != OK
)
183 tp
->tty_out_vir_g
+= count
;
187 /* Update terminal data structure. */
188 tp
->tty_outcum
+= count
;
189 tp
->tty_outleft
-= count
;
191 /* Output each byte of the copy to the screen. Avoid calling
192 * out_char() for the "easy" characters, put them into the buffer
196 if ((unsigned) *tbuf
< ' ' || cons
->c_esc_state
> 0
197 || cons
->c_column
>= scr_width
198 || cons
->c_rwords
>= buflen(cons
->c_ramqueue
))
200 out_char(cons
, *tbuf
++);
203 if (cons
== &cons_table
[0]) ser_putc(*tbuf
);
205 cons
->c_ramqueue
[cons
->c_rwords
++] =
206 cons
->c_attr
| (*tbuf
++ & BYTE
);
209 } while (--count
!= 0);
210 } while ((count
= tp
->tty_outleft
) != 0 && !tp
->tty_inhibited
);
212 flush(cons
); /* transfer anything buffered to the screen */
214 /* Reply to the writer if all output is finished or if an error occured. */
215 if (tp
->tty_outleft
== 0 || result
!= OK
) {
216 /* REVIVE is not possible. I/O on memory mapped consoles finishes. */
217 tty_reply(tp
->tty_outrepcode
, tp
->tty_outcaller
, tp
->tty_outproc
,
225 /*===========================================================================*
227 *===========================================================================*/
228 PRIVATE
void cons_echo(tp
, c
)
229 register tty_t
*tp
; /* pointer to tty struct */
230 int c
; /* character to be echoed */
232 /* Echo keyboard input (print & flush). */
233 console_t
*cons
= tp
->tty_priv
;
239 /*===========================================================================*
241 *===========================================================================*/
242 PRIVATE
void out_char(cons
, c
)
243 register console_t
*cons
; /* pointer to console struct */
244 int c
; /* character to be output */
246 /* Output a character on the console. Check for escape sequences first. */
247 if (cons
->c_esc_state
> 0) {
248 parse_escape(cons
, c
);
253 if (cons
== &cons_table
[0] && c
!= '\0')
262 case 000: /* null is typically used for padding */
263 return; /* better not do anything */
265 case 007: /* ring the bell */
266 flush(cons
); /* print any chars queued for output */
270 case '\b': /* backspace */
271 if (--cons
->c_column
< 0) {
272 if (--cons
->c_row
>= 0) cons
->c_column
+= scr_width
;
277 case '\n': /* line feed */
278 if ((cons
->c_tty
->tty_termios
.c_oflag
& (OPOST
|ONLCR
))
283 case 013: /* CTRL-K */
284 case 014: /* CTRL-L */
285 if (cons
->c_row
== scr_lines
-1) {
286 scroll_screen(cons
, SCROLL_UP
);
293 case '\r': /* carriage return */
299 cons
->c_column
= (cons
->c_column
+ TAB_SIZE
) & ~TAB_MASK
;
300 if (cons
->c_column
> scr_width
) {
301 cons
->c_column
-= scr_width
;
302 if (cons
->c_row
== scr_lines
-1) {
303 scroll_screen(cons
, SCROLL_UP
);
311 case 033: /* ESC - start of an escape sequence */
312 flush(cons
); /* print any chars queued for output */
313 cons
->c_esc_state
= 1; /* mark ESC as seen */
316 default: /* printable chars are stored in ramqueue */
317 if (cons
->c_column
>= scr_width
) {
318 if (!LINEWRAP
) return;
319 if (cons
->c_row
== scr_lines
-1) {
320 scroll_screen(cons
, SCROLL_UP
);
327 if (cons
->c_rwords
== buflen(cons
->c_ramqueue
)) flush(cons
);
328 cons
->c_ramqueue
[cons
->c_rwords
++] = cons
->c_attr
| (c
& BYTE
);
329 cons
->c_column
++; /* next column */
334 /*===========================================================================*
336 *===========================================================================*/
337 PRIVATE
void scroll_screen(cons
, dir
)
338 register console_t
*cons
; /* pointer to console struct */
339 int dir
; /* SCROLL_UP or SCROLL_DOWN */
341 unsigned new_line
, new_org
, chars
;
344 chars
= scr_size
- scr_width
; /* one screen minus one line */
346 /* Scrolling the screen is a real nuisance due to the various incompatible
347 * video cards. This driver supports software scrolling (Hercules?),
348 * hardware scrolling (mono and CGA cards) and hardware scrolling without
349 * wrapping (EGA cards). In the latter case we must make sure that
350 * c_start <= c_org && c_org + scr_size <= c_limit
351 * holds, because EGA doesn't wrap around the end of video memory.
353 if (dir
== SCROLL_UP
) {
354 /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
356 vid_vid_copy(cons
->c_start
+ scr_width
, cons
->c_start
, chars
);
358 if (!wrap
&& cons
->c_org
+ scr_size
+ scr_width
>= cons
->c_limit
) {
359 vid_vid_copy(cons
->c_org
+ scr_width
, cons
->c_start
, chars
);
360 UPDATE_ORIGIN(cons
, cons
->c_start
);
362 UPDATE_ORIGIN(cons
, (cons
->c_org
+ scr_width
) & vid_mask
);
364 new_line
= (cons
->c_org
+ chars
) & vid_mask
;
366 /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
368 vid_vid_copy(cons
->c_start
, cons
->c_start
+ scr_width
, chars
);
370 if (!wrap
&& cons
->c_org
< cons
->c_start
+ scr_width
) {
371 new_org
= cons
->c_limit
- scr_size
;
372 vid_vid_copy(cons
->c_org
, new_org
+ scr_width
, chars
);
373 UPDATE_ORIGIN(cons
, new_org
);
375 UPDATE_ORIGIN(cons
, (cons
->c_org
- scr_width
) & vid_mask
);
377 new_line
= cons
->c_org
;
379 /* Blank the new line at top or bottom. */
380 blank_color
= cons
->c_blank
;
381 mem_vid_copy(BLANK_MEM
, new_line
, scr_width
);
386 /*===========================================================================*
388 *===========================================================================*/
389 PRIVATE
void flush(cons
)
390 register console_t
*cons
; /* pointer to console struct */
392 /* Send characters buffered in 'ramqueue' to screen memory, check the new
393 * cursor position, compute the new hardware cursor position and set it.
396 tty_t
*tp
= cons
->c_tty
;
398 /* Have the characters in 'ramqueue' transferred to the screen. */
399 if (cons
->c_rwords
> 0) {
400 mem_vid_copy((vir_bytes
) cons
->c_ramqueue
, cons
->c_cur
, cons
->c_rwords
);
403 /* TTY likes to know the current column and if echoing messed up. */
404 tp
->tty_position
= cons
->c_column
;
405 tp
->tty_reprint
= TRUE
;
408 /* Check and update the cursor position. */
409 if (cons
->c_column
< 0) cons
->c_column
= 0;
410 if (cons
->c_column
> scr_width
) cons
->c_column
= scr_width
;
411 if (cons
->c_row
< 0) cons
->c_row
= 0;
412 if (cons
->c_row
>= scr_lines
) cons
->c_row
= scr_lines
- 1;
413 cur
= cons
->c_org
+ cons
->c_row
* scr_width
+ cons
->c_column
;
414 if (cur
!= cons
->c_cur
)
415 UPDATE_CURSOR(cons
, cur
);
418 /*===========================================================================*
420 *===========================================================================*/
421 PRIVATE
void parse_escape(cons
, c
)
422 register console_t
*cons
; /* pointer to console struct */
423 char c
; /* next character in escape sequence */
425 /* The following ANSI escape sequences are currently supported.
426 * If n and/or m are omitted, they default to 1.
427 * ESC [nA moves up n lines
428 * ESC [nB moves down n lines
429 * ESC [nC moves right n spaces
430 * ESC [nD moves left n spaces
431 * ESC [m;nH" moves cursor to (m,n)
432 * ESC [J clears screen from cursor
433 * ESC [K clears line from cursor
434 * ESC [nL inserts n lines ar cursor
435 * ESC [nM deletes n lines at cursor
436 * ESC [nP deletes n chars at cursor
437 * ESC [n@ inserts n chars at cursor
438 * ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
439 * ESC M scrolls the screen backwards if the cursor is on the top line
442 switch (cons
->c_esc_state
) {
443 case 1: /* ESC seen */
444 cons
->c_esc_intro
= '\0';
445 cons
->c_esc_parmp
= bufend(cons
->c_esc_parmv
);
447 *--cons
->c_esc_parmp
= 0;
448 } while (cons
->c_esc_parmp
> cons
->c_esc_parmv
);
450 case '[': /* Control Sequence Introducer */
451 cons
->c_esc_intro
= c
;
452 cons
->c_esc_state
= 2;
454 case 'M': /* Reverse Index */
458 cons
->c_esc_state
= 0;
462 case 2: /* ESC [ seen */
463 if (c
>= '0' && c
<= '9') {
464 if (cons
->c_esc_parmp
< bufend(cons
->c_esc_parmv
))
465 *cons
->c_esc_parmp
= *cons
->c_esc_parmp
* 10 + (c
-'0');
468 if (cons
->c_esc_parmp
< bufend(cons
->c_esc_parmv
))
477 /*===========================================================================*
479 *===========================================================================*/
480 PRIVATE
void do_escape(cons
, c
)
481 register console_t
*cons
; /* pointer to console struct */
482 char c
; /* next character in escape sequence */
485 unsigned src
, dst
, count
;
488 /* Some of these things hack on screen RAM, so it had better be up to date */
491 if (cons
->c_esc_intro
== '\0') {
492 /* Handle a sequence beginning with just ESC */
494 case 'M': /* Reverse Index */
495 if (cons
->c_row
== 0) {
496 scroll_screen(cons
, SCROLL_DOWN
);
506 if (cons
->c_esc_intro
== '[') {
507 /* Handle a sequence beginning with ESC [ and parameters */
508 value
= cons
->c_esc_parmv
[0];
510 case 'A': /* ESC [nA moves up n lines */
511 n
= (value
== 0 ? 1 : value
);
516 case 'B': /* ESC [nB moves down n lines */
517 n
= (value
== 0 ? 1 : value
);
522 case 'C': /* ESC [nC moves right n spaces */
523 n
= (value
== 0 ? 1 : value
);
528 case 'D': /* ESC [nD moves left n spaces */
529 n
= (value
== 0 ? 1 : value
);
534 case 'H': /* ESC [m;nH" moves cursor to (m,n) */
535 cons
->c_row
= cons
->c_esc_parmv
[0] - 1;
536 cons
->c_column
= cons
->c_esc_parmv
[1] - 1;
540 case 'J': /* ESC [sJ clears in display */
542 case 0: /* Clear from cursor to end of screen */
543 count
= scr_size
- (cons
->c_cur
- cons
->c_org
);
546 case 1: /* Clear from start of screen to cursor */
547 count
= cons
->c_cur
- cons
->c_org
;
550 case 2: /* Clear entire screen */
554 default: /* Do nothing */
558 blank_color
= cons
->c_blank
;
559 mem_vid_copy(BLANK_MEM
, dst
, count
);
562 case 'K': /* ESC [sK clears line from cursor */
564 case 0: /* Clear from cursor to end of line */
565 count
= scr_width
- cons
->c_column
;
568 case 1: /* Clear from beginning of line to cursor */
569 count
= cons
->c_column
;
570 dst
= cons
->c_cur
- cons
->c_column
;
572 case 2: /* Clear entire line */
574 dst
= cons
->c_cur
- cons
->c_column
;
576 default: /* Do nothing */
580 blank_color
= cons
->c_blank
;
581 mem_vid_copy(BLANK_MEM
, dst
, count
);
584 case 'L': /* ESC [nL inserts n lines at cursor */
587 if (n
> (scr_lines
- cons
->c_row
))
588 n
= scr_lines
- cons
->c_row
;
590 src
= cons
->c_org
+ cons
->c_row
* scr_width
;
591 dst
= src
+ n
* scr_width
;
592 count
= (scr_lines
- cons
->c_row
- n
) * scr_width
;
593 vid_vid_copy(src
, dst
, count
);
594 blank_color
= cons
->c_blank
;
595 mem_vid_copy(BLANK_MEM
, src
, n
* scr_width
);
598 case 'M': /* ESC [nM deletes n lines at cursor */
601 if (n
> (scr_lines
- cons
->c_row
))
602 n
= scr_lines
- cons
->c_row
;
604 dst
= cons
->c_org
+ cons
->c_row
* scr_width
;
605 src
= dst
+ n
* scr_width
;
606 count
= (scr_lines
- cons
->c_row
- n
) * scr_width
;
607 vid_vid_copy(src
, dst
, count
);
608 blank_color
= cons
->c_blank
;
609 mem_vid_copy(BLANK_MEM
, dst
+ count
, n
* scr_width
);
612 case '@': /* ESC [n@ inserts n chars at cursor */
615 if (n
> (scr_width
- cons
->c_column
))
616 n
= scr_width
- cons
->c_column
;
620 count
= scr_width
- cons
->c_column
- n
;
621 vid_vid_copy(src
, dst
, count
);
622 blank_color
= cons
->c_blank
;
623 mem_vid_copy(BLANK_MEM
, src
, n
);
626 case 'P': /* ESC [nP deletes n chars at cursor */
629 if (n
> (scr_width
- cons
->c_column
))
630 n
= scr_width
- cons
->c_column
;
634 count
= scr_width
- cons
->c_column
- n
;
635 vid_vid_copy(src
, dst
, count
);
636 blank_color
= cons
->c_blank
;
637 mem_vid_copy(BLANK_MEM
, dst
+ count
, n
);
640 case 'm': /* ESC [nm enables rendition n */
641 for (parmp
= cons
->c_esc_parmv
; parmp
<= cons
->c_esc_parmp
642 && parmp
< bufend(cons
->c_esc_parmv
); parmp
++) {
643 if (cons
->c_reverse
) {
644 /* Unswap fg and bg colors */
645 cons
->c_attr
= ((cons
->c_attr
& 0x7000) >> 4) |
646 ((cons
->c_attr
& 0x0700) << 4) |
647 ((cons
->c_attr
& 0x8800));
649 switch (n
= *parmp
) {
651 cons
->c_attr
= cons
->c_blank
= BLANK_COLOR
;
652 cons
->c_reverse
= FALSE
;
656 /* Set intensity bit */
657 cons
->c_attr
|= 0x0800;
660 case 4: /* UNDERLINE */
662 /* Change white to cyan, i.e. lose red
664 cons
->c_attr
= (cons
->c_attr
& 0xBBFF);
666 /* Set underline attribute */
667 cons
->c_attr
= (cons
->c_attr
& 0x99FF);
671 case 5: /* BLINKING */
672 /* Set the blink bit */
673 cons
->c_attr
|= 0x8000;
676 case 7: /* REVERSE */
677 cons
->c_reverse
= TRUE
;
681 if (n
== 39) n
= 37; /* set default color */
685 /* Don't mess up a monochrome screen */
687 if (30 <= n
&& n
<= 37) {
688 /* Foreground color */
690 (cons
->c_attr
& 0xF8FF) |
691 (ansi_colors
[(n
- 30)] << 8);
693 (cons
->c_blank
& 0xF8FF) |
694 (ansi_colors
[(n
- 30)] << 8);
696 if (40 <= n
&& n
<= 47) {
697 /* Background color */
699 (cons
->c_attr
& 0x8FFF) |
700 (ansi_colors
[(n
- 40)] << 12);
702 (cons
->c_blank
& 0x8FFF) |
703 (ansi_colors
[(n
- 40)] << 12);
706 if (cons
->c_reverse
) {
707 /* Swap fg and bg colors */
708 cons
->c_attr
= ((cons
->c_attr
& 0x7000) >> 4) |
709 ((cons
->c_attr
& 0x0700) << 4) |
710 ((cons
->c_attr
& 0x8800));
716 cons
->c_esc_state
= 0;
719 /*===========================================================================*
721 *===========================================================================*/
722 PRIVATE
void set_6845(reg
, val
)
723 int reg
; /* which register pair to set */
724 unsigned val
; /* 16-bit value to set it to */
726 /* Set a register pair inside the 6845.
727 * Registers 12-13 tell the 6845 where in video ram to start
728 * Registers 14-15 tell the 6845 where to put the cursor
730 pvb_pair_t char_out
[4];
731 pv_set(char_out
[0], vid_port
+ INDEX
, reg
); /* set index register */
732 pv_set(char_out
[1], vid_port
+ DATA
, (val
>>8) & BYTE
); /* high byte */
733 pv_set(char_out
[2], vid_port
+ INDEX
, reg
+ 1); /* again */
734 pv_set(char_out
[3], vid_port
+ DATA
, val
&BYTE
); /* low byte */
735 sys_voutb(char_out
, 4); /* do actual output */
739 /*===========================================================================*
741 *===========================================================================*/
742 PRIVATE
void get_6845(reg
, val
)
743 int reg
; /* which register pair to set */
744 unsigned *val
; /* 16-bit value to set it to */
748 /* Get a register pair inside the 6845. */
749 sys_outb(vid_port
+ INDEX
, reg
);
750 sys_inb(vid_port
+ DATA
, &v
);
752 sys_outb(vid_port
+ INDEX
, reg
+1);
753 sys_inb(vid_port
+ DATA
, &v
);
755 *val
= (v1
<< 8) | v2
;
759 /*===========================================================================*
761 *===========================================================================*/
764 /* Making a beeping sound on the speaker (output for CRTL-G).
765 * This routine works by turning on the bits 0 and 1 in port B of the 8255
766 * chip that drive the speaker.
768 static timer_t tmr_stop_beep
;
769 pvb_pair_t char_out
[3];
771 unsigned long port_b_val
;
774 /* Fetch current time in advance to prevent beeping delay. */
775 if ((s
=getuptime(&now
)) != OK
)
776 panic("TTY","Console couldn't get clock's uptime.", s
);
778 /* Set timer channel 2, square wave, with given frequency. */
779 pv_set(char_out
[0], TIMER_MODE
, 0xB6);
780 pv_set(char_out
[1], TIMER2
, (BEEP_FREQ
>> 0) & BYTE
);
781 pv_set(char_out
[2], TIMER2
, (BEEP_FREQ
>> 8) & BYTE
);
782 if (sys_voutb(char_out
, 3)==OK
) {
783 if (sys_inb(PORT_B
, &port_b_val
)==OK
&&
784 sys_outb(PORT_B
, (port_b_val
|3))==OK
)
788 /* Add a timer to the timers list. Possibly reschedule the alarm. */
789 tmrs_settimer(&tty_timers
, &tmr_stop_beep
, now
+B_TIME
, stop_beep
, NULL
);
790 if (tty_timers
->tmr_exp_time
!= tty_next_timeout
) {
791 tty_next_timeout
= tty_timers
->tmr_exp_time
;
792 if ((s
=sys_setalarm(tty_next_timeout
, 1)) != OK
)
793 panic("TTY","Console couldn't set alarm.", s
);
798 /*===========================================================================*
800 *===========================================================================*/
801 PUBLIC
void do_video(message
*m
)
805 /* Execute the requested device driver function. */
806 r
= EINVAL
; /* just in case */
809 /* Should grant IOPL */
819 switch(m
->TTY_REQUEST
) {
823 struct mapreqvm mapreqvm
;
826 do_map
= (m
->REQUEST
== TIOCMAPMEM
); /* else unmap */
828 /* Get request structure */
830 printf("tty: safecopy only\n");
834 r
= sys_safecopyfrom(m
->IO_ENDPT
,
835 (vir_bytes
)m
->ADDRESS
, 0, (vir_bytes
) &mapreqvm
,
836 sizeof(mapreqvm
), D
);
840 printf("tty: sys_safecopyfrom failed\n");
841 tty_reply(TASK_REPLY
, m
->m_source
, m
->IO_ENDPT
,
846 /* In safe ioctl mode, the POSITION field contains
847 * the endpt number of the original requestor.
848 * IO_ENDPT is always FS.
852 mapreqvm
.vaddr_ret
= vm_map_phys(m
->POSITION
,
853 (void *) mapreqvm
.phys_offset
, mapreqvm
.size
);
854 if((r
= sys_safecopyto(m
->IO_ENDPT
,
855 (vir_bytes
)m
->ADDRESS
, 0,
856 (vir_bytes
) &mapreqvm
,
857 sizeof(mapreqvm
), D
)) != OK
) {
858 printf("tty: sys_safecopyto failed\n");
861 r
= vm_unmap_phys(m
->POSITION
,
862 mapreqvm
.vaddr
, mapreqvm
.size
);
864 tty_reply(TASK_REPLY
, m
->m_source
, m
->IO_ENDPT
, r
);
873 "Warning, TTY(video) got unexpected request %d from %d\n",
874 m
->m_type
, m
->m_source
);
877 tty_reply(TASK_REPLY
, m
->m_source
, m
->IO_ENDPT
, r
);
881 /*===========================================================================*
883 *===========================================================================*/
884 PUBLIC
void beep_x(freq
, dur
)
888 /* Making a beeping sound on the speaker.
889 * This routine works by turning on the bits 0 and 1 in port B of the 8255
890 * chip that drive the speaker.
892 static timer_t tmr_stop_beep
;
893 pvb_pair_t char_out
[3];
895 unsigned long port_b_val
;
898 unsigned long ival
= TIMER_FREQ
/ freq
;
899 if (ival
== 0 || ival
> 0xffff)
900 return; /* Frequency out of range */
902 /* Fetch current time in advance to prevent beeping delay. */
903 if ((s
=getuptime(&now
)) != OK
)
904 panic("TTY","Console couldn't get clock's uptime.", s
);
906 /* Set timer channel 2, square wave, with given frequency. */
907 pv_set(char_out
[0], TIMER_MODE
, 0xB6);
908 pv_set(char_out
[1], TIMER2
, (ival
>> 0) & BYTE
);
909 pv_set(char_out
[2], TIMER2
, (ival
>> 8) & BYTE
);
910 if (sys_voutb(char_out
, 3)==OK
) {
911 if (sys_inb(PORT_B
, &port_b_val
)==OK
&&
912 sys_outb(PORT_B
, (port_b_val
|3))==OK
)
916 /* Add a timer to the timers list. Possibly reschedule the alarm. */
917 tmrs_settimer(&tty_timers
, &tmr_stop_beep
, now
+dur
, stop_beep
, NULL
);
918 if (tty_timers
->tmr_exp_time
!= tty_next_timeout
) {
919 tty_next_timeout
= tty_timers
->tmr_exp_time
;
920 if ((s
=sys_setalarm(tty_next_timeout
, 1)) != OK
)
921 panic("TTY","Console couldn't set alarm.", s
);
925 /*===========================================================================*
927 *===========================================================================*/
928 PRIVATE
void stop_beep(tmrp
)
931 /* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
932 unsigned long port_b_val
;
933 if (sys_inb(PORT_B
, &port_b_val
)==OK
&&
934 sys_outb(PORT_B
, (port_b_val
& ~3))==OK
)
938 /*===========================================================================*
940 *===========================================================================*/
941 PUBLIC
void scr_init(tp
)
944 /* Initialize the screen driver. */
946 u16_t bios_columns
, bios_crtbase
, bios_fontlines
;
950 static int vdu_initialized
= 0;
951 static unsigned page_size
;
953 /* Associate console and TTY. */
954 line
= tp
- &tty_table
[0];
955 if (line
>= nr_cons
) return;
956 cons
= &cons_table
[line
];
961 /* Fill in TTY function hooks. */
962 tp
->tty_devwrite
= cons_write
;
963 tp
->tty_echo
= cons_echo
;
964 tp
->tty_ioctl
= cons_ioctl
;
966 /* Get the BIOS parameters that describe the VDU. */
967 if (! vdu_initialized
++) {
969 /* How about error checking? What to do on failure??? */
970 s
=sys_readbios(VDU_SCREEN_COLS_ADDR
, &bios_columns
,
971 VDU_SCREEN_COLS_SIZE
);
972 s
=sys_readbios(VDU_CRT_BASE_ADDR
, &bios_crtbase
,
974 s
=sys_readbios( VDU_SCREEN_ROWS_ADDR
, &bios_rows
,
975 VDU_SCREEN_ROWS_SIZE
);
976 s
=sys_readbios(VDU_FONTLINES_ADDR
, &bios_fontlines
,
979 vid_port
= bios_crtbase
;
980 scr_width
= bios_columns
;
981 font_lines
= bios_fontlines
;
982 scr_lines
= machine
.vdu_ega
? bios_rows
+1 : 25;
985 vid_base
= COLOR_BASE
;
986 vid_size
= COLOR_SIZE
;
988 vid_base
= MONO_BASE
;
989 vid_size
= MONO_SIZE
;
991 if (machine
.vdu_ega
) vid_size
= EGA_SIZE
;
992 wrap
= ! machine
.vdu_ega
;
994 console_memory
= vm_map_phys(SELF
, (void *) vid_base
, vid_size
);
996 if(console_memory
== MAP_FAILED
)
997 panic("TTY","Console couldn't map video memory", NO_NUM
);
999 font_memory
= vm_map_phys(SELF
, (void *)GA_VIDEO_ADDRESS
, GA_FONT_SIZE
);
1001 if(font_memory
== MAP_FAILED
)
1002 panic("TTY","Console couldn't map font memory", NO_NUM
);
1005 vid_size
>>= 1; /* word count */
1006 vid_mask
= vid_size
- 1;
1008 /* Size of the screen (number of displayed characters.) */
1009 scr_size
= scr_lines
* scr_width
;
1011 /* There can be as many consoles as video memory allows. */
1012 nr_cons
= vid_size
/ scr_size
;
1014 if (nr_cons
> NR_CONS
) nr_cons
= NR_CONS
;
1015 if (nr_cons
> 1) wrap
= 0;
1016 page_size
= vid_size
/ nr_cons
;
1019 cons
->c_start
= line
* page_size
;
1020 cons
->c_limit
= cons
->c_start
+ page_size
;
1021 cons
->c_cur
= cons
->c_org
= cons
->c_start
;
1022 cons
->c_attr
= cons
->c_blank
= BLANK_COLOR
;
1025 /* Clear the non-console vtys. */
1026 blank_color
= BLANK_COLOR
;
1027 mem_vid_copy(BLANK_MEM
, cons
->c_start
, scr_size
);
1029 /* Set the cursor of the console vty at the bottom. c_cur
1030 * is updated automatically later.
1032 scroll_screen(cons
, SCROLL_UP
);
1033 cons
->c_row
= scr_lines
- 1;
1040 /*===========================================================================*
1042 *===========================================================================*/
1043 PUBLIC
void kputc(c
)
1046 /* Accumulate a single character for a kernel message. Send a notification
1047 * the to output driver if an END_OF_KMESS is encountered.
1059 kmess
.km_buf
[kmess
.km_next
] = c
; /* put normal char in buffer */
1060 if (kmess
.km_size
< _KMESS_BUF_SIZE
)
1062 kmess
.km_next
= (kmess
.km_next
+ 1) % _KMESS_BUF_SIZE
;
1064 notify(LOG_PROC_NR
);
1068 /*===========================================================================*
1070 *===========================================================================*/
1071 PUBLIC
void do_new_kmess(m
)
1074 /* Notification for a new kernel message. */
1075 static struct kmessages kmess
; /* kmessages structure */
1076 static int prev_next
= 0; /* previous next seen */
1080 /* Try to get a fresh copy of the buffer with kernel messages. */
1082 /* During shutdown, the reply is garbled because new notifications arrive
1083 * while the system task makes a copy of the kernel messages buffer.
1084 * Hence, don't check the return value.
1086 if ((r
=sys_getkmessages(&kmess
)) != OK
) {
1087 printf("TTY: couldn't get copy of kmessages: %d, 0x%x\n", r
,r
);
1091 sys_getkmessages(&kmess
);
1093 /* Print only the new part. Determine how many new bytes there are with
1094 * help of the current and previous 'next' index. Note that the kernel
1095 * buffer is circular. This works fine if less then _KMESS_BUF_SIZE bytes
1096 * is new data; else we miss % _KMESS_BUF_SIZE here.
1097 * Check for size being positive, the buffer might as well be emptied!
1099 if (kmess
.km_size
> 0) {
1100 bytes
= ((kmess
.km_next
+ _KMESS_BUF_SIZE
) - prev_next
) % _KMESS_BUF_SIZE
;
1101 r
=prev_next
; /* start at previous old */
1103 cons_putk( kmess
.km_buf
[(r
%_KMESS_BUF_SIZE
)] );
1107 cons_putk(0); /* terminate to flush output */
1110 /* Almost done, store 'next' so that we can determine what part of the
1111 * kernel messages buffer to print next time a notification arrives.
1113 prev_next
= kmess
.km_next
;
1116 /*===========================================================================*
1118 *===========================================================================*/
1119 PUBLIC
void do_diagnostics(m_ptr
, safe
)
1120 message
*m_ptr
; /* pointer to request message */
1123 /* Print a string for a server. */
1126 int count
, offset
= 0;
1128 int proc_nr
= m_ptr
->m_source
;
1130 src
= (vir_bytes
) m_ptr
->DIAG_PRINT_BUF_G
;
1131 for (count
= m_ptr
->DIAG_BUF_COUNT
; count
> 0; count
--) {
1134 r
= sys_safecopyfrom(proc_nr
, src
, offset
, (vir_bytes
) &c
, 1, D
);
1136 printf("<tty: proc %d, grant %ld>", proc_nr
, src
);
1138 r
= sys_vircopy(proc_nr
, D
, src
+offset
, SELF
, D
, (vir_bytes
) &c
, 1);
1147 cons_putk(0); /* always terminate, even with EFAULT */
1149 if(m_ptr
->m_type
!= ASYN_DIAGNOSTICS_OLD
) {
1150 m_ptr
->m_type
= DIAG_REPL_OLD
;
1151 m_ptr
->REP_STATUS
= result
;
1152 send(m_ptr
->m_source
, m_ptr
);
1156 /*===========================================================================*
1158 *===========================================================================*/
1159 PUBLIC
void do_get_kmess(m_ptr
)
1160 message
*m_ptr
; /* pointer to request message */
1162 /* Provide the log device with debug output */
1166 dst
= (vir_bytes
) m_ptr
->GETKM_PTR
;
1168 if (sys_vircopy(SELF
, D
, (vir_bytes
)&kmess
, m_ptr
->m_source
, D
,
1169 dst
, sizeof(kmess
)) != OK
) {
1173 send(m_ptr
->m_source
, m_ptr
);
1176 /*===========================================================================*
1178 *===========================================================================*/
1179 PUBLIC
void do_get_kmess_s(m_ptr
)
1180 message
*m_ptr
; /* pointer to request message */
1182 /* Provide the log device with debug output */
1186 gid
= m_ptr
->GETKM_GRANT
;
1188 if (sys_safecopyto(m_ptr
->m_source
, gid
, 0, (vir_bytes
)&kmess
, sizeof(kmess
),
1193 send(m_ptr
->m_source
, m_ptr
);
1196 /*===========================================================================*
1198 *===========================================================================*/
1199 PRIVATE
void cons_putk(c
)
1200 int c
; /* character to print */
1202 /* This procedure is used to print a character on the console.
1205 if (c
== '\n') cons_putk('\r');
1206 out_char(&cons_table
[0], (int) c
);
1211 flush(&cons_table
[0]);
1215 /*===========================================================================*
1217 *===========================================================================*/
1218 PUBLIC
void toggle_scroll()
1220 /* Toggle between hardware and software scroll. */
1223 softscroll
= !softscroll
;
1224 printf("%sware scrolling enabled.\n", softscroll
? "Soft" : "Hard");
1227 /*===========================================================================*
1229 *===========================================================================*/
1230 PUBLIC
void cons_stop()
1232 /* Prepare for halt or reboot. */
1236 cons_table
[0].c_attr
= cons_table
[0].c_blank
= BLANK_COLOR
;
1237 shutting_down
= TRUE
;
1240 /*===========================================================================*
1242 *===========================================================================*/
1243 PRIVATE
void cons_org0()
1245 /* Scroll video memory back to put the origin at 0. */
1250 for (cons_line
= 0; cons_line
< nr_cons
; cons_line
++) {
1251 cons
= &cons_table
[cons_line
];
1252 while (cons
->c_org
> cons
->c_start
) {
1253 n
= vid_size
- scr_size
; /* amount of unused memory */
1254 if (n
> cons
->c_org
- cons
->c_start
)
1255 n
= cons
->c_org
- cons
->c_start
;
1256 vid_vid_copy(cons
->c_org
, cons
->c_org
- n
, scr_size
);
1257 UPDATE_ORIGIN(cons
, cons
->c_org
- n
);
1261 select_console(ccurrent
);
1264 /*===========================================================================*
1266 *===========================================================================*/
1267 PRIVATE
void disable_console()
1269 if (disabled_vc
!= -1)
1272 disabled_vc
= ccurrent
;
1273 disabled_sm
= softscroll
;
1279 /* Should also disable further output to virtual consoles */
1282 /*===========================================================================*
1283 * reenable_console *
1284 *===========================================================================*/
1285 PRIVATE
void reenable_console()
1287 if (disabled_vc
== -1)
1290 softscroll
= disabled_sm
;
1291 select_console(disabled_vc
);
1295 /*===========================================================================*
1297 *===========================================================================*/
1298 PUBLIC
void select_console(int cons_line
)
1300 /* Set the current console to console number 'cons_line'. */
1302 if (shutting_down
) return;
1304 if (cons_line
< 0 || cons_line
>= nr_cons
) return;
1306 ccurrent
= cons_line
;
1307 curcons
= &cons_table
[cons_line
];
1309 UPDATE_CURSOR(curcons
, curcons
->c_cur
);
1310 UPDATE_ORIGIN(curcons
, curcons
->c_org
);
1313 /*===========================================================================*
1315 *===========================================================================*/
1316 PUBLIC
int con_loadfont(m
)
1320 /* Load a font into the EGA or VGA adapter. */
1322 static struct sequence seq1
[7] = {
1323 { GA_SEQUENCER_INDEX
, 0x00, 0x01 },
1324 { GA_SEQUENCER_INDEX
, 0x02, 0x04 },
1325 { GA_SEQUENCER_INDEX
, 0x04, 0x07 },
1326 { GA_SEQUENCER_INDEX
, 0x00, 0x03 },
1327 { GA_GRAPHICS_INDEX
, 0x04, 0x02 },
1328 { GA_GRAPHICS_INDEX
, 0x05, 0x00 },
1329 { GA_GRAPHICS_INDEX
, 0x06, 0x00 },
1331 static struct sequence seq2
[7] = {
1332 { GA_SEQUENCER_INDEX
, 0x00, 0x01 },
1333 { GA_SEQUENCER_INDEX
, 0x02, 0x03 },
1334 { GA_SEQUENCER_INDEX
, 0x04, 0x03 },
1335 { GA_SEQUENCER_INDEX
, 0x00, 0x03 },
1336 { GA_GRAPHICS_INDEX
, 0x04, 0x00 },
1337 { GA_GRAPHICS_INDEX
, 0x05, 0x10 },
1338 { GA_GRAPHICS_INDEX
, 0x06, 0 },
1341 seq2
[6].value
= color
? 0x0E : 0x0A;
1343 if (!machine
.vdu_ega
) return(ENOTTY
);
1344 result
= ga_program(seq1
); /* bring font memory into view */
1346 if(sys_safecopyfrom(m
->IO_ENDPT
, (cp_grant_id_t
) m
->ADDRESS
, 0,
1347 (vir_bytes
) font_memory
, GA_FONT_SIZE
, D
) != OK
) {
1348 printf("tty: copying from %d failed\n", m
->IO_ENDPT
);
1352 result
= ga_program(seq2
); /* restore */
1357 /*===========================================================================*
1359 *===========================================================================*/
1360 PRIVATE
int ga_program(seq
)
1361 struct sequence
*seq
;
1363 pvb_pair_t char_out
[14];
1365 for (i
=0; i
<7; i
++) {
1366 pv_set(char_out
[2*i
], seq
->index
, seq
->port
);
1367 pv_set(char_out
[2*i
+1], seq
->index
+1, seq
->value
);
1370 return sys_voutb(char_out
, 14);
1373 /*===========================================================================*
1375 *===========================================================================*/
1376 PRIVATE
int cons_ioctl(tp
, try)
1380 /* Set the screen dimensions. */
1382 tp
->tty_winsize
.ws_row
= scr_lines
;
1383 tp
->tty_winsize
.ws_col
= scr_width
;
1384 tp
->tty_winsize
.ws_xpixel
= scr_width
* 8;
1385 tp
->tty_winsize
.ws_ypixel
= scr_lines
* font_lines
;
1390 #define LIMITINDEX(mask, start, size, ct) { \
1391 int countlimit = size - start; \
1393 if(ct > countlimit) ct = countlimit; \
1396 /*===========================================================================*
1398 *===========================================================================*/
1399 PRIVATE
void mem_vid_copy(vir_bytes src
, int dst_index
, int count
)
1401 u16_t
*src_mem
= (u16_t
*) src
;
1403 int i
, subcount
= count
;
1405 LIMITINDEX(vid_mask
, dst_index
, vid_size
, subcount
);
1406 dst_mem
= (u16_t
*) console_memory
+ dst_index
;
1408 for(i
= 0; i
< subcount
; i
++)
1409 *dst_mem
++ = blank_color
;
1411 for(i
= 0; i
< subcount
; i
++)
1412 *dst_mem
++ = *src_mem
++;
1414 dst_index
+= subcount
;
1418 /*===========================================================================*
1420 *===========================================================================*/
1421 PRIVATE
void vid_vid_copy(int src_index
, int dst_index
, int count
)
1424 if(src_index
< dst_index
)
1427 int i
, subcount
= count
;
1428 u16_t
*dst_mem
, *src_mem
;
1429 LIMITINDEX(vid_mask
, src_index
, vid_size
, subcount
);
1430 LIMITINDEX(vid_mask
, dst_index
, vid_size
, subcount
);
1431 src_mem
= (u16_t
*) console_memory
+ src_index
;
1432 dst_mem
= (u16_t
*) console_memory
+ dst_index
;
1434 src_mem
+= subcount
- 1;
1435 dst_mem
+= subcount
- 1;
1436 for(i
= 0; i
< subcount
; i
++)
1437 *dst_mem
-- = *src_mem
--;
1439 for(i
= 0; i
< subcount
; i
++)
1440 *dst_mem
++ = *src_mem
++;
1443 dst_index
+= subcount
;
1444 src_index
+= subcount
;