/* 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"); }