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 beep(void);
126 static void do_escape(console_t
*cons
, int c
);
127 static void flush(console_t
*cons
);
128 static void parse_escape(console_t
*cons
, int c
);
129 static void scroll_screen(console_t
*cons
, int dir
);
130 static void set_6845(int reg
, unsigned val
);
131 static void stop_beep(timer_t
*tmrp
);
132 static void cons_org0(void);
133 static void disable_console(void);
134 static void reenable_console(void);
135 static int ga_program(struct sequence
*seq
);
136 static int cons_ioctl(tty_t
*tp
, int);
137 static void mem_vid_copy(vir_bytes src
, int dst
, int count
);
138 static void vid_vid_copy(int src
, int dst
, int count
);
141 static void get_6845(int reg
, unsigned *val
);
144 /*===========================================================================*
146 *===========================================================================*/
147 static 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_outcaller
== KERNEL
) {
175 /* We're trying to print on kernel's behalf */
176 memcpy(buf
, (void *) tp
->tty_outgrant
+ tp
->tty_outoffset
,
179 if ((result
= sys_safecopyfrom(tp
->tty_outcaller
,
180 tp
->tty_outgrant
, tp
->tty_outoffset
,
181 (vir_bytes
) buf
, count
)) != OK
) {
185 tp
->tty_outoffset
+= count
;
188 /* Update terminal data structure. */
189 tp
->tty_outcum
+= count
;
190 tp
->tty_outleft
-= count
;
192 /* Output each byte of the copy to the screen. Avoid calling
193 * out_char() for the "easy" characters, put them into the buffer
197 if ((unsigned) *tbuf
< ' ' || cons
->c_esc_state
> 0
198 || cons
->c_column
>= scr_width
199 || cons
->c_rwords
>= buflen(cons
->c_ramqueue
))
201 out_char(cons
, *tbuf
++);
204 if (cons
== &cons_table
[0]) ser_putc(*tbuf
);
206 cons
->c_ramqueue
[cons
->c_rwords
++] =
207 cons
->c_attr
| (*tbuf
++ & BYTE
);
210 } while (--count
!= 0);
211 } while ((count
= tp
->tty_outleft
) != 0 && !tp
->tty_inhibited
);
213 flush(cons
); /* transfer anything buffered to the screen */
215 /* Reply to the writer if all output is finished or if an error occured. */
216 if (tp
->tty_outleft
== 0 || result
!= OK
) {
217 if(tp
->tty_outrepcode
== TTY_REVIVE
) {
218 notify(tp
->tty_outcaller
);
219 tp
->tty_outrevived
= 1;
221 tty_reply(tp
->tty_outrepcode
, tp
->tty_outcaller
,
222 tp
->tty_outproc
, tp
->tty_outcum
);
230 /*===========================================================================*
232 *===========================================================================*/
233 static void cons_echo(tp
, c
)
234 register tty_t
*tp
; /* pointer to tty struct */
235 int c
; /* character to be echoed */
237 /* Echo keyboard input (print & flush). */
238 console_t
*cons
= tp
->tty_priv
;
244 /*===========================================================================*
246 *===========================================================================*/
247 static void out_char(cons
, c
)
248 register console_t
*cons
; /* pointer to console struct */
249 int c
; /* character to be output */
251 /* Output a character on the console. Check for escape sequences first. */
252 if (cons
->c_esc_state
> 0) {
253 parse_escape(cons
, c
);
258 if (cons
== &cons_table
[0] && c
!= '\0')
267 case 000: /* null is typically used for padding */
268 return; /* better not do anything */
270 case 007: /* ring the bell */
271 flush(cons
); /* print any chars queued for output */
275 case '\b': /* backspace */
276 if (--cons
->c_column
< 0) {
277 if (--cons
->c_row
>= 0) cons
->c_column
+= scr_width
;
282 case '\n': /* line feed */
283 if ((cons
->c_tty
->tty_termios
.c_oflag
& (OPOST
|ONLCR
))
288 case 013: /* CTRL-K */
289 case 014: /* CTRL-L */
290 if (cons
->c_row
== scr_lines
-1) {
291 scroll_screen(cons
, SCROLL_UP
);
298 case '\r': /* carriage return */
304 cons
->c_column
= (cons
->c_column
+ TAB_SIZE
) & ~TAB_MASK
;
305 if (cons
->c_column
> scr_width
) {
306 cons
->c_column
-= scr_width
;
307 if (cons
->c_row
== scr_lines
-1) {
308 scroll_screen(cons
, SCROLL_UP
);
316 case 033: /* ESC - start of an escape sequence */
317 flush(cons
); /* print any chars queued for output */
318 cons
->c_esc_state
= 1; /* mark ESC as seen */
321 default: /* printable chars are stored in ramqueue */
322 if (cons
->c_column
>= scr_width
) {
323 if (!LINEWRAP
) return;
324 if (cons
->c_row
== scr_lines
-1) {
325 scroll_screen(cons
, SCROLL_UP
);
332 if (cons
->c_rwords
== buflen(cons
->c_ramqueue
)) flush(cons
);
333 cons
->c_ramqueue
[cons
->c_rwords
++] = cons
->c_attr
| (c
& BYTE
);
334 cons
->c_column
++; /* next column */
339 /*===========================================================================*
341 *===========================================================================*/
342 static void scroll_screen(cons
, dir
)
343 register console_t
*cons
; /* pointer to console struct */
344 int dir
; /* SCROLL_UP or SCROLL_DOWN */
346 unsigned new_line
, new_org
, chars
;
349 chars
= scr_size
- scr_width
; /* one screen minus one line */
351 /* Scrolling the screen is a real nuisance due to the various incompatible
352 * video cards. This driver supports software scrolling (Hercules?),
353 * hardware scrolling (mono and CGA cards) and hardware scrolling without
354 * wrapping (EGA cards). In the latter case we must make sure that
355 * c_start <= c_org && c_org + scr_size <= c_limit
356 * holds, because EGA doesn't wrap around the end of video memory.
358 if (dir
== SCROLL_UP
) {
359 /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
361 vid_vid_copy(cons
->c_start
+ scr_width
, cons
->c_start
, chars
);
363 if (!wrap
&& cons
->c_org
+ scr_size
+ scr_width
>= cons
->c_limit
) {
364 vid_vid_copy(cons
->c_org
+ scr_width
, cons
->c_start
, chars
);
365 UPDATE_ORIGIN(cons
, cons
->c_start
);
367 UPDATE_ORIGIN(cons
, (cons
->c_org
+ scr_width
) & vid_mask
);
369 new_line
= (cons
->c_org
+ chars
) & vid_mask
;
371 /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
373 vid_vid_copy(cons
->c_start
, cons
->c_start
+ scr_width
, chars
);
375 if (!wrap
&& cons
->c_org
< cons
->c_start
+ scr_width
) {
376 new_org
= cons
->c_limit
- scr_size
;
377 vid_vid_copy(cons
->c_org
, new_org
+ scr_width
, chars
);
378 UPDATE_ORIGIN(cons
, new_org
);
380 UPDATE_ORIGIN(cons
, (cons
->c_org
- scr_width
) & vid_mask
);
382 new_line
= cons
->c_org
;
384 /* Blank the new line at top or bottom. */
385 blank_color
= cons
->c_blank
;
386 mem_vid_copy(BLANK_MEM
, new_line
, scr_width
);
391 /*===========================================================================*
393 *===========================================================================*/
394 static void flush(cons
)
395 register console_t
*cons
; /* pointer to console struct */
397 /* Send characters buffered in 'ramqueue' to screen memory, check the new
398 * cursor position, compute the new hardware cursor position and set it.
401 tty_t
*tp
= cons
->c_tty
;
403 /* Have the characters in 'ramqueue' transferred to the screen. */
404 if (cons
->c_rwords
> 0) {
405 mem_vid_copy((vir_bytes
) cons
->c_ramqueue
, cons
->c_cur
, cons
->c_rwords
);
408 /* TTY likes to know the current column and if echoing messed up. */
409 tp
->tty_position
= cons
->c_column
;
410 tp
->tty_reprint
= TRUE
;
413 /* Check and update the cursor position. */
414 if (cons
->c_column
< 0) cons
->c_column
= 0;
415 if (cons
->c_column
> scr_width
) cons
->c_column
= scr_width
;
416 if (cons
->c_row
< 0) cons
->c_row
= 0;
417 if (cons
->c_row
>= scr_lines
) cons
->c_row
= scr_lines
- 1;
418 cur
= cons
->c_org
+ cons
->c_row
* scr_width
+ cons
->c_column
;
419 if (cur
!= cons
->c_cur
)
420 UPDATE_CURSOR(cons
, cur
);
423 /*===========================================================================*
425 *===========================================================================*/
426 static void parse_escape(cons
, c
)
427 register console_t
*cons
; /* pointer to console struct */
428 char c
; /* next character in escape sequence */
430 /* The following ANSI escape sequences are currently supported.
431 * If n and/or m are omitted, they default to 1.
432 * ESC [nA moves up n lines
433 * ESC [nB moves down n lines
434 * ESC [nC moves right n spaces
435 * ESC [nD moves left n spaces
436 * ESC [m;nH" moves cursor to (m,n)
437 * ESC [J clears screen from cursor
438 * ESC [K clears line from cursor
439 * ESC [nL inserts n lines ar cursor
440 * ESC [nM deletes n lines at cursor
441 * ESC [nP deletes n chars at cursor
442 * ESC [n@ inserts n chars at cursor
443 * ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
444 * ESC M scrolls the screen backwards if the cursor is on the top line
447 switch (cons
->c_esc_state
) {
448 case 1: /* ESC seen */
449 cons
->c_esc_intro
= '\0';
450 cons
->c_esc_parmp
= bufend(cons
->c_esc_parmv
);
452 *--cons
->c_esc_parmp
= 0;
453 } while (cons
->c_esc_parmp
> cons
->c_esc_parmv
);
455 case '[': /* Control Sequence Introducer */
456 cons
->c_esc_intro
= c
;
457 cons
->c_esc_state
= 2;
459 case 'M': /* Reverse Index */
463 cons
->c_esc_state
= 0;
467 case 2: /* ESC [ seen */
468 if (c
>= '0' && c
<= '9') {
469 if (cons
->c_esc_parmp
< bufend(cons
->c_esc_parmv
))
470 *cons
->c_esc_parmp
= *cons
->c_esc_parmp
* 10 + (c
-'0');
473 if (cons
->c_esc_parmp
< bufend(cons
->c_esc_parmv
))
482 /*===========================================================================*
484 *===========================================================================*/
485 static void do_escape(cons
, c
)
486 register console_t
*cons
; /* pointer to console struct */
487 char c
; /* next character in escape sequence */
490 unsigned src
, dst
, count
;
493 /* Some of these things hack on screen RAM, so it had better be up to date */
496 if (cons
->c_esc_intro
== '\0') {
497 /* Handle a sequence beginning with just ESC */
499 case 'M': /* Reverse Index */
500 if (cons
->c_row
== 0) {
501 scroll_screen(cons
, SCROLL_DOWN
);
511 if (cons
->c_esc_intro
== '[') {
512 /* Handle a sequence beginning with ESC [ and parameters */
513 value
= cons
->c_esc_parmv
[0];
515 case 'A': /* ESC [nA moves up n lines */
516 n
= (value
== 0 ? 1 : value
);
521 case 'B': /* ESC [nB moves down n lines */
522 n
= (value
== 0 ? 1 : value
);
527 case 'C': /* ESC [nC moves right n spaces */
528 n
= (value
== 0 ? 1 : value
);
533 case 'D': /* ESC [nD moves left n spaces */
534 n
= (value
== 0 ? 1 : value
);
539 case 'H': /* ESC [m;nH" moves cursor to (m,n) */
540 cons
->c_row
= cons
->c_esc_parmv
[0] - 1;
541 cons
->c_column
= cons
->c_esc_parmv
[1] - 1;
545 case 'J': /* ESC [sJ clears in display */
547 case 0: /* Clear from cursor to end of screen */
548 count
= scr_size
- (cons
->c_cur
- cons
->c_org
);
551 case 1: /* Clear from start of screen to cursor */
552 count
= cons
->c_cur
- cons
->c_org
;
555 case 2: /* Clear entire screen */
559 default: /* Do nothing */
563 blank_color
= cons
->c_blank
;
564 mem_vid_copy(BLANK_MEM
, dst
, count
);
567 case 'K': /* ESC [sK clears line from cursor */
569 case 0: /* Clear from cursor to end of line */
570 count
= scr_width
- cons
->c_column
;
573 case 1: /* Clear from beginning of line to cursor */
574 count
= cons
->c_column
;
575 dst
= cons
->c_cur
- cons
->c_column
;
577 case 2: /* Clear entire line */
579 dst
= cons
->c_cur
- cons
->c_column
;
581 default: /* Do nothing */
585 blank_color
= cons
->c_blank
;
586 mem_vid_copy(BLANK_MEM
, dst
, count
);
589 case 'L': /* ESC [nL inserts n lines at cursor */
592 if (n
> (scr_lines
- cons
->c_row
))
593 n
= scr_lines
- cons
->c_row
;
595 src
= cons
->c_org
+ cons
->c_row
* scr_width
;
596 dst
= src
+ n
* scr_width
;
597 count
= (scr_lines
- cons
->c_row
- n
) * scr_width
;
598 vid_vid_copy(src
, dst
, count
);
599 blank_color
= cons
->c_blank
;
600 mem_vid_copy(BLANK_MEM
, src
, n
* scr_width
);
603 case 'M': /* ESC [nM deletes n lines at cursor */
606 if (n
> (scr_lines
- cons
->c_row
))
607 n
= scr_lines
- cons
->c_row
;
609 dst
= cons
->c_org
+ cons
->c_row
* scr_width
;
610 src
= dst
+ n
* scr_width
;
611 count
= (scr_lines
- cons
->c_row
- n
) * scr_width
;
612 vid_vid_copy(src
, dst
, count
);
613 blank_color
= cons
->c_blank
;
614 mem_vid_copy(BLANK_MEM
, dst
+ count
, n
* scr_width
);
617 case '@': /* ESC [n@ inserts n chars at cursor */
620 if (n
> (scr_width
- cons
->c_column
))
621 n
= scr_width
- cons
->c_column
;
625 count
= scr_width
- cons
->c_column
- n
;
626 vid_vid_copy(src
, dst
, count
);
627 blank_color
= cons
->c_blank
;
628 mem_vid_copy(BLANK_MEM
, src
, n
);
631 case 'P': /* ESC [nP deletes n chars at cursor */
634 if (n
> (scr_width
- cons
->c_column
))
635 n
= scr_width
- cons
->c_column
;
639 count
= scr_width
- cons
->c_column
- n
;
640 vid_vid_copy(src
, dst
, count
);
641 blank_color
= cons
->c_blank
;
642 mem_vid_copy(BLANK_MEM
, dst
+ count
, n
);
645 case 'm': /* ESC [nm enables rendition n */
646 for (parmp
= cons
->c_esc_parmv
; parmp
<= cons
->c_esc_parmp
647 && parmp
< bufend(cons
->c_esc_parmv
); parmp
++) {
648 if (cons
->c_reverse
) {
649 /* Unswap fg and bg colors */
650 cons
->c_attr
= ((cons
->c_attr
& 0x7000) >> 4) |
651 ((cons
->c_attr
& 0x0700) << 4) |
652 ((cons
->c_attr
& 0x8800));
654 switch (n
= *parmp
) {
656 cons
->c_attr
= cons
->c_blank
= BLANK_COLOR
;
657 cons
->c_reverse
= FALSE
;
661 /* Set intensity bit */
662 cons
->c_attr
|= 0x0800;
665 case 4: /* UNDERLINE */
667 /* Change white to cyan, i.e. lose red
669 cons
->c_attr
= (cons
->c_attr
& 0xBBFF);
671 /* Set underline attribute */
672 cons
->c_attr
= (cons
->c_attr
& 0x99FF);
676 case 5: /* BLINKING */
677 /* Set the blink bit */
678 cons
->c_attr
|= 0x8000;
681 case 7: /* REVERSE */
682 cons
->c_reverse
= TRUE
;
686 if (n
== 39) n
= 37; /* set default color */
690 /* Don't mess up a monochrome screen */
692 if (30 <= n
&& n
<= 37) {
693 /* Foreground color */
695 (cons
->c_attr
& 0xF8FF) |
696 (ansi_colors
[(n
- 30)] << 8);
698 (cons
->c_blank
& 0xF8FF) |
699 (ansi_colors
[(n
- 30)] << 8);
701 if (40 <= n
&& n
<= 47) {
702 /* Background color */
704 (cons
->c_attr
& 0x8FFF) |
705 (ansi_colors
[(n
- 40)] << 12);
707 (cons
->c_blank
& 0x8FFF) |
708 (ansi_colors
[(n
- 40)] << 12);
711 if (cons
->c_reverse
) {
712 /* Swap fg and bg colors */
713 cons
->c_attr
= ((cons
->c_attr
& 0x7000) >> 4) |
714 ((cons
->c_attr
& 0x0700) << 4) |
715 ((cons
->c_attr
& 0x8800));
721 cons
->c_esc_state
= 0;
724 /*===========================================================================*
726 *===========================================================================*/
727 static void set_6845(reg
, val
)
728 int reg
; /* which register pair to set */
729 unsigned val
; /* 16-bit value to set it to */
731 /* Set a register pair inside the 6845.
732 * Registers 12-13 tell the 6845 where in video ram to start
733 * Registers 14-15 tell the 6845 where to put the cursor
735 pvb_pair_t char_out
[4];
736 pv_set(char_out
[0], vid_port
+ INDEX
, reg
); /* set index register */
737 pv_set(char_out
[1], vid_port
+ DATA
, (val
>>8) & BYTE
); /* high byte */
738 pv_set(char_out
[2], vid_port
+ INDEX
, reg
+ 1); /* again */
739 pv_set(char_out
[3], vid_port
+ DATA
, val
&BYTE
); /* low byte */
740 sys_voutb(char_out
, 4); /* do actual output */
744 /*===========================================================================*
746 *===========================================================================*/
747 static void get_6845(reg
, val
)
748 int reg
; /* which register pair to set */
749 unsigned *val
; /* 16-bit value to set it to */
753 /* Get a register pair inside the 6845. */
754 sys_outb(vid_port
+ INDEX
, reg
);
755 sys_inb(vid_port
+ DATA
, &v
);
757 sys_outb(vid_port
+ INDEX
, reg
+1);
758 sys_inb(vid_port
+ DATA
, &v
);
760 *val
= (v1
<< 8) | v2
;
764 /*===========================================================================*
766 *===========================================================================*/
769 /* Making a beeping sound on the speaker (output for CRTL-G).
770 * This routine works by turning on the bits 0 and 1 in port B of the 8255
771 * chip that drive the speaker.
773 static timer_t tmr_stop_beep
;
774 pvb_pair_t char_out
[3];
777 /* Set timer in advance to prevent beeping delay. */
778 set_timer(&tmr_stop_beep
, B_TIME
, stop_beep
, 0);
781 /* Set timer channel 2, square wave, with given frequency. */
782 pv_set(char_out
[0], TIMER_MODE
, 0xB6);
783 pv_set(char_out
[1], TIMER2
, (BEEP_FREQ
>> 0) & BYTE
);
784 pv_set(char_out
[2], TIMER2
, (BEEP_FREQ
>> 8) & BYTE
);
785 if (sys_voutb(char_out
, 3)==OK
) {
786 if (sys_inb(PORT_B
, &port_b_val
)==OK
&&
787 sys_outb(PORT_B
, (port_b_val
|3))==OK
)
794 /*===========================================================================*
796 *===========================================================================*/
797 void do_video(message
*m
)
801 /* Execute the requested device driver function. */
802 r
= EINVAL
; /* just in case */
805 /* Should grant IOPL */
814 switch(m
->TTY_REQUEST
) {
818 struct mapreqvm mapreqvm
;
820 do_map
= (m
->REQUEST
== TIOCMAPMEM
); /* else unmap */
822 r
= sys_safecopyfrom(m
->m_source
,
823 (cp_grant_id_t
) m
->IO_GRANT
, 0,
824 (vir_bytes
) &mapreqvm
, sizeof(mapreqvm
));
828 printf("tty: sys_safecopyfrom failed\n");
829 tty_reply(TASK_REPLY
, m
->m_source
,
834 /* In safe ioctl mode, the POSITION field contains
835 * the endpt number of the original requestor.
836 * USER_ENDPT is always FS.
840 mapreqvm
.vaddr_ret
= vm_map_phys(m
->POSITION
,
841 (void *) mapreqvm
.phys_offset
, mapreqvm
.size
);
842 if((r
= sys_safecopyto(m
->m_source
,
843 (cp_grant_id_t
) m
->IO_GRANT
, 0,
844 (vir_bytes
) &mapreqvm
,
845 sizeof(mapreqvm
))) != OK
) {
846 printf("tty: sys_safecopyto failed\n");
849 r
= vm_unmap_phys(m
->POSITION
,
850 mapreqvm
.vaddr
, mapreqvm
.size
);
852 tty_reply(TASK_REPLY
, m
->m_source
, m
->USER_ENDPT
, r
);
861 "Warning, TTY(video) got unexpected request %d from %d\n",
862 m
->m_type
, m
->m_source
);
865 tty_reply(TASK_REPLY
, m
->m_source
, m
->USER_ENDPT
, r
);
869 /*===========================================================================*
871 *===========================================================================*/
872 void beep_x(freq
, dur
)
876 /* Making a beeping sound on the speaker.
877 * This routine works by turning on the bits 0 and 1 in port B of the 8255
878 * chip that drive the speaker.
880 static timer_t tmr_stop_beep
;
881 pvb_pair_t char_out
[3];
884 unsigned long ival
= TIMER_FREQ
/ freq
;
885 if (ival
== 0 || ival
> 0xffff)
886 return; /* Frequency out of range */
888 /* Set timer in advance to prevent beeping delay. */
889 set_timer(&tmr_stop_beep
, dur
, stop_beep
, 0);
892 /* Set timer channel 2, square wave, with given frequency. */
893 pv_set(char_out
[0], TIMER_MODE
, 0xB6);
894 pv_set(char_out
[1], TIMER2
, (ival
>> 0) & BYTE
);
895 pv_set(char_out
[2], TIMER2
, (ival
>> 8) & BYTE
);
896 if (sys_voutb(char_out
, 3)==OK
) {
897 if (sys_inb(PORT_B
, &port_b_val
)==OK
&&
898 sys_outb(PORT_B
, (port_b_val
|3))==OK
)
904 /*===========================================================================*
906 *===========================================================================*/
907 static void stop_beep(timer_t
*UNUSED(tmrp
))
909 /* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
911 if (sys_inb(PORT_B
, &port_b_val
)==OK
&&
912 sys_outb(PORT_B
, (port_b_val
& ~3))==OK
)
916 /*===========================================================================*
918 *===========================================================================*/
922 /* Initialize the screen driver. */
924 u16_t bios_columns
, bios_crtbase
, bios_fontlines
;
928 static int vdu_initialized
= 0;
929 static unsigned page_size
;
931 /* Associate console and TTY. */
932 line
= tp
- &tty_table
[0];
933 if (line
>= nr_cons
) return;
934 cons
= &cons_table
[line
];
939 /* Fill in TTY function hooks. */
940 tp
->tty_devwrite
= cons_write
;
941 tp
->tty_echo
= cons_echo
;
942 tp
->tty_ioctl
= cons_ioctl
;
944 /* Get the BIOS parameters that describe the VDU. */
945 if (! vdu_initialized
++) {
947 /* FIXME: How about error checking? What to do on failure??? */
948 s
=sys_readbios(VDU_SCREEN_COLS_ADDR
, &bios_columns
,
949 VDU_SCREEN_COLS_SIZE
);
950 s
=sys_readbios(VDU_CRT_BASE_ADDR
, &bios_crtbase
,
952 s
=sys_readbios( VDU_SCREEN_ROWS_ADDR
, &bios_rows
,
953 VDU_SCREEN_ROWS_SIZE
);
954 s
=sys_readbios(VDU_FONTLINES_ADDR
, &bios_fontlines
,
957 vid_port
= bios_crtbase
;
958 scr_width
= bios_columns
;
959 font_lines
= bios_fontlines
;
960 scr_lines
= bios_rows
+1;
963 vid_base
= COLOR_BASE
;
964 vid_size
= COLOR_SIZE
;
966 vid_base
= MONO_BASE
;
967 vid_size
= MONO_SIZE
;
972 console_memory
= vm_map_phys(SELF
, (void *) vid_base
, vid_size
);
974 if(console_memory
== MAP_FAILED
)
975 panic("Console couldn't map video memory");
977 font_memory
= vm_map_phys(SELF
, (void *)GA_VIDEO_ADDRESS
, GA_FONT_SIZE
);
979 if(font_memory
== MAP_FAILED
)
980 panic("Console couldn't map font memory");
982 vid_size
>>= 1; /* word count */
983 vid_mask
= vid_size
- 1;
985 /* Size of the screen (number of displayed characters.) */
986 scr_size
= scr_lines
* scr_width
;
988 /* There can be as many consoles as video memory allows. */
989 nr_cons
= vid_size
/ scr_size
;
991 if (nr_cons
> NR_CONS
) nr_cons
= NR_CONS
;
992 if (nr_cons
> 1) wrap
= 0;
993 if (nr_cons
< 1) panic("no consoles");
994 page_size
= vid_size
/ nr_cons
;
997 cons
->c_start
= line
* page_size
;
998 cons
->c_limit
= cons
->c_start
+ page_size
;
999 cons
->c_cur
= cons
->c_org
= cons
->c_start
;
1000 cons
->c_attr
= cons
->c_blank
= BLANK_COLOR
;
1003 /* Clear the non-console vtys. */
1004 blank_color
= BLANK_COLOR
;
1005 mem_vid_copy(BLANK_MEM
, cons
->c_start
, scr_size
);
1007 /* Set the cursor of the console vty at the bottom. c_cur
1008 * is updated automatically later.
1010 scroll_screen(cons
, SCROLL_UP
);
1011 cons
->c_row
= scr_lines
- 1;
1018 /*===========================================================================*
1020 *===========================================================================*/
1021 void toggle_scroll()
1023 /* Toggle between hardware and software scroll. */
1026 softscroll
= !softscroll
;
1027 printf("%sware scrolling enabled.\n", softscroll
? "Soft" : "Hard");
1030 /*===========================================================================*
1032 *===========================================================================*/
1035 /* Prepare for halt or reboot. */
1039 cons_table
[0].c_attr
= cons_table
[0].c_blank
= BLANK_COLOR
;
1040 shutting_down
= TRUE
;
1043 /*===========================================================================*
1045 *===========================================================================*/
1046 static void cons_org0()
1048 /* Scroll video memory back to put the origin at 0. */
1053 for (cons_line
= 0; cons_line
< nr_cons
; cons_line
++) {
1054 cons
= &cons_table
[cons_line
];
1055 while (cons
->c_org
> cons
->c_start
) {
1056 n
= vid_size
- scr_size
; /* amount of unused memory */
1057 if (n
> cons
->c_org
- cons
->c_start
)
1058 n
= cons
->c_org
- cons
->c_start
;
1059 vid_vid_copy(cons
->c_org
, cons
->c_org
- n
, scr_size
);
1060 UPDATE_ORIGIN(cons
, cons
->c_org
- n
);
1064 select_console(ccurrent
);
1067 /*===========================================================================*
1069 *===========================================================================*/
1070 static void disable_console()
1072 if (disabled_vc
!= -1)
1075 disabled_vc
= ccurrent
;
1076 disabled_sm
= softscroll
;
1082 /* Should also disable further output to virtual consoles */
1085 /*===========================================================================*
1086 * reenable_console *
1087 *===========================================================================*/
1088 static void reenable_console()
1090 if (disabled_vc
== -1)
1093 softscroll
= disabled_sm
;
1094 select_console(disabled_vc
);
1098 /*===========================================================================*
1100 *===========================================================================*/
1101 void select_console(int cons_line
)
1103 /* Set the current console to console number 'cons_line'. */
1105 if (shutting_down
) return;
1107 if (cons_line
< 0 || cons_line
>= nr_cons
) return;
1109 ccurrent
= cons_line
;
1110 curcons
= &cons_table
[cons_line
];
1112 UPDATE_CURSOR(curcons
, curcons
->c_cur
);
1113 UPDATE_ORIGIN(curcons
, curcons
->c_org
);
1116 /*===========================================================================*
1118 *===========================================================================*/
1123 /* Load a font into the EGA or VGA adapter. */
1125 static struct sequence seq1
[7] = {
1126 { GA_SEQUENCER_INDEX
, 0x00, 0x01 },
1127 { GA_SEQUENCER_INDEX
, 0x02, 0x04 },
1128 { GA_SEQUENCER_INDEX
, 0x04, 0x07 },
1129 { GA_SEQUENCER_INDEX
, 0x00, 0x03 },
1130 { GA_GRAPHICS_INDEX
, 0x04, 0x02 },
1131 { GA_GRAPHICS_INDEX
, 0x05, 0x00 },
1132 { GA_GRAPHICS_INDEX
, 0x06, 0x00 },
1134 static struct sequence seq2
[7] = {
1135 { GA_SEQUENCER_INDEX
, 0x00, 0x01 },
1136 { GA_SEQUENCER_INDEX
, 0x02, 0x03 },
1137 { GA_SEQUENCER_INDEX
, 0x04, 0x03 },
1138 { GA_SEQUENCER_INDEX
, 0x00, 0x03 },
1139 { GA_GRAPHICS_INDEX
, 0x04, 0x00 },
1140 { GA_GRAPHICS_INDEX
, 0x05, 0x10 },
1141 { GA_GRAPHICS_INDEX
, 0x06, 0 },
1144 seq2
[6].value
= color
? 0x0E : 0x0A;
1146 result
= ga_program(seq1
); /* bring font memory into view */
1148 if(sys_safecopyfrom(m
->m_source
, (cp_grant_id_t
) m
->IO_GRANT
, 0,
1149 (vir_bytes
) font_memory
, GA_FONT_SIZE
) != OK
) {
1150 printf("tty: copying from %d failed\n", m
->m_source
);
1154 result
= ga_program(seq2
); /* restore */
1159 /*===========================================================================*
1161 *===========================================================================*/
1162 static int ga_program(seq
)
1163 struct sequence
*seq
;
1165 pvb_pair_t char_out
[14];
1167 for (i
=0; i
<7; i
++) {
1168 pv_set(char_out
[2*i
], seq
->index
, seq
->port
);
1169 pv_set(char_out
[2*i
+1], seq
->index
+1, seq
->value
);
1172 return sys_voutb(char_out
, 14);
1175 /*===========================================================================*
1177 *===========================================================================*/
1178 static int cons_ioctl(tty_t
*tp
, int UNUSED(try))
1180 /* Set the screen dimensions. */
1182 tp
->tty_winsize
.ws_row
= scr_lines
;
1183 tp
->tty_winsize
.ws_col
= scr_width
;
1184 tp
->tty_winsize
.ws_xpixel
= scr_width
* 8;
1185 tp
->tty_winsize
.ws_ypixel
= scr_lines
* font_lines
;
1190 #define LIMITINDEX(mask, start, size, ct) { \
1191 int countlimit = size - start; \
1193 if(ct > countlimit) ct = countlimit; \
1196 /*===========================================================================*
1198 *===========================================================================*/
1199 static void mem_vid_copy(vir_bytes src
, int dst_index
, int count
)
1201 u16_t
*src_mem
= (u16_t
*) src
;
1203 int i
, subcount
= count
;
1205 LIMITINDEX(vid_mask
, dst_index
, vid_size
, subcount
);
1206 dst_mem
= (u16_t
*) console_memory
+ dst_index
;
1208 for(i
= 0; i
< subcount
; i
++)
1209 *dst_mem
++ = blank_color
;
1211 for(i
= 0; i
< subcount
; i
++)
1212 *dst_mem
++ = *src_mem
++;
1214 dst_index
+= subcount
;
1218 /*===========================================================================*
1220 *===========================================================================*/
1221 static void vid_vid_copy(int src_index
, int dst_index
, int count
)
1224 if(src_index
< dst_index
)
1227 int i
, subcount
= count
;
1228 u16_t
*dst_mem
, *src_mem
;
1229 LIMITINDEX(vid_mask
, src_index
, vid_size
, subcount
);
1230 LIMITINDEX(vid_mask
, dst_index
, vid_size
, subcount
);
1231 src_mem
= (u16_t
*) console_memory
+ src_index
;
1232 dst_mem
= (u16_t
*) console_memory
+ dst_index
;
1234 src_mem
+= subcount
- 1;
1235 dst_mem
+= subcount
- 1;
1236 for(i
= 0; i
< subcount
; i
++)
1237 *dst_mem
-- = *src_mem
--;
1239 for(i
= 0; i
< subcount
; i
++)
1240 *dst_mem
++ = *src_mem
++;
1243 dst_index
+= subcount
;
1244 src_index
+= subcount
;