📄 console.c
字号:
/* Code and data for the IBM console driver. * * The 6845 video controller used by the IBM PC shares its video memory with * the CPU somewhere in the 0xB0000 memory bank. To the 6845 this memory * consists of 16-bit words. Each word has a character code in the low byte * and a so-called attribute byte in the high byte. The CPU directly modifies * video memory to display characters, and sets two registers on the 6845 that * specify the video origin and the cursor position. The video origin is the * place in video memory where the first character (upper left corner) can * be found. Moving the origin is a fast way to scroll the screen. Some * video adapters wrap around the top of video memory, so the origin can * move without bounds. For other adapters screen memory must sometimes be * moved to reset the origin. All computations on video memory use character * (word) addresses for simplicity and assume there is no wrapping. The * assembly support functions translate the word addresses to byte addresses * and the scrolling function worries about wrapping. */#include "../drivers.h"#include <termios.h>#include <minix/callnr.h>#include <minix/com.h>#include "tty.h"#include "../../kernel/const.h"#include "../../kernel/config.h"#include "../../kernel/type.h"/* Definitions used by the console driver. */#define MONO_BASE 0xB0000L /* base of mono video memory */#define COLOR_BASE 0xB8000L /* base of color video memory */#define MONO_SIZE 0x1000 /* 4K mono video memory */#define COLOR_SIZE 0x4000 /* 16K color video memory */#define EGA_SIZE 0x8000 /* EGA & VGA have at least 32K */#define BLANK_COLOR 0x0700 /* determines cursor color on blank screen */#define SCROLL_UP 0 /* scroll forward */#define SCROLL_DOWN 1 /* scroll backward */#define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */#define CONS_RAM_WORDS 80 /* video ram buffer size */#define MAX_ESC_PARMS 4 /* number of escape sequence params allowed *//* Constants relating to the controller chips. */#define M_6845 0x3B4 /* port for 6845 mono */#define C_6845 0x3D4 /* port for 6845 color */#define INDEX 0 /* 6845's index register */#define DATA 1 /* 6845's data register */#define STATUS 6 /* 6845's status 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 *//* definitions used for font management */#define GA_SEQUENCER_INDEX 0x3C4#define GA_SEQUENCER_DATA 0x3C5#define GA_GRAPHICS_INDEX 0x3CE#define GA_GRAPHICS_DATA 0x3CF#define GA_VIDEO_ADDRESS 0xA0000L#define GA_FONT_SIZE 8192/* Global variables used by the console driver and assembly support. */PUBLIC int vid_index; /* index of video segment in remote mem map */PUBLIC u16_t vid_seg;PUBLIC vir_bytes vid_off; /* video ram is found at vid_seg:vid_off */PUBLIC unsigned vid_size; /* 0x2000 for color or 0x0800 for mono */PUBLIC unsigned vid_mask; /* 0x1FFF for color or 0x07FF for mono */PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank *//* Private variables used by the console driver. */PRIVATE int vid_port; /* I/O port for accessing 6845 */PRIVATE int wrap; /* hardware can wrap? */PRIVATE int softscroll; /* 1 = software scrolling, 0 = hardware */PRIVATE int beeping; /* speaker is beeping? */PRIVATE unsigned font_lines; /* font lines per character */PRIVATE unsigned scr_width; /* # characters on a line */PRIVATE unsigned scr_lines; /* # lines on the screen */PRIVATE unsigned scr_size; /* # characters on the screen *//* Per console data. */typedef struct console { tty_t *c_tty; /* associated TTY struct */ int c_column; /* current column number (0-origin) */ int c_row; /* current row (0 at top of screen) */ int c_rwords; /* number of WORDS (not bytes) in outqueue */ unsigned c_start; /* start of video memory of this console */ unsigned c_limit; /* limit of this console's video memory */ unsigned c_org; /* location in RAM where 6845 base points */ unsigned c_cur; /* current position of cursor in video RAM */ unsigned c_attr; /* character attribute */ unsigned c_blank; /* blank attribute */ char c_reverse; /* reverse video */ char c_esc_state; /* 0=normal, 1=ESC, 2=ESC[ */ char c_esc_intro; /* Distinguishing character following ESC */ int *c_esc_parmp; /* pointer to current escape parameter */ int c_esc_parmv[MAX_ESC_PARMS]; /* list of escape parameters */ u16_t c_ramqueue[CONS_RAM_WORDS]; /* buffer for video RAM */} console_t;PRIVATE int nr_cons= 1; /* actual number of consoles */PRIVATE console_t cons_table[NR_CONS];PRIVATE console_t *curcons; /* currently visible *//* Color if using a color controller. */#define color (vid_port == C_6845)/* Map from ANSI colors to the attributes used by the PC */PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};/* Structure used for font management */struct sequence { unsigned short index; unsigned char port; unsigned char value;};FORWARD _PROTOTYPE( int cons_write, (struct tty *tp, int try) );FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c) );FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c) );FORWARD _PROTOTYPE( void cons_putk, (int c) );FORWARD _PROTOTYPE( void beep, (void) );FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c) );FORWARD _PROTOTYPE( void flush, (console_t *cons) );FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c) );FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir) );FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val) );FORWARD _PROTOTYPE( void get_6845, (int reg, unsigned *val) );FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp) );FORWARD _PROTOTYPE( void cons_org0, (void) );FORWARD _PROTOTYPE( int ga_program, (struct sequence *seq) );FORWARD _PROTOTYPE( int cons_ioctl, (tty_t *tp, int) );/*===========================================================================* * cons_write * *===========================================================================*/PRIVATE int cons_write(tp, try)register struct tty *tp; /* tells which terminal is to be used */int try;{/* 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 result; register char *tbuf; char buf[64]; console_t *cons = tp->tty_priv; if (try) return 1; /* we can always write to console */ /* Check quickly for nothing to do, so this can be called often without * unmodular tests elsewhere. */ if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return; /* Copy the user bytes to buf[] for decent addressing. Loop over the * copies, since the user buffer may be much larger than buf[]. */ do { if (count > sizeof(buf)) count = sizeof(buf); if ((result = sys_vircopy(tp->tty_outproc, D, tp->tty_out_vir, SELF, D, (vir_bytes) buf, (vir_bytes) count)) != OK) break; tbuf = buf; /* Update terminal data structure. */ tp->tty_out_vir += count; tp->tty_outcum += count; tp->tty_outleft -= count; /* Output each byte of the copy to the screen. Avoid calling * out_char() for the "easy" characters, put them into the buffer * directly. */ do { if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0 || cons->c_column >= scr_width || cons->c_rwords >= buflen(cons->c_ramqueue)) { out_char(cons, *tbuf++); } else { cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (*tbuf++ & BYTE); cons->c_column++; } } while (--count != 0); } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited); flush(cons); /* transfer anything buffered to the screen */ /* Reply to the writer if all output is finished or if an error occured. */ if (tp->tty_outleft == 0 || result != OK) { /* REVIVE is not possible. I/O on memory mapped consoles finishes. */ tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc, tp->tty_outcum); tp->tty_outcum = 0; }}/*===========================================================================* * cons_echo * *===========================================================================*/PRIVATE void cons_echo(tp, c)register tty_t *tp; /* pointer to tty struct */int c; /* character to be echoed */{/* Echo keyboard input (print & flush). */ console_t *cons = tp->tty_priv; out_char(cons, c); flush(cons);}/*===========================================================================* * out_char * *===========================================================================*/PRIVATE void out_char(cons, c)register console_t *cons; /* pointer to console struct */int c; /* character to be output */{/* Output a character on the console. Check for escape sequences first. */ if (cons->c_esc_state > 0) { parse_escape(cons, c); return; } switch(c) { case 000: /* null is typically used for padding */ return; /* better not do anything */ case 007: /* ring the bell */ flush(cons); /* print any chars queued for output */ beep(); return; case '\b': /* backspace */ if (--cons->c_column < 0) { if (--cons->c_row >= 0) cons->c_column += scr_width; } flush(cons); return; case '\n': /* line feed */ if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR)) == (OPOST|ONLCR)) { cons->c_column = 0; } /*FALL THROUGH*/ case 013: /* CTRL-K */ case 014: /* CTRL-L */ if (cons->c_row == scr_lines-1) { scroll_screen(cons, SCROLL_UP); } else { cons->c_row++; } flush(cons); return; case '\r': /* carriage return */ cons->c_column = 0; flush(cons); return; case '\t': /* tab */ cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK; if (cons->c_column > scr_width) { cons->c_column -= scr_width; if (cons->c_row == scr_lines-1) { scroll_screen(cons, SCROLL_UP); } else { cons->c_row++; } } flush(cons); return; case 033: /* ESC - start of an escape sequence */ flush(cons); /* print any chars queued for output */ cons->c_esc_state = 1; /* mark ESC as seen */ return; default: /* printable chars are stored in ramqueue */ if (cons->c_column >= scr_width) { if (!LINEWRAP) return; if (cons->c_row == scr_lines-1) { scroll_screen(cons, SCROLL_UP); } else { cons->c_row++; } cons->c_column = 0; flush(cons); } if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons); cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE); cons->c_column++; /* next column */ return; }}/*===========================================================================* * scroll_screen * *===========================================================================*/PRIVATE void scroll_screen(cons, dir)register console_t *cons; /* pointer to console struct */int dir; /* SCROLL_UP or SCROLL_DOWN */{ unsigned new_line, new_org, chars; flush(cons); chars = scr_size - scr_width; /* one screen minus one line */ /* Scrolling the screen is a real nuisance due to the various incompatible * video cards. This driver supports software scrolling (Hercules?), * hardware scrolling (mono and CGA cards) and hardware scrolling without * wrapping (EGA cards). In the latter case we must make sure that * c_start <= c_org && c_org + scr_size <= c_limit * holds, because EGA doesn't wrap around the end of video memory. */ if (dir == SCROLL_UP) { /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */ if (softscroll) { vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars); } else if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) { vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars); cons->c_org = cons->c_start; } else { cons->c_org = (cons->c_org + scr_width) & vid_mask; } new_line = (cons->c_org + chars) & vid_mask; } else { /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */ if (softscroll) { vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars); } else if (!wrap && cons->c_org < cons->c_start + scr_width) { new_org = cons->c_limit - scr_size; vid_vid_copy(cons->c_org, new_org + scr_width, chars); cons->c_org = new_org; } else { cons->c_org = (cons->c_org - scr_width) & vid_mask; } new_line = cons->c_org; } /* Blank the new line at top or bottom. */ blank_color = cons->c_blank; mem_vid_copy(BLANK_MEM, new_line, scr_width); /* Set the new video origin. */ if (cons == curcons) set_6845(VID_ORG, cons->c_org); flush(cons);}/*===========================================================================* * flush * *===========================================================================*/PRIVATE void flush(cons)register console_t *cons; /* pointer to console struct */{/* Send characters buffered in 'ramqueue' to screen memory, check the new * cursor position, compute the new hardware cursor position and set it. */ unsigned cur; tty_t *tp = cons->c_tty; /* Have the characters in 'ramqueue' transferred to the screen. */ if (cons->c_rwords > 0) { mem_vid_copy(cons->c_ramqueue, cons->c_cur, cons->c_rwords); cons->c_rwords = 0; /* TTY likes to know the current column and if echoing messed up. */ tp->tty_position = cons->c_column; tp->tty_reprint = TRUE; } /* Check and update the cursor position. */ if (cons->c_column < 0) cons->c_column = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -