📄 console.c
字号:
/* * linux/kernel/console.c * * (C) 1991 Linus Torvalds *//* * console.c * * This module implements the console io functions * 'void con_init(void)' * 'void con_write(struct tty_queue * queue)' * Hopefully this will be a rather complete VT102 implementation. * * Beeping thanks to John T Kohl. *//* * NOTE!!! We sometimes disable and enable interrupts for a short while * (to put a word in video IO), but this will work even for keyboard * interrupts. We know interrupts aren't enabled when getting a keyboard * interrupt, as we use trap-gates. Hopefully all is well. *//* * Code to check for different video-cards mostly by Galen Hunt, * <g-hunt@ee.utah.edu> */#include <linux/sched.h>#include <linux/tty.h>#include <asm/io.h>#include <asm/system.h>/* * These are set up by the setup-routine(setup.s) at boot-time: */#define ORIG_X (*(unsigned char *)0x90000) /* 初始关标列号*/#define ORIG_Y (*(unsigned char *)0x90001) /* 初始关标行号*/#define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004) /*显示页面*/#define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff) /* 显示模式*/#define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8) /* 字符列数*/#define ORIG_VIDEO_LINES (25) /*显示行数*/#define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008)#define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a) /* 显存大小*/#define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c) /* 显卡特性参数*/#define VIDEO_TYPE_MDA 0x10 /* Monochrome(单色) Text Display */#define VIDEO_TYPE_CGA 0x11 /* CGA Display */#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */#define NPAR 16 /* 转义字符序列中最大参数个数*/extern void keyboard_interrupt(void); static unsigned char video_type; /* Type of display being used */static unsigned long video_num_columns; /* Number of text columns */static unsigned long video_size_row; /* Bytes per row */static unsigned long video_num_lines; /* Number of text lines */static unsigned char video_page; /* Initial video page */static unsigned long video_mem_start; /* Start of video RAM */static unsigned long video_mem_end; /* End of video RAM (sort of) */static unsigned short video_port_reg; /* Video register select port */static unsigned short video_port_val; /* Video register value port */static unsigned short video_erase_char; /* Char+Attrib to erase with *//* 擦除字符属性及字符 */static unsigned long origin; /* Used for EGA/VGA fast scroll *//* 屏幕起始地址(orgin-video_mem_start即为) */static unsigned long scr_end; /* Used for EGA/VGA fast scroll *//* 屏幕末端地址 */static unsigned long pos; /* 当前光标对应显示内存位置*/static unsigned long x,y; /* 目前光标位置 */static unsigned long top,bottom; /* 屏幕中顶行行号,底行行号(top是相对于orgin的) */static unsigned long state=0; /* ANSI转义字符序列处理状态 */static unsigned long npar,par[NPAR]; /* ANSI转义字符序列参数和参数个数*/static unsigned long ques=0; /* 收到问号字符标志 */static unsigned char attr=0x07; /* 字符属性(黑底白子) */static void sysbeep(void); /* 系统蜂鸣函数*//* * this is what the terminal answers to a ESC-Z or csi0c * query (= vt100 response). */#define RESPONSE "\033[?1;2c" /* 表示终端是高级视频终端(应答主机发问的应答序列) *//* NOTE! gotoxy thinks x==video_num_columns is ok */static inline void gotoxy(unsigned int new_x,unsigned int new_y)/*更新光标当前所在位置和光标对应的显存位置pos。*/{ if (new_x > video_num_columns || new_y >= video_num_lines) return; x=new_x; y=new_y; pos=origin + y*video_size_row + (x<<1);}static inline void set_origin(void) /* 设置滚屏起始显存地址(在屏幕上显示数据的实质) */ /* 屏幕上一个字符用2个字节表示*/{ cli(); outb_p(12, video_port_reg); /* 选择显示控制数据寄存器r12*/ outb_p(0xff&((origin-video_mem_start)>>9), video_port_val); /* 向r12中写入卷屏起始地址高字节*/ outb_p(13, video_port_reg); /* 选择显示控制数据寄存器r13*/ outb_p(0xff&((origin-video_mem_start)>>1), video_port_val); /* 向r13中写入卷屏起始地址底字节*/ sti();}static void scrup(void) /* 向上卷动一行*/{ if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) /* 显卡类型*/ { if (!top && bottom == video_num_lines) {/* 整屏窗口向下移动(显存中的数据不动,仅仅是屏幕在下移)*/ origin += video_size_row; pos += video_size_row; scr_end += video_size_row; if (scr_end > video_mem_end) {/* 下移之后越界,则将屏幕中的数据移置显存开始位置*/ __asm__("cld\n\t" "rep\n\t" "movsl\n\t" /*move data from edi(S) to esi(D)*/ "movl _video_num_columns,%1\n\t" "rep\n\t" "stosw" /*在新行上填空格*/ ::"a" (video_erase_char), "c" ((video_num_lines-1)*video_num_columns>>1), "D" (video_mem_start), "S" (origin) :"cx","di","si"); scr_end -= origin-video_mem_start; pos -= origin-video_mem_start; origin = video_mem_start; } else { /*下移之后未越界,则将新进入屏幕的一行填成空格*/ __asm__("cld\n\t" "rep\n\t" "stosw" ::"a" (video_erase_char), "c" (video_num_columns), "D" (scr_end-video_size_row) :"cx","di"); } set_origin();/* 设置显示控制器中显示的内容*/ } else { /*非整屏移动(屏幕不动,仅移动显存中的数据)*/ __asm__("cld\n\t" "rep\n\t" "movsl\n\t" /*将top--botton之间的数据上移一行*/ "movl _video_num_columns,%%ecx\n\t" "rep\n\t" "stosw" ::"a" (video_erase_char), "c" ((bottom-top-1)*video_num_columns>>1), "D" (origin+video_size_row*top), "S" (origin+video_size_row*(top+1)) :"cx","di","si"); } } else /* Not EGA/VGA */ { __asm__("cld\n\t" "rep\n\t" "movsl\n\t" "movl _video_num_columns,%%ecx\n\t" "rep\n\t" "stosw" ::"a" (video_erase_char), "c" ((bottom-top-1)*video_num_columns>>1), "D" (origin+video_size_row*top), "S" (origin+video_size_row*(top+1)) :"cx","di","si"); }}static void scrdown(void) /* 向下卷动一行*/{ if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) { __asm__("std\n\t" "rep\n\t" "movsl\n\t" "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ "movl _video_num_columns,%%ecx\n\t" "rep\n\t" "stosw" ::"a" (video_erase_char), "c" ((bottom-top-1)*video_num_columns>>1), "D" (origin+video_size_row*bottom-4), "S" (origin+video_size_row*(bottom-1)-4) :"ax","cx","di","si"); } else /* Not EGA/VGA */ { __asm__("std\n\t" "rep\n\t" "movsl\n\t" "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ "movl _video_num_columns,%%ecx\n\t" "rep\n\t" "stosw" ::"a" (video_erase_char), "c" ((bottom-top-1)*video_num_columns>>1), "D" (origin+video_size_row*bottom-4), "S" (origin+video_size_row*(bottom-1)-4) :"ax","cx","di","si"); }}static void lf(void)/*换行*/{ if (y+1<bottom) { y++; pos += video_size_row; return; } scrup();}static void ri(void)/*反换行*/{ if (y>top) { y--; pos -= video_size_row; return; } scrdown();}static void cr(void) /*回行首*/{ pos -= x<<1; x=0;}static void del(void) /*删除一字符*/{ if (x) { pos -= 2; x--; *(unsigned short *)pos = video_erase_char; }}static void csi_J(int par)/*删除屏幕上的相关数据*/{ long count __asm__("cx"); long start __asm__("di"); switch (par) { case 0: /* erase from cursor to end of display */ count = (scr_end-pos)>>1; start = pos; break; case 1: /* erase from start to cursor */ count = (pos-origin)>>1; start = origin; break; case 2: /* erase whole display */ count = video_num_columns * video_num_lines; start = origin; break; default: return; } __asm__("cld\n\t" "rep\n\t" "stosw\n\t" ::"c" (count), "D" (start),"a" (video_erase_char) :"cx","di");}static void csi_K(int par)/*类上*/{ long count __asm__("cx"); long start __asm__("di"); switch (par) { case 0: /* erase from cursor to end of line */ if (x>=video_num_columns) return; count = video_num_columns-x; start = pos; break; case 1: /* erase from start of line to cursor */ start = pos - (x<<1); count = (x<video_num_columns)?x:video_num_columns; break; case 2: /* erase whole line */ start = pos - (x<<1); count = video_num_columns; break; default: return; } __asm__("cld\n\t" "rep\n\t" "stosw\n\t" ::"c" (count), "D" (start),"a" (video_erase_char) :"cx","di");}void csi_m(void) /*设置显示字符属性*/{ int i; for (i=0;i<=npar;i++) switch (par[i]) { case 0:attr=0x07;break; case 1:attr=0x0f;break; case 4:attr=0x0f;break; case 7:attr=0x70;break; case 27:attr=0x07;break; }}static inline void set_cursor(void)/*设置显示光标*/{ cli(); outb_p(14, video_port_reg); outb_p(0xff&((pos-video_mem_start)>>9), video_port_val); outb_p(15, video_port_reg); outb_p(0xff&((pos-video_mem_start)>>1), video_port_val); sti();}static void respond(struct tty_struct * tty)/*将RESPONSE放入读队列及辅助队列中*/{ char * p = RESPONSE; cli(); while (*p) { /*逐字的放入read_q队列*/ PUTCH(*p,tty->read_q); p++; } sti(); copy_to_cooked(tty);/*放入辅助队列*/}static void insert_char(void)/*插入空格*/{ int i=x; unsigned short tmp, old = video_erase_char; unsigned short * p = (unsigned short *) pos; while (i++<video_num_columns) { tmp=*p; *p=old; old=tmp; p++; }}static void insert_line(void)/*插入行*/{ int oldtop,oldbottom; oldtop=top; oldbottom=bottom; top=y;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -