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 <minix/drivers.h>
22 #include <sys/ioctl.h>
24 #include <sys/video.h>
26 #include <minix/tty.h>
27 #include <minix/callnr.h>
28 #include <minix/com.h>
29 #include <minix/sys_config.h>
33 /* Set this to 1 if you want console output duplicated on the first
36 #define DUP_CONS_TO_SER 0
38 /* The clock task should provide an interface for this */
39 #define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */
41 /* Global variables used by the console driver and assembly support. */
42 static phys_bytes vid_size
; /* 0x2000 for color or 0x0800 for mono */
43 static phys_bytes vid_base
;
44 static unsigned vid_mask
; /* 0x1FFF for color or 0x07FF for mono */
45 static unsigned blank_color
= BLANK_COLOR
; /* display code for blank */
47 /* Private variables used by the console driver. */
48 static int vid_port
; /* I/O port for accessing 6845 */
49 static int wrap
; /* hardware can wrap? */
50 static int softscroll
; /* 1 = software scrolling, 0 = hardware */
51 static int beeping
; /* speaker is beeping? */
52 static unsigned font_lines
; /* font lines per character */
53 static unsigned scr_width
; /* # characters on a line */
54 static unsigned scr_lines
; /* # lines on the screen */
55 static unsigned scr_size
; /* # characters on the screen */
57 /* tells mem_vid_copy() to blank the screen */
58 #define BLANK_MEM ((vir_bytes) 0)
60 static int disabled_vc
= -1; /* Virtual console that was active when
61 * disable_console was called.
63 static int disabled_sm
; /* Scroll mode to be restored when re-enabling
67 static char *console_memory
= NULL
;
68 static char *font_memory
= NULL
;
70 /* Per console data. */
71 typedef struct console
{
72 tty_t
*c_tty
; /* associated TTY struct */
73 int c_column
; /* current column number (0-origin) */
74 int c_row
; /* current row (0 at top of screen) */
75 int c_rwords
; /* number of WORDS (not bytes) in outqueue */
76 unsigned c_start
; /* start of video memory of this console */
77 unsigned c_limit
; /* limit of this console's video memory */
78 unsigned c_org
; /* location in RAM where 6845 base points */
79 unsigned c_cur
; /* current position of cursor in video RAM */
80 unsigned c_attr
; /* character attribute */
81 unsigned c_blank
; /* blank attribute */
82 char c_reverse
; /* reverse video */
83 char c_esc_state
; /* 0=normal, 1=ESC, 2=ESC[ */
84 char c_esc_intro
; /* Distinguishing character following ESC */
85 int *c_esc_parmp
; /* pointer to current escape parameter */
86 int c_esc_parmv
[MAX_ESC_PARMS
]; /* list of escape parameters */
87 u16_t c_ramqueue
[CONS_RAM_WORDS
]; /* buffer for video RAM */
88 int c_line
; /* line no */
91 #define UPDATE_CURSOR(ccons, cursor) { \
92 ccons->c_cur = cursor; \
93 if(curcons && ccons == curcons) \
94 set_6845(CURSOR, ccons->c_cur); \
97 #define UPDATE_ORIGIN(ccons, origin) { \
98 ccons->c_org = origin; \
99 if (curcons && ccons == curcons) \
100 set_6845(VID_ORG, ccons->c_org); \
103 static int nr_cons
= 1; /* actual number of consoles */
104 static console_t cons_table
[NR_CONS
];
105 static console_t
*curcons
= NULL
; /* currently visible */
107 static int shutting_down
= FALSE
; /* don't allow console switches */
109 /* Color if using a color controller. */
110 #define color (vid_port == C_6845)
112 /* Map from ANSI colors to the attributes used by the PC */
113 static int ansi_colors
[8] = {0, 4, 2, 6, 1, 5, 3, 7};
115 /* Structure used for font management */
117 unsigned short index
;
122 static int cons_write(struct tty
*tp
, int try);
123 static void cons_echo(tty_t
*tp
, int c
);
124 static void out_char(console_t
*cons
, int c
);
125 static void cons_putk(int c
);
126 static void beep(void);
127 static void do_escape(console_t
*cons
, int c
);
128 static void flush(console_t
*cons
);
129 static void parse_escape(console_t
*cons
, int c
);
130 static void scroll_screen(console_t
*cons
, int dir
);
131 static void set_6845(int reg
, unsigned val
);
132 static void stop_beep(timer_t
*tmrp
);
133 static void cons_org0(void);
134 static void disable_console(void);
135 static void reenable_console(void);
136 static int ga_program(struct sequence
*seq
);
137 static int cons_ioctl(tty_t
*tp
, int);
138 static void mem_vid_copy(vir_bytes src
, int dst
, int count
);
139 static void vid_vid_copy(int src
, int dst
, int count
);
142 static void get_6845(int reg
, unsigned *val
);
145 /*===========================================================================*
147 *===========================================================================*/
148 static int cons_write(tp
, try)
149 register struct tty
*tp
; /* tells which terminal is to be used */
152 /* Copy as much data as possible to the output queue, then start I/O. On
153 * memory-mapped terminals, such as the IBM console, the I/O will also be
154 * finished, and the counts updated. Keep repeating until all I/O done.
161 console_t
*cons
= tp
->tty_priv
;
163 if (try) return 1; /* we can always write to console */
165 /* Check quickly for nothing to do, so this can be called often without
166 * unmodular tests elsewhere.
168 if ((count
= tp
->tty_outleft
) == 0 || tp
->tty_inhibited
) return 0;
170 /* Copy the user bytes to buf[] for decent addressing. Loop over the
171 * copies, since the user buffer may be much larger than buf[].
174 if (count
> sizeof(buf
)) count
= sizeof(buf
);
175 if ((result
= sys_safecopyfrom(tp
->tty_outcaller
, tp
->tty_outgrant
,
176 tp
->tty_outoffset
, (vir_bytes
) buf
, count
)) != OK
)
178 tp
->tty_outoffset
+= count
;
181 /* Update terminal data structure. */
182 tp
->tty_outcum
+= count
;
183 tp
->tty_outleft
-= count
;
185 /* Output each byte of the copy to the screen. Avoid calling
186 * out_char() for the "easy" characters, put them into the buffer
190 if ((unsigned) *tbuf
< ' ' || cons
->c_esc_state
> 0
191 || cons
->c_column
>= scr_width
192 || cons
->c_rwords
>= buflen(cons
->c_ramqueue
))
194 out_char(cons
, *tbuf
++);
197 if (cons
== &cons_table
[0]) ser_putc(*tbuf
);
199 cons
->c_ramqueue
[cons
->c_rwords
++] =
200 cons
->c_attr
| (*tbuf
++ & BYTE
);
203 } while (--count
!= 0);
204 } while ((count
= tp
->tty_outleft
) != 0 && !tp
->tty_inhibited
);
206 flush(cons
); /* transfer anything buffered to the screen */
208 /* Reply to the writer if all output is finished or if an error occured. */
209 if (tp
->tty_outleft
== 0 || result
!= OK
) {
210 if(tp
->tty_outrepcode
== TTY_REVIVE
) {
211 notify(tp
->tty_outcaller
);
212 tp
->tty_outrevived
= 1;
214 tty_reply(tp
->tty_outrepcode
, tp
->tty_outcaller
,
215 tp
->tty_outproc
, tp
->tty_outcum
);
223 /*===========================================================================*
225 *===========================================================================*/
226 static void cons_echo(tp
, c
)
227 register tty_t
*tp
; /* pointer to tty struct */
228 int c
; /* character to be echoed */
230 /* Echo keyboard input (print & flush). */
231 console_t
*cons
= tp
->tty_priv
;
237 /*===========================================================================*
239 *===========================================================================*/
240 static void out_char(cons
, c
)
241 register console_t
*cons
; /* pointer to console struct */
242 int c
; /* character to be output */
244 /* Output a character on the console. Check for escape sequences first. */
245 if (cons
->c_esc_state
> 0) {
246 parse_escape(cons
, c
);
251 if (cons
== &cons_table
[0] && c
!= '\0')
260 case 000: /* null is typically used for padding */
261 return; /* better not do anything */
263 case 007: /* ring the bell */
264 flush(cons
); /* print any chars queued for output */
268 case '\b': /* backspace */
269 if (--cons
->c_column
< 0) {
270 if (--cons
->c_row
>= 0) cons
->c_column
+= scr_width
;
275 case '\n': /* line feed */
276 if ((cons
->c_tty
->tty_termios
.c_oflag
& (OPOST
|ONLCR
))
281 case 013: /* CTRL-K */
282 case 014: /* CTRL-L */
283 if (cons
->c_row
== scr_lines
-1) {
284 scroll_screen(cons
, SCROLL_UP
);
291 case '\r': /* carriage return */
297 cons
->c_column
= (cons
->c_column
+ TAB_SIZE
) & ~TAB_MASK
;
298 if (cons
->c_column
> scr_width
) {
299 cons
->c_column
-= scr_width
;
300 if (cons
->c_row
== scr_lines
-1) {
301 scroll_screen(cons
, SCROLL_UP
);
309 case 033: /* ESC - start of an escape sequence */
310 flush(cons
); /* print any chars queued for output */
311 cons
->c_esc_state
= 1; /* mark ESC as seen */
314 default: /* printable chars are stored in ramqueue */
315 if (cons
->c_column
>= scr_width
) {
316 if (!LINEWRAP
) return;
317 if (cons
->c_row
== scr_lines
-1) {
318 scroll_screen(cons
, SCROLL_UP
);
325 if (cons
->c_rwords
== buflen(cons
->c_ramqueue
)) flush(cons
);
326 cons
->c_ramqueue
[cons
->c_rwords
++] = cons
->c_attr
| (c
& BYTE
);
327 cons
->c_column
++; /* next column */
332 /*===========================================================================*
334 *===========================================================================*/
335 static void scroll_screen(cons
, dir
)
336 register console_t
*cons
; /* pointer to console struct */
337 int dir
; /* SCROLL_UP or SCROLL_DOWN */
339 unsigned new_line
, new_org
, chars
;
342 chars
= scr_size
- scr_width
; /* one screen minus one line */
344 /* Scrolling the screen is a real nuisance due to the various incompatible
345 * video cards. This driver supports software scrolling (Hercules?),
346 * hardware scrolling (mono and CGA cards) and hardware scrolling without
347 * wrapping (EGA cards). In the latter case we must make sure that
348 * c_start <= c_org && c_org + scr_size <= c_limit
349 * holds, because EGA doesn't wrap around the end of video memory.
351 if (dir
== SCROLL_UP
) {
352 /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
354 vid_vid_copy(cons
->c_start
+ scr_width
, cons
->c_start
, chars
);
356 if (!wrap
&& cons
->c_org
+ scr_size
+ scr_width
>= cons
->c_limit
) {
357 vid_vid_copy(cons
->c_org
+ scr_width
, cons
->c_start
, chars
);
358 UPDATE_ORIGIN(cons
, cons
->c_start
);
360 UPDATE_ORIGIN(cons
, (cons
->c_org
+ scr_width
) & vid_mask
);
362 new_line
= (cons
->c_org
+ chars
) & vid_mask
;
364 /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
366 vid_vid_copy(cons
->c_start
, cons
->c_start
+ scr_width
, chars
);
368 if (!wrap
&& cons
->c_org
< cons
->c_start
+ scr_width
) {
369 new_org
= cons
->c_limit
- scr_size
;
370 vid_vid_copy(cons
->c_org
, new_org
+ scr_width
, chars
);
371 UPDATE_ORIGIN(cons
, new_org
);
373 UPDATE_ORIGIN(cons
, (cons
->c_org
- scr_width
) & vid_mask
);
375 new_line
= cons
->c_org
;
377 /* Blank the new line at top or bottom. */
378 blank_color
= cons
->c_blank
;
379 mem_vid_copy(BLANK_MEM
, new_line
, scr_width
);
384 /*===========================================================================*
386 *===========================================================================*/
387 static void flush(cons
)
388 register console_t
*cons
; /* pointer to console struct */
390 /* Send characters buffered in 'ramqueue' to screen memory, check the new
391 * cursor position, compute the new hardware cursor position and set it.
394 tty_t
*tp
= cons
->c_tty
;
396 /* Have the characters in 'ramqueue' transferred to the screen. */
397 if (cons
->c_rwords
> 0) {
398 mem_vid_copy((vir_bytes
) cons
->c_ramqueue
, cons
->c_cur
, cons
->c_rwords
);
401 /* TTY likes to know the current column and if echoing messed up. */
402 tp
->tty_position
= cons
->c_column
;
403 tp
->tty_reprint
= TRUE
;
406 /* Check and update the cursor position. */
407 if (cons
->c_column
< 0) cons
->c_column
= 0;
408 if (cons
->c_column
> scr_width
) cons
->c_column
= scr_width
;
409 if (cons
->c_row
< 0) cons
->c_row
= 0;
410 if (cons
->c_row
>= scr_lines
) cons
->c_row
= scr_lines
- 1;
411 cur
= cons
->c_org
+ cons
->c_row
* scr_width
+ cons
->c_column
;
412 if (cur
!= cons
->c_cur
)
413 UPDATE_CURSOR(cons
, cur
);
416 /*===========================================================================*
418 *===========================================================================*/
419 static void parse_escape(cons
, c
)
420 register console_t
*cons
; /* pointer to console struct */
421 char c
; /* next character in escape sequence */
423 /* The following ANSI escape sequences are currently supported.
424 * If n and/or m are omitted, they default to 1.
425 * ESC [nA moves up n lines
426 * ESC [nB moves down n lines
427 * ESC [nC moves right n spaces
428 * ESC [nD moves left n spaces
429 * ESC [m;nH" moves cursor to (m,n)
430 * ESC [J clears screen from cursor
431 * ESC [K clears line from cursor
432 * ESC [nL inserts n lines ar cursor
433 * ESC [nM deletes n lines at cursor
434 * ESC [nP deletes n chars at cursor
435 * ESC [n@ inserts n chars at cursor
436 * ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
437 * ESC M scrolls the screen backwards if the cursor is on the top line
440 switch (cons
->c_esc_state
) {
441 case 1: /* ESC seen */
442 cons
->c_esc_intro
= '\0';
443 cons
->c_esc_parmp
= bufend(cons
->c_esc_parmv
);
445 *--cons
->c_esc_parmp
= 0;
446 } while (cons
->c_esc_parmp
> cons
->c_esc_parmv
);
448 case '[': /* Control Sequence Introducer */
449 cons
->c_esc_intro
= c
;
450 cons
->c_esc_state
= 2;
452 case 'M': /* Reverse Index */
456 cons
->c_esc_state
= 0;
460 case 2: /* ESC [ seen */
461 if (c
>= '0' && c
<= '9') {
462 if (cons
->c_esc_parmp
< bufend(cons
->c_esc_parmv
))
463 *cons
->c_esc_parmp
= *cons
->c_esc_parmp
* 10 + (c
-'0');
466 if (cons
->c_esc_parmp
< bufend(cons
->c_esc_parmv
))
475 /*===========================================================================*
477 *===========================================================================*/
478 static void do_escape(cons
, c
)
479 register console_t
*cons
; /* pointer to console struct */
480 char c
; /* next character in escape sequence */
483 unsigned src
, dst
, count
;
486 /* Some of these things hack on screen RAM, so it had better be up to date */
489 if (cons
->c_esc_intro
== '\0') {
490 /* Handle a sequence beginning with just ESC */
492 case 'M': /* Reverse Index */
493 if (cons
->c_row
== 0) {
494 scroll_screen(cons
, SCROLL_DOWN
);
504 if (cons
->c_esc_intro
== '[') {
505 /* Handle a sequence beginning with ESC [ and parameters */
506 value
= cons
->c_esc_parmv
[0];
508 case 'A': /* ESC [nA moves up n lines */
509 n
= (value
== 0 ? 1 : value
);
514 case 'B': /* ESC [nB moves down n lines */
515 n
= (value
== 0 ? 1 : value
);
520 case 'C': /* ESC [nC moves right n spaces */
521 n
= (value
== 0 ? 1 : value
);
526 case 'D': /* ESC [nD moves left n spaces */
527 n
= (value
== 0 ? 1 : value
);
532 case 'H': /* ESC [m;nH" moves cursor to (m,n) */
533 cons
->c_row
= cons
->c_esc_parmv
[0] - 1;
534 cons
->c_column
= cons
->c_esc_parmv
[1] - 1;
538 case 'J': /* ESC [sJ clears in display */
540 case 0: /* Clear from cursor to end of screen */
541 count
= scr_size
- (cons
->c_cur
- cons
->c_org
);
544 case 1: /* Clear from start of screen to cursor */
545 count
= cons
->c_cur
- cons
->c_org
;
548 case 2: /* Clear entire screen */
552 default: /* Do nothing */
556 blank_color
= cons
->c_blank
;
557 mem_vid_copy(BLANK_MEM
, dst
, count
);
560 case 'K': /* ESC [sK clears line from cursor */
562 case 0: /* Clear from cursor to end of line */
563 count
= scr_width
- cons
->c_column
;
566 case 1: /* Clear from beginning of line to cursor */
567 count
= cons
->c_column
;
568 dst
= cons
->c_cur
- cons
->c_column
;
570 case 2: /* Clear entire line */
572 dst
= cons
->c_cur
- cons
->c_column
;
574 default: /* Do nothing */
578 blank_color
= cons
->c_blank
;
579 mem_vid_copy(BLANK_MEM
, dst
, count
);
582 case 'L': /* ESC [nL inserts n lines at cursor */
585 if (n
> (scr_lines
- cons
->c_row
))
586 n
= scr_lines
- cons
->c_row
;
588 src
= cons
->c_org
+ cons
->c_row
* scr_width
;
589 dst
= src
+ n
* scr_width
;
590 count
= (scr_lines
- cons
->c_row
- n
) * scr_width
;
591 vid_vid_copy(src
, dst
, count
);
592 blank_color
= cons
->c_blank
;
593 mem_vid_copy(BLANK_MEM
, src
, n
* scr_width
);
596 case 'M': /* ESC [nM deletes n lines at cursor */
599 if (n
> (scr_lines
- cons
->c_row
))
600 n
= scr_lines
- cons
->c_row
;
602 dst
= cons
->c_org
+ cons
->c_row
* scr_width
;
603 src
= dst
+ n
* scr_width
;
604 count
= (scr_lines
- cons
->c_row
- n
) * scr_width
;
605 vid_vid_copy(src
, dst
, count
);
606 blank_color
= cons
->c_blank
;
607 mem_vid_copy(BLANK_MEM
, dst
+ count
, n
* scr_width
);
610 case '@': /* ESC [n@ inserts n chars at cursor */
613 if (n
> (scr_width
- cons
->c_column
))
614 n
= scr_width
- cons
->c_column
;
618 count
= scr_width
- cons
->c_column
- n
;
619 vid_vid_copy(src
, dst
, count
);
620 blank_color
= cons
->c_blank
;
621 mem_vid_copy(BLANK_MEM
, src
, n
);
624 case 'P': /* ESC [nP deletes n chars at cursor */
627 if (n
> (scr_width
- cons
->c_column
))
628 n
= scr_width
- cons
->c_column
;
632 count
= scr_width
- cons
->c_column
- n
;
633 vid_vid_copy(src
, dst
, count
);
634 blank_color
= cons
->c_blank
;
635 mem_vid_copy(BLANK_MEM
, dst
+ count
, n
);
638 case 'm': /* ESC [nm enables rendition n */
639 for (parmp
= cons
->c_esc_parmv
; parmp
<= cons
->c_esc_parmp
640 && parmp
< bufend(cons
->c_esc_parmv
); parmp
++) {
641 if (cons
->c_reverse
) {
642 /* Unswap fg and bg colors */
643 cons
->c_attr
= ((cons
->c_attr
& 0x7000) >> 4) |
644 ((cons
->c_attr
& 0x0700) << 4) |
645 ((cons
->c_attr
& 0x8800));
647 switch (n
= *parmp
) {
649 cons
->c_attr
= cons
->c_blank
= BLANK_COLOR
;
650 cons
->c_reverse
= FALSE
;
654 /* Set intensity bit */
655 cons
->c_attr
|= 0x0800;
658 case 4: /* UNDERLINE */
660 /* Change white to cyan, i.e. lose red
662 cons
->c_attr
= (cons
->c_attr
& 0xBBFF);
664 /* Set underline attribute */
665 cons
->c_attr
= (cons
->c_attr
& 0x99FF);
669 case 5: /* BLINKING */
670 /* Set the blink bit */
671 cons
->c_attr
|= 0x8000;
674 case 7: /* REVERSE */
675 cons
->c_reverse
= TRUE
;
679 if (n
== 39) n
= 37; /* set default color */
683 /* Don't mess up a monochrome screen */
685 if (30 <= n
&& n
<= 37) {
686 /* Foreground color */
688 (cons
->c_attr
& 0xF8FF) |
689 (ansi_colors
[(n
- 30)] << 8);
691 (cons
->c_blank
& 0xF8FF) |
692 (ansi_colors
[(n
- 30)] << 8);
694 if (40 <= n
&& n
<= 47) {
695 /* Background color */
697 (cons
->c_attr
& 0x8FFF) |
698 (ansi_colors
[(n
- 40)] << 12);
700 (cons
->c_blank
& 0x8FFF) |
701 (ansi_colors
[(n
- 40)] << 12);
704 if (cons
->c_reverse
) {
705 /* Swap fg and bg colors */
706 cons
->c_attr
= ((cons
->c_attr
& 0x7000) >> 4) |
707 ((cons
->c_attr
& 0x0700) << 4) |
708 ((cons
->c_attr
& 0x8800));
714 cons
->c_esc_state
= 0;
717 /*===========================================================================*
719 *===========================================================================*/
720 static void set_6845(reg
, val
)
721 int reg
; /* which register pair to set */
722 unsigned val
; /* 16-bit value to set it to */
724 /* Set a register pair inside the 6845.
725 * Registers 12-13 tell the 6845 where in video ram to start
726 * Registers 14-15 tell the 6845 where to put the cursor
728 pvb_pair_t char_out
[4];
729 pv_set(char_out
[0], vid_port
+ INDEX
, reg
); /* set index register */
730 pv_set(char_out
[1], vid_port
+ DATA
, (val
>>8) & BYTE
); /* high byte */
731 pv_set(char_out
[2], vid_port
+ INDEX
, reg
+ 1); /* again */
732 pv_set(char_out
[3], vid_port
+ DATA
, val
&BYTE
); /* low byte */
733 sys_voutb(char_out
, 4); /* do actual output */
737 /*===========================================================================*
739 *===========================================================================*/
740 static void get_6845(reg
, val
)
741 int reg
; /* which register pair to set */
742 unsigned *val
; /* 16-bit value to set it to */
746 /* Get a register pair inside the 6845. */
747 sys_outb(vid_port
+ INDEX
, reg
);
748 sys_inb(vid_port
+ DATA
, &v
);
750 sys_outb(vid_port
+ INDEX
, reg
+1);
751 sys_inb(vid_port
+ DATA
, &v
);
753 *val
= (v1
<< 8) | v2
;
757 /*===========================================================================*
759 *===========================================================================*/
762 /* Making a beeping sound on the speaker (output for CRTL-G).
763 * This routine works by turning on the bits 0 and 1 in port B of the 8255
764 * chip that drive the speaker.
766 static timer_t tmr_stop_beep
;
767 pvb_pair_t char_out
[3];
770 /* Set timer in advance to prevent beeping delay. */
771 set_timer(&tmr_stop_beep
, B_TIME
, stop_beep
, 0);
774 /* Set timer channel 2, square wave, with given frequency. */
775 pv_set(char_out
[0], TIMER_MODE
, 0xB6);
776 pv_set(char_out
[1], TIMER2
, (BEEP_FREQ
>> 0) & BYTE
);
777 pv_set(char_out
[2], TIMER2
, (BEEP_FREQ
>> 8) & BYTE
);
778 if (sys_voutb(char_out
, 3)==OK
) {
779 if (sys_inb(PORT_B
, &port_b_val
)==OK
&&
780 sys_outb(PORT_B
, (port_b_val
|3))==OK
)
787 /*===========================================================================*
789 *===========================================================================*/
790 void do_video(message
*m
)
794 /* Execute the requested device driver function. */
795 r
= EINVAL
; /* just in case */
798 /* Should grant IOPL */
807 switch(m
->TTY_REQUEST
) {
811 struct mapreqvm mapreqvm
;
813 do_map
= (m
->REQUEST
== TIOCMAPMEM
); /* else unmap */
815 r
= sys_safecopyfrom(m
->m_source
,
816 (cp_grant_id_t
) m
->IO_GRANT
, 0,
817 (vir_bytes
) &mapreqvm
, sizeof(mapreqvm
));
821 printf("tty: sys_safecopyfrom failed\n");
822 tty_reply(TASK_REPLY
, m
->m_source
,
827 /* In safe ioctl mode, the POSITION field contains
828 * the endpt number of the original requestor.
829 * USER_ENDPT is always FS.
833 mapreqvm
.vaddr_ret
= vm_map_phys(m
->POSITION
,
834 (void *) mapreqvm
.phys_offset
, mapreqvm
.size
);
835 if((r
= sys_safecopyto(m
->m_source
,
836 (cp_grant_id_t
) m
->IO_GRANT
, 0,
837 (vir_bytes
) &mapreqvm
,
838 sizeof(mapreqvm
))) != OK
) {
839 printf("tty: sys_safecopyto failed\n");
842 r
= vm_unmap_phys(m
->POSITION
,
843 mapreqvm
.vaddr
, mapreqvm
.size
);
845 tty_reply(TASK_REPLY
, m
->m_source
, m
->USER_ENDPT
, r
);
854 "Warning, TTY(video) got unexpected request %d from %d\n",
855 m
->m_type
, m
->m_source
);
858 tty_reply(TASK_REPLY
, m
->m_source
, m
->USER_ENDPT
, r
);
862 /*===========================================================================*
864 *===========================================================================*/
865 void beep_x(freq
, dur
)
869 /* Making a beeping sound on the speaker.
870 * This routine works by turning on the bits 0 and 1 in port B of the 8255
871 * chip that drive the speaker.
873 static timer_t tmr_stop_beep
;
874 pvb_pair_t char_out
[3];
877 unsigned long ival
= TIMER_FREQ
/ freq
;
878 if (ival
== 0 || ival
> 0xffff)
879 return; /* Frequency out of range */
881 /* Set timer in advance to prevent beeping delay. */
882 set_timer(&tmr_stop_beep
, dur
, stop_beep
, 0);
885 /* Set timer channel 2, square wave, with given frequency. */
886 pv_set(char_out
[0], TIMER_MODE
, 0xB6);
887 pv_set(char_out
[1], TIMER2
, (ival
>> 0) & BYTE
);
888 pv_set(char_out
[2], TIMER2
, (ival
>> 8) & BYTE
);
889 if (sys_voutb(char_out
, 3)==OK
) {
890 if (sys_inb(PORT_B
, &port_b_val
)==OK
&&
891 sys_outb(PORT_B
, (port_b_val
|3))==OK
)
897 /*===========================================================================*
899 *===========================================================================*/
900 static void stop_beep(timer_t
*UNUSED(tmrp
))
902 /* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
904 if (sys_inb(PORT_B
, &port_b_val
)==OK
&&
905 sys_outb(PORT_B
, (port_b_val
& ~3))==OK
)
909 /*===========================================================================*
911 *===========================================================================*/
915 /* Initialize the screen driver. */
917 u16_t bios_columns
, bios_crtbase
, bios_fontlines
;
921 static int vdu_initialized
= 0;
922 static unsigned page_size
;
924 /* Associate console and TTY. */
925 line
= tp
- &tty_table
[0];
926 if (line
>= nr_cons
) return;
927 cons
= &cons_table
[line
];
932 /* Fill in TTY function hooks. */
933 tp
->tty_devwrite
= cons_write
;
934 tp
->tty_echo
= cons_echo
;
935 tp
->tty_ioctl
= cons_ioctl
;
937 /* Get the BIOS parameters that describe the VDU. */
938 if (! vdu_initialized
++) {
940 /* FIXME: How about error checking? What to do on failure??? */
941 s
=sys_readbios(VDU_SCREEN_COLS_ADDR
, &bios_columns
,
942 VDU_SCREEN_COLS_SIZE
);
943 s
=sys_readbios(VDU_CRT_BASE_ADDR
, &bios_crtbase
,
945 s
=sys_readbios( VDU_SCREEN_ROWS_ADDR
, &bios_rows
,
946 VDU_SCREEN_ROWS_SIZE
);
947 s
=sys_readbios(VDU_FONTLINES_ADDR
, &bios_fontlines
,
950 vid_port
= bios_crtbase
;
951 scr_width
= bios_columns
;
952 font_lines
= bios_fontlines
;
953 scr_lines
= bios_rows
+1;
956 vid_base
= COLOR_BASE
;
957 vid_size
= COLOR_SIZE
;
959 vid_base
= MONO_BASE
;
960 vid_size
= MONO_SIZE
;
965 console_memory
= vm_map_phys(SELF
, (void *) vid_base
, vid_size
);
967 if(console_memory
== MAP_FAILED
)
968 panic("Console couldn't map video memory");
970 font_memory
= vm_map_phys(SELF
, (void *)GA_VIDEO_ADDRESS
, GA_FONT_SIZE
);
972 if(font_memory
== MAP_FAILED
)
973 panic("Console couldn't map font memory");
975 vid_size
>>= 1; /* word count */
976 vid_mask
= vid_size
- 1;
978 /* Size of the screen (number of displayed characters.) */
979 scr_size
= scr_lines
* scr_width
;
981 /* There can be as many consoles as video memory allows. */
982 nr_cons
= vid_size
/ scr_size
;
984 if (nr_cons
> NR_CONS
) nr_cons
= NR_CONS
;
985 if (nr_cons
> 1) wrap
= 0;
986 if (nr_cons
< 1) panic("no consoles");
987 page_size
= vid_size
/ nr_cons
;
990 cons
->c_start
= line
* page_size
;
991 cons
->c_limit
= cons
->c_start
+ page_size
;
992 cons
->c_cur
= cons
->c_org
= cons
->c_start
;
993 cons
->c_attr
= cons
->c_blank
= BLANK_COLOR
;
996 /* Clear the non-console vtys. */
997 blank_color
= BLANK_COLOR
;
998 mem_vid_copy(BLANK_MEM
, cons
->c_start
, scr_size
);
1000 /* Set the cursor of the console vty at the bottom. c_cur
1001 * is updated automatically later.
1003 scroll_screen(cons
, SCROLL_UP
);
1004 cons
->c_row
= scr_lines
- 1;
1011 extern struct minix_kerninfo
*_minix_kerninfo
;
1013 /*===========================================================================*
1015 *===========================================================================*/
1018 /* Notification for a new kernel message. */
1019 struct kmessages
*kmess_ptr
; /* kmessages structure */
1020 static int prev_next
= 0; /* previous next seen */
1024 assert(_minix_kerninfo
);
1025 kmess_ptr
= _minix_kerninfo
->kmessages
;
1027 /* Print only the new part. Determine how many new bytes there are with
1028 * help of the current and previous 'next' index. Note that the kernel
1029 * buffer is circular. This works fine if less then _KMESS_BUF_SIZE bytes
1030 * is new data; else we miss % _KMESS_BUF_SIZE here.
1031 * Check for size being positive, the buffer might as well be emptied!
1033 if (kmess_ptr
->km_size
> 0) {
1034 bytes
= ((kmess_ptr
->km_next
+ _KMESS_BUF_SIZE
) - prev_next
) % _KMESS_BUF_SIZE
;
1035 r
=prev_next
; /* start at previous old */
1037 cons_putk( kmess_ptr
->km_buf
[(r
%_KMESS_BUF_SIZE
)] );
1041 cons_putk(0); /* terminate to flush output */
1044 /* Almost done, store 'next' so that we can determine what part of the
1045 * kernel messages buffer to print next time a notification arrives.
1047 prev_next
= kmess_ptr
->km_next
;
1050 /*===========================================================================*
1052 *===========================================================================*/
1053 static void cons_putk(c
)
1054 int c
; /* character to print */
1056 /* This procedure is used to print a character on the console.
1059 if (c
== '\n') cons_putk('\r');
1060 out_char(&cons_table
[0], (int) c
);
1065 flush(&cons_table
[0]);
1069 /*===========================================================================*
1071 *===========================================================================*/
1072 void toggle_scroll()
1074 /* Toggle between hardware and software scroll. */
1077 softscroll
= !softscroll
;
1078 printf("%sware scrolling enabled.\n", softscroll
? "Soft" : "Hard");
1081 /*===========================================================================*
1083 *===========================================================================*/
1086 /* Prepare for halt or reboot. */
1090 cons_table
[0].c_attr
= cons_table
[0].c_blank
= BLANK_COLOR
;
1091 shutting_down
= TRUE
;
1094 /*===========================================================================*
1096 *===========================================================================*/
1097 static void cons_org0()
1099 /* Scroll video memory back to put the origin at 0. */
1104 for (cons_line
= 0; cons_line
< nr_cons
; cons_line
++) {
1105 cons
= &cons_table
[cons_line
];
1106 while (cons
->c_org
> cons
->c_start
) {
1107 n
= vid_size
- scr_size
; /* amount of unused memory */
1108 if (n
> cons
->c_org
- cons
->c_start
)
1109 n
= cons
->c_org
- cons
->c_start
;
1110 vid_vid_copy(cons
->c_org
, cons
->c_org
- n
, scr_size
);
1111 UPDATE_ORIGIN(cons
, cons
->c_org
- n
);
1115 select_console(ccurrent
);
1118 /*===========================================================================*
1120 *===========================================================================*/
1121 static void disable_console()
1123 if (disabled_vc
!= -1)
1126 disabled_vc
= ccurrent
;
1127 disabled_sm
= softscroll
;
1133 /* Should also disable further output to virtual consoles */
1136 /*===========================================================================*
1137 * reenable_console *
1138 *===========================================================================*/
1139 static void reenable_console()
1141 if (disabled_vc
== -1)
1144 softscroll
= disabled_sm
;
1145 select_console(disabled_vc
);
1149 /*===========================================================================*
1151 *===========================================================================*/
1152 void select_console(int cons_line
)
1154 /* Set the current console to console number 'cons_line'. */
1156 if (shutting_down
) return;
1158 if (cons_line
< 0 || cons_line
>= nr_cons
) return;
1160 ccurrent
= cons_line
;
1161 curcons
= &cons_table
[cons_line
];
1163 UPDATE_CURSOR(curcons
, curcons
->c_cur
);
1164 UPDATE_ORIGIN(curcons
, curcons
->c_org
);
1167 /*===========================================================================*
1169 *===========================================================================*/
1174 /* Load a font into the EGA or VGA adapter. */
1176 static struct sequence seq1
[7] = {
1177 { GA_SEQUENCER_INDEX
, 0x00, 0x01 },
1178 { GA_SEQUENCER_INDEX
, 0x02, 0x04 },
1179 { GA_SEQUENCER_INDEX
, 0x04, 0x07 },
1180 { GA_SEQUENCER_INDEX
, 0x00, 0x03 },
1181 { GA_GRAPHICS_INDEX
, 0x04, 0x02 },
1182 { GA_GRAPHICS_INDEX
, 0x05, 0x00 },
1183 { GA_GRAPHICS_INDEX
, 0x06, 0x00 },
1185 static struct sequence seq2
[7] = {
1186 { GA_SEQUENCER_INDEX
, 0x00, 0x01 },
1187 { GA_SEQUENCER_INDEX
, 0x02, 0x03 },
1188 { GA_SEQUENCER_INDEX
, 0x04, 0x03 },
1189 { GA_SEQUENCER_INDEX
, 0x00, 0x03 },
1190 { GA_GRAPHICS_INDEX
, 0x04, 0x00 },
1191 { GA_GRAPHICS_INDEX
, 0x05, 0x10 },
1192 { GA_GRAPHICS_INDEX
, 0x06, 0 },
1195 seq2
[6].value
= color
? 0x0E : 0x0A;
1197 result
= ga_program(seq1
); /* bring font memory into view */
1199 if(sys_safecopyfrom(m
->m_source
, (cp_grant_id_t
) m
->IO_GRANT
, 0,
1200 (vir_bytes
) font_memory
, GA_FONT_SIZE
) != OK
) {
1201 printf("tty: copying from %d failed\n", m
->m_source
);
1205 result
= ga_program(seq2
); /* restore */
1210 /*===========================================================================*
1212 *===========================================================================*/
1213 static int ga_program(seq
)
1214 struct sequence
*seq
;
1216 pvb_pair_t char_out
[14];
1218 for (i
=0; i
<7; i
++) {
1219 pv_set(char_out
[2*i
], seq
->index
, seq
->port
);
1220 pv_set(char_out
[2*i
+1], seq
->index
+1, seq
->value
);
1223 return sys_voutb(char_out
, 14);
1226 /*===========================================================================*
1228 *===========================================================================*/
1229 static int cons_ioctl(tty_t
*tp
, int UNUSED(try))
1231 /* Set the screen dimensions. */
1233 tp
->tty_winsize
.ws_row
= scr_lines
;
1234 tp
->tty_winsize
.ws_col
= scr_width
;
1235 tp
->tty_winsize
.ws_xpixel
= scr_width
* 8;
1236 tp
->tty_winsize
.ws_ypixel
= scr_lines
* font_lines
;
1241 #define LIMITINDEX(mask, start, size, ct) { \
1242 int countlimit = size - start; \
1244 if(ct > countlimit) ct = countlimit; \
1247 /*===========================================================================*
1249 *===========================================================================*/
1250 static void mem_vid_copy(vir_bytes src
, int dst_index
, int count
)
1252 u16_t
*src_mem
= (u16_t
*) src
;
1254 int i
, subcount
= count
;
1256 LIMITINDEX(vid_mask
, dst_index
, vid_size
, subcount
);
1257 dst_mem
= (u16_t
*) console_memory
+ dst_index
;
1259 for(i
= 0; i
< subcount
; i
++)
1260 *dst_mem
++ = blank_color
;
1262 for(i
= 0; i
< subcount
; i
++)
1263 *dst_mem
++ = *src_mem
++;
1265 dst_index
+= subcount
;
1269 /*===========================================================================*
1271 *===========================================================================*/
1272 static void vid_vid_copy(int src_index
, int dst_index
, int count
)
1275 if(src_index
< dst_index
)
1278 int i
, subcount
= count
;
1279 u16_t
*dst_mem
, *src_mem
;
1280 LIMITINDEX(vid_mask
, src_index
, vid_size
, subcount
);
1281 LIMITINDEX(vid_mask
, dst_index
, vid_size
, subcount
);
1282 src_mem
= (u16_t
*) console_memory
+ src_index
;
1283 dst_mem
= (u16_t
*) console_memory
+ dst_index
;
1285 src_mem
+= subcount
- 1;
1286 dst_mem
+= subcount
- 1;
1287 for(i
= 0; i
< subcount
; i
++)
1288 *dst_mem
-- = *src_mem
--;
1290 for(i
= 0; i
< subcount
; i
++)
1291 *dst_mem
++ = *src_mem
++;
1294 dst_index
+= subcount
;
1295 src_index
+= subcount
;