Minix1.5/kernel/console.c
/* Code and data for the IBM console driver. */
#include "kernel.h"
#include <sgtty.h>
#include <minix/callnr.h>
#include <minix/com.h>
#include "protect.h"
#include "tty.h"
/* Definitions used by the console driver. */
#define C_VID_MASK 0x3FFF /* mask for 16K video RAM */
#define M_VID_MASK 0x0FFF /* mask for 4K video RAM */
#define C_RETRACE 0x0300 /* how many characters to display at once */
#define M_RETRACE 0x7000 /* how many characters to display at once */
#define BLANK 0x0700 /* determines cursor color on blank screen */
#define LINE_WIDTH 80 /* # characters on a line */
#define SCR_LINES 25 /* # lines on the screen */
#define SCR_BYTES 8000 /* size video RAM. multiple of 2*LINE_WIDTH */
#define GO_FORWARD 0 /* scroll forward */
#define GO_BACKWARD 1 /* scroll backward */
/* Constants relating to the controller chips. */
#define M_6845 0x3B0 /* port for 6845 mono */
#define C_6845 0x3D0 /* port for 6845 color */
#define EGA 0x3C0 /* port for EGA card */
#define INDEX 4 /* 6845's index register */
#define DATA 5 /* 6845's data register */
#define CUR_SIZE 10 /* 6845's cursor size register */
#define VID_ORG 12 /* 6845's origin register */
#define CURSOR 14 /* 6845's cursor register */
/* Beeper. */
#define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */
#define B_TIME 3 /* length of CTRL-G beep is ticks */
/* Global variables used by the console driver. */
PUBLIC int vid_mask; /* 037777 for color (16K) or 07777 for mono */
PUBLIC int vid_port; /* I/O port for accessing 6845 */
PUBLIC int blank_color = 0x0700; /* display code for blank */
/* Private variables used by the console driver. */
PRIVATE vid_retrace; /* how many characters to display per burst */
PRIVATE int softscroll; /* 1 = software scrolling, 0 = hardware */
PRIVATE unsigned vid_base; /* base of video ram (0xB000 or 0xB800) */
PRIVATE int one_con_attribute; /* current attribute byte << 8 */
/* Map from ANSI colors to the attributes used by the PC */
PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
FORWARD void beep();
FORWARD void do_escape();
FORWARD void l_scr_up();
FORWARD void l_scr_down();
FORWARD void long_vid_copy();
FORWARD void move_to();
FORWARD void parse_escape();
FORWARD void scroll_screen();
FORWARD void set_6845();
FORWARD void stop_beep();
/*===========================================================================*
* console *
*===========================================================================*/
PUBLIC void console(tp)
register struct tty_struct *tp; /* tells which terminal is to be used */
{
/* Copy as much data as possible to the output queue, then start I/O. On
* memory-mapped terminals, such as the IBM console, the I/O will also be
* finished, and the counts updated. Keep repeating until all I/O done.
*/
int count;
int remaining;
register char *tbuf;
/* Check quickly for nothing to do, so this can be called often without
* unmodular tests elsewhere.
*/
if ( (remaining = tp->tty_outleft) == 0 || tp->tty_inhibited == STOPPED)
return;
/* Copy the user bytes to tty_buf for decent addressing. Loop over the
* copies, since the user buffer may be much larger than tty_buf.
*/
do {
if (remaining > sizeof tty_buf) remaining = sizeof tty_buf;
phys_copy(tp->tty_phys, tty_bphys, (phys_bytes) remaining);
tbuf = tty_buf;
/* Output each byte of the copy to the screen. This is the inner loop
* of the output routine, so attempt to make it fast. A more serious
* attempt should produce
* while (easy_cases-- != 0 && *tbuf >= ' ') {
* *outptr++ = *tbuf++;
* *outptr++ = one_con_attribute;
* }
*/
do {
if (*tbuf < ' ' || tp->tty_esc_state > 0 ||
tp->tty_column >= LINE_WIDTH - 1 ||
tp->tty_rwords >= TTY_RAM_WORDS) {
out_char(tp, *tbuf++);
} else {
tp->tty_ramqueue[tp->tty_rwords++] =
one_con_attribute | (*tbuf++ & BYTE);
tp->tty_column++;
}
}
while (--remaining != 0 && tp->tty_inhibited == RUNNING);
/* Update terminal data structure. */
count = tbuf - tty_buf; /* # characters printed */
tp->tty_phys += count; /* advance physical data pointer */
tp->tty_cum += count; /* number of characters printed */
tp->tty_outleft -= count;
if (remaining != 0) break; /* inhibited while in progress */
}
while ( (remaining = tp->tty_outleft) != 0 && tp->tty_inhibited == RUNNING);
flush(tp); /* transfer anything buffered to the screen */
/* If output was not inhibited early, send the appropiate completion reply.
* Otherwise, let TTY handle suspension.
*/
if (tp->tty_outleft == 0) finish(tp, tp->tty_cum);
}
/*===========================================================================*
* out_char *
*===========================================================================*/
PUBLIC void out_char(tp, c)
register struct tty_struct *tp; /* pointer to tty struct */
char c; /* character to be output */
{
/* Output a character on the console. Check for escape sequences first. */
if (tp->tty_esc_state > 0) {
parse_escape(tp, c);
return;
}
switch(c) {
case 000: /* null is typically used for padding */
return; /* better not do anything */
case 007: /* ring the bell */
flush(tp); /* print any chars queued for output */
beep();
return;
case 013: /* CTRL-K */
move_to(tp, tp->tty_column, tp->tty_row - 1);
return;
case 014: /* CTRL-L */
move_to(tp, tp->tty_column + 1, tp->tty_row);
return;
case 016: /* CTRL-N */
move_to(tp, tp->tty_column + 1, tp->tty_row);
return;
case '\b': /* backspace */
move_to(tp, tp->tty_column - 1, tp->tty_row);
return;
case '\n': /* line feed */
if (tp->tty_mode & CRMOD) move_to(tp, 0, tp->tty_row);
if (tp->tty_row == SCR_LINES-1)
scroll_screen(tp, GO_FORWARD);
else
tp->tty_row++;
move_to(tp, tp->tty_column, tp->tty_row);
return;
case '\r': /* carriage return */
move_to(tp, 0, tp->tty_row);
return;
case '\t': /* tab */
if ( (tp->tty_mode & XTABS) == XTABS) {
do {
if (tp->tty_column >= LINE_WIDTH - 1 ||
tp->tty_rwords >= TTY_RAM_WORDS) {
out_char(tp, ' ');
} else {
tp->tty_ramqueue[tp->tty_rwords++] =
one_con_attribute | ' ';
tp->tty_column++;
}
} while (tp->tty_column & TAB_MASK);
return;
}
/* Ignore tab if XTABS is off--video RAM has no hardware tab */
return;
case 033: /* ESC - start of an escape sequence */
flush(tp); /* print any chars queued for output */
tp->tty_esc_state = 1; /* mark ESC as seen */
return;
default: /* printable chars are stored in ramqueue */
#if !LINEWRAP
if (tp->tty_column >= LINE_WIDTH) return; /* long line */
#endif
if (tp->tty_rwords == TTY_RAM_WORDS) flush(tp);
tp->tty_ramqueue[tp->tty_rwords++]=one_con_attribute|(c&BYTE);
tp->tty_column++; /* next column */
#if LINEWRAP
if (tp->tty_column >= LINE_WIDTH) {
flush(tp);
if (tp->tty_row == SCR_LINES-1)
scroll_screen(tp, GO_FORWARD);
else
tp->tty_row++;
move_to(tp, 0, tp->tty_row);
}
#endif /* LINEWRAP */
return;
}
}
/*===========================================================================*
* scroll_screen *
*===========================================================================*/
PRIVATE void scroll_screen(tp, dir)
register struct tty_struct *tp; /* pointer to tty struct */
int dir; /* GO_FORWARD or GO_BACKWARD */
{
int amount, offset, bytes;
flush(tp);
bytes = 2 * (SCR_LINES - 1) * LINE_WIDTH; /* 2 * 24 * 80 bytes */
/* Scrolling the screen is a real nuisance due to the various incompatible
* video cards. This driver supports hardware scrolling (mono and CGA cards)
* and software scrolling (EGA cards).
*/
if (softscroll) {
/* Software scrolling for non-IBM compatible EGA cards. */
if (dir == GO_FORWARD) {
scr_up(vid_base, LINE_WIDTH * 2, 0,
(SCR_LINES - 1) * LINE_WIDTH);
vid_copy(NIL_PTR, vid_base, tp->tty_org+bytes, LINE_WIDTH);
} else {
scr_down(vid_base,
(SCR_LINES - 1) * LINE_WIDTH * 2 - 2,
SCR_LINES * LINE_WIDTH * 2 - 2,
(SCR_LINES - 1) * LINE_WIDTH);
vid_copy(NIL_PTR, vid_base, tp->tty_org, LINE_WIDTH);
}
} else if (ega) {
/* Use video origin, but don't assume the hardware can wrap */
if (dir == GO_FORWARD) {
/* after we scroll by one line, end of screen */
offset = tp->tty_org + (SCR_LINES + 1) * LINE_WIDTH * 2;
if (offset > vid_mask) {
scr_up(vid_base, tp->tty_org + LINE_WIDTH * 2, 0,
(SCR_LINES - 1) * LINE_WIDTH);
tp->tty_org = 0;
} else
tp->tty_org += 2 * LINE_WIDTH;
offset = tp->tty_org + bytes;
} else { /* scroll backwards */
offset = tp->tty_org - 2 * LINE_WIDTH;
if (offset < 0) {
scr_down(vid_base,
tp->tty_org + (SCR_LINES - 1) * LINE_WIDTH * 2 - 2,
vid_mask - 1,
(SCR_LINES - 1) * LINE_WIDTH);
tp->tty_org = vid_mask + 1 - SCR_LINES*LINE_WIDTH * 2;
} else
tp->tty_org -= 2 * LINE_WIDTH;
offset = tp->tty_org;
}
/* Blank the new line at top or bottom. */
vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH);
set_6845(VID_ORG, tp->tty_org >> 1); /* 6845 thinks in words */
} else {
/* Normal scrolling using the 6845 registers. */
amount = (dir == GO_FORWARD ? 2 * LINE_WIDTH : -2 * LINE_WIDTH);
tp->tty_org = (tp->tty_org + amount) & vid_mask;
if (dir == GO_FORWARD)
offset = (tp->tty_org + bytes) & vid_mask;
else
offset = tp->tty_org;
/* Blank the new line at top or bottom. */
vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH);
set_6845(VID_ORG, tp->tty_org >> 1); /* 6845 thinks in words */
}
}
/*===========================================================================*
* flush *
*===========================================================================*/
PUBLIC void flush(tp)
register struct tty_struct *tp; /* pointer to tty struct */
{
/* Have the characters in 'ramqueue' transferred to the screen. */
if (tp->tty_rwords == 0) return;
vid_copy((char *)tp->tty_ramqueue, vid_base, tp->tty_vid, tp->tty_rwords);
/* Update the video parameters and cursor. */
tp->tty_vid = (tp->tty_vid + 2 * tp->tty_rwords);
set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */
tp->tty_rwords = 0;
}
/*===========================================================================*
* move_to *
*===========================================================================*/
PRIVATE void move_to(tp, x, y)
struct tty_struct *tp; /* pointer to tty struct */
int x; /* column (0 <= x <= 79) */
int y; /* row (0 <= y <= 24, 0 at top) */
{
/* Move the cursor to (x, y). */
flush(tp); /* flush any pending characters */
if (x < 0 || x >= LINE_WIDTH || y < 0 || y >= SCR_LINES) return;
tp->tty_column = x; /* set x co-ordinate */
tp->tty_row = y; /* set y co-ordinate */
tp->tty_vid = (tp->tty_org + 2*y*LINE_WIDTH + 2*x);
set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */
}
/*===========================================================================*
* parse_escape *
*===========================================================================*/
PRIVATE void parse_escape(tp, c)
register struct tty_struct *tp; /* pointer to tty struct */
char c; /* next character in escape sequence */
{
/* The following ANSI escape sequences are currently supported.
* If n and/or m are omitted, they default to 1.
* ESC [nA moves up n lines
* ESC [nB moves down n lines
* ESC [nC moves right n spaces
* ESC [nD moves left n spaces
* ESC [m;nH" moves cursor to (m,n)
* ESC [J clears screen from cursor
* ESC [K clears line from cursor
* ESC [nL inserts n lines ar cursor
* ESC [nM deletes n lines at cursor
* ESC [nP deletes n chars at cursor
* ESC [n@ inserts n chars at cursor
* ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
* ESC M scrolls the screen backwards if the cursor is on the top line
*/
switch (tp->tty_esc_state) {
case 1: /* ESC seen */
tp->tty_esc_intro = '\0';
tp->tty_esc_parmp = tp->tty_esc_parmv;
tp->tty_esc_parmv[0] = tp->tty_esc_parmv[1] = 0;
switch (c) {
case '[': /* Control Sequence Introducer */
tp->tty_esc_intro = c;
tp->tty_esc_state = 2;
break;
case 'M': /* Reverse Index */
do_escape(tp, c);
break;
default:
tp->tty_esc_state = 0;
break;
}
break;
case 2: /* ESC [ seen */
if (c >= '0' && c <= '9') {
if (tp->tty_esc_parmp
< tp->tty_esc_parmv + MAX_ESC_PARMS)
*tp->tty_esc_parmp =
*tp->tty_esc_parmp * 10 + (c - '0');
break;
}
else if (c == ';') {
if (++tp->tty_esc_parmp
< tp->tty_esc_parmv + MAX_ESC_PARMS)
*tp->tty_esc_parmp = 0;
break;
}
else {
do_escape(tp, c);
}
break;
default: /* illegal state */
tp->tty_esc_state = 0;
break;
}
}
/*===========================================================================*
* do_escape *
*===========================================================================*/
PRIVATE void do_escape(tp, c)
register struct tty_struct *tp; /* pointer to tty struct */
char c; /* next character in escape sequence */
{
int n, vx, value, attr, src, dst, count;
/* Some of these things hack on screen RAM, so it had better be up to date */
flush(tp);
/* Handle a sequence beginning with just ESC */
if (tp->tty_esc_intro == '\0') {
switch (c) {
case 'M': /* Reverse Index */
if (tp->tty_row == 0)
scroll_screen(tp, GO_BACKWARD);
else
tp->tty_row--;
move_to(tp, tp->tty_column, tp->tty_row);
break;
default: break;
}
} else {
/* Handle a sequence beginning with ESC [ and parameters */
if (tp->tty_esc_intro == '[') {
value = tp->tty_esc_parmv[0];
attr = one_con_attribute;
switch (c) {
case 'A': /* ESC [nA moves up n lines */
n = (value == 0 ? 1 : value);
move_to(tp, tp->tty_column, tp->tty_row - n);
break;
case 'B': /* ESC [nB moves down n lines */
n = (value == 0 ? 1 : value);
move_to(tp, tp->tty_column, tp->tty_row + n);
break;
case 'C': /* ESC [nC moves right n spaces */
n = (value == 0 ? 1 : value);
move_to(tp, tp->tty_column + n, tp->tty_row);
break;
case 'D': /* ESC [nD moves left n spaces */
n = (value == 0 ? 1 : value);
move_to(tp, tp->tty_column - n, tp->tty_row);
break;
case 'H': /* ESC [m;nH" moves cursor to (m,n) */
move_to(tp, MAX(1, MIN(LINE_WIDTH,
tp->tty_esc_parmv[1])) - 1,
MAX(1, MIN(SCR_LINES, tp->tty_esc_parmv[0])) - 1 );
break;
case 'J': /* ESC [J clears screen from cursor */
if (value == 0) {
n=2*((SCR_LINES-(tp->tty_row+1))*LINE_WIDTH
+ LINE_WIDTH - (tp->tty_column));
vx = tp->tty_vid;
long_vid_copy(NIL_PTR,vid_base,vx,n/2);
}
break;
case 'K': /* ESC [K clears line from cursor */
if (value == 0) {
n = 2 * (LINE_WIDTH - (tp->tty_column));
vid_copy(NIL_PTR, vid_base, tp->tty_vid, n/2);
}
break;
case 'L': /* ESC [nL inserts n lines ar cursor */
n = value;
if (n < 1) n = 1;
if (n > (SCR_LINES - tp->tty_row))
n = SCR_LINES - tp->tty_row;
src = tp->tty_org+(SCR_LINES - n) * LINE_WIDTH * 2 - 2;
dst = tp->tty_org+SCR_LINES * LINE_WIDTH * 2 - 2;
count = (SCR_LINES - n - tp->tty_row) * LINE_WIDTH;
l_scr_down(vid_base, src, dst, count);
dst = tp->tty_org + tp->tty_row * LINE_WIDTH * 2;
long_vid_copy(NIL_PTR, vid_base, dst, n * LINE_WIDTH);
break;
case 'M': /* ESC [nM deletes n lines at cursor */
n = value;
if (n < 1) n = 1;
if (n > (SCR_LINES - tp->tty_row))
n = SCR_LINES - tp->tty_row;
src = tp->tty_org + (tp->tty_row + n) * LINE_WIDTH * 2;
dst = tp->tty_org + (tp->tty_row) * LINE_WIDTH * 2;
count = (SCR_LINES - n - tp->tty_row) * LINE_WIDTH;
l_scr_up(vid_base, src, dst, count);
dst = tp->tty_org + (SCR_LINES - n) * LINE_WIDTH * 2;
long_vid_copy(NIL_PTR, vid_base, dst, n * LINE_WIDTH);
break;
case 'P': /* ESC [nP deletes n chars at cursor */
n = value;
if (n < 1) n = 1;
if (n > (LINE_WIDTH - tp->tty_column))
n = LINE_WIDTH - tp->tty_column;
src = (tp->tty_row * LINE_WIDTH + tp->tty_column+n) *2;
dst = (tp->tty_row * LINE_WIDTH + tp->tty_column) * 2;
count = LINE_WIDTH - tp->tty_column - n;
src += tp->tty_org;
dst += tp->tty_org;
scr_up(vid_base, src, dst, count);
vid_copy(NIL_PTR, vid_base, dst + count * 2, n);
break;
case '@': /* ESC [n@ inserts n chars at cursor */
n = value;
if (n < 1) n = 1;
if (n > (LINE_WIDTH - tp->tty_column))
n = LINE_WIDTH - tp->tty_column;
src = (tp->tty_row * LINE_WIDTH + LINE_WIDTH- n-1) * 2;
dst = (tp->tty_row * LINE_WIDTH + LINE_WIDTH - 1) * 2;
count = LINE_WIDTH - tp->tty_column - n;
src += tp->tty_org;
dst += tp->tty_org;
scr_down(vid_base, src, dst, count);
dst = (tp->tty_row * LINE_WIDTH + tp->tty_column) * 2;
dst += tp->tty_org;
vid_copy(NIL_PTR, vid_base, dst, n);
break;
case 'm': /* ESC [nm enables rendition n */
switch (value) {
case 1: /* BOLD */
if (color)
one_con_attribute = /* red fg */
(attr & 0xf0ff) | 0x0400;
else
one_con_attribute |= 0x0800; /* inten*/
break;
case 4: /* UNDERLINE */
if (color)
one_con_attribute = /* blue fg */
(attr & 0xf0ff) | 0x0100;
else
one_con_attribute = /* ul */
(attr & 0x8900);
break;
case 5: /* BLINKING */
if (color) /* can't blink color */
one_con_attribute = /* magenta fg */
(attr & 0xf0ff) | 0x0500;
else
one_con_attribute |= /* blink */
0x8000;
break;
case 7: /* REVERSE (black on light grey) */
if (color)
one_con_attribute =
((attr & 0xf000) >> 4) |
((attr & 0x0f00) << 4);
else if ((attr & 0x7000) == 0)
one_con_attribute =
(attr & 0x8800) | 0x7000;
else
one_con_attribute =
(attr & 0x8800) | 0x0700;
break;
default: if (value >= 30 && value <= 37) {
one_con_attribute =
(attr & 0xf0ff) |
(ansi_colors[(value - 30)] << 8);
blank_color =
(blank_color & 0xf0ff) |
(ansi_colors[(value - 30)] << 8);
} else if (value >= 40 && value <= 47) {
one_con_attribute =
(attr & 0x0fff) |
(ansi_colors[(value - 40)] << 12);
blank_color =
(blank_color & 0x0fff) |
(ansi_colors[(value - 40)] << 12);
} else
one_con_attribute = blank_color;
break;
}
break;
default:
break;
} /* closes switch(c) */
} /* closes if (tp->tty_esc_intro == '[') */
}
tp->tty_esc_state = 0;
}
/*===========================================================================*
* long_vid_copy *
*===========================================================================*/
PRIVATE void long_vid_copy(src, base, offset, count)
char *src;
unsigned int base, offset, count;
{
/* Break up a call to vid_copy for machines that can only write
* during vertical retrace. Vid_copy itself does the wait.
*/
int ct;
while (count > 0) {
ct = MIN (count, vid_retrace >> 1);
vid_copy(src, base, offset, ct);
if (src != NIL_PTR) src += ct * 2;
offset += ct * 2;
count -= ct;
}
}
/*===========================================================================*
* long_src_up *
*===========================================================================*/
PRIVATE void l_scr_up(base, src, dst, count)
unsigned int base, src, dst, count;
{
/* Break up a call to scr_up for machines that can only write
* during vertical retrace. scr_up doesn't do the wait, so we do.
* Note however that we keep interrupts on during the scr_up. This
* could lead to snow if an interrupt happens while we are doing
* the display. Sorry, but I don't see any good alternative.
* Turning off interrupts makes us lose RS232 input chars.
*/
int ct, wait;
wait = color && ! ega;
while (count > 0) {
if (wait) wait_retrace();
ct = MIN (count, vid_retrace >> 1);
scr_up(base, src, dst, ct);
src += ct * 2;
dst += ct * 2;
count -= ct;
}
}
/*===========================================================================*
* long_scr_down *
*===========================================================================*/
PRIVATE void l_scr_down(base, src, dst, count)
unsigned int base, src, dst, count;
{
/* Break up a call to scr_down as for scr_up. */
int ct, wait;
wait = color && ! ega;
while (count > 0) {
if (wait) wait_retrace();
ct = MIN (count, vid_retrace >> 1);
scr_down(base, src, dst, ct);
src -= ct * 2;
dst -= ct * 2;
count -= ct;
}
}
/*===========================================================================*
* set_6845 *
*===========================================================================*/
PRIVATE void set_6845(reg, val)
int reg; /* which register pair to set */
int val; /* 16-bit value to set it to */
{
/* Set a register pair inside the 6845.
* Registers 10-11 control the format of the cursor (how high it is, etc).
* Registers 12-13 tell the 6845 where in video ram to start (in WORDS)
* Registers 14-15 tell the 6845 where to put the cursor (in WORDS)
*
* Note that registers 12-15 work in words, i.e. 0x0000 is the top left
* character, but 0x0001 (not 0x0002) is the next character. This addressing
* is different from the way the 8088 addresses the video ram, where 0x0002
* is the address of the next character.
*/
lock(); /* try to stop h/w loading in-between value */
out_byte(vid_port + INDEX, reg); /* set the index register */
out_byte(vid_port + DATA, (val>>8) & BYTE); /* output high byte */
out_byte(vid_port + INDEX, reg + 1); /* again */
out_byte(vid_port + DATA, val&BYTE); /* output low byte */
unlock();
}
/*===========================================================================*
* beep *
*===========================================================================*/
PRIVATE int beeping = FALSE;
PRIVATE void beep()
{
/* Making a beeping sound on the speaker (output for CRTL-G).
* This routine works by turning on the bits 0 and 1 in port B of the 8255
* chip that drive the speaker.
*/
message mess;
if (beeping) return;
out_byte(TIMER_MODE, 0xB6); /* set up timer channel 2 (square wave) */
out_byte(TIMER2, BEEP_FREQ & BYTE); /* load low-order bits of frequency */
out_byte(TIMER2, (BEEP_FREQ >> 8) & BYTE); /* now high-order bits */
lock(); /* guard PORT_B from keyboard intr handler */
out_byte(PORT_B, in_byte(PORT_B) | 3); /* turn on beep bits */
unlock();
beeping = TRUE;
mess.m_type = SET_ALARM;
mess.CLOCK_PROC_NR = TTY;
mess.DELTA_TICKS = B_TIME;
mess.FUNC_TO_CALL = (void (*)()) stop_beep;
sendrec(CLOCK, &mess);
}
/*===========================================================================*
* stop_beep *
*===========================================================================*/
PRIVATE void stop_beep()
{
/* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
lock(); /* guard PORT_B from keyboard intr handler */
out_byte(PORT_B, in_byte(PORT_B) & ~3);
beeping = FALSE;
unlock();
}
/*===========================================================================*
* scr_init *
*===========================================================================*/
PUBLIC void scr_init(minor)
int minor;
{
/* Initialize the screen driver. */
one_con_attribute = BLANK;
if (ps) softscroll = TRUE;
/* Tell the EGA card, if any, to simulate a 16K CGA card. */
out_byte(EGA + INDEX, 4); /* register select */
out_byte(EGA + DATA, 1); /* no extended memory to be used */
if (color) {
vid_base = protected_mode ? COLOR_SELECTOR:physb_to_hclick(COLOR_BASE);
vid_mask = C_VID_MASK;
vid_port = C_6845;
vid_retrace = C_RETRACE;
} else {
vid_base = protected_mode ? MONO_SELECTOR : physb_to_hclick(MONO_BASE);
vid_mask = M_VID_MASK;
vid_port = M_6845;
vid_retrace = M_RETRACE;
}
if (ega) {
vid_mask = C_VID_MASK;
vid_retrace = C_VID_MASK + 1;
}
set_6845(CUR_SIZE, CURSOR_SHAPE); /* set cursor shape */
set_6845(VID_ORG, 0); /* use page 0 of video ram */
move_to(&tty_struct[0], 0, SCR_LINES-1); /* move cursor to lower left */
}
/*===========================================================================*
* putc *
*===========================================================================*/
PUBLIC void putc(c)
char c; /* character to print */
{
/* This procedure is used by the version of printf() that is linked with
* the kernel itself. The one in the library sends a message to FS, which is
* not what is needed for printing within the kernel. This version just queues
* the character and starts the output.
*/
out_char(&tty_struct[0], c);
}
/*===========================================================================*
* toggle_scroll *
*===========================================================================*/
PUBLIC void toggle_scroll()
{
/* Toggle between hardware and software scroll. */
softscroll = 1 - softscroll;
tty_struct[0].tty_org = 0;
move_to(&tty_struct[0], 0, SCR_LINES-1); /* cursor to lower left */
set_6845(VID_ORG, 0);
printf("\033[H\033[J%sware scrolling enabled.\n",
softscroll ? "Soft" : "Hard");
}