vt.c

来自「linux 内核源代码」· C语言 代码 · 共 2,565 行 · 第 1/5 页

C
2,565
字号
		}	}}static void insert_char(struct vc_data *vc, unsigned int nr){	unsigned short *p, *q = (unsigned short *)vc->vc_pos;	p = q + vc->vc_cols - nr - vc->vc_x;	while (--p >= q)		scr_writew(scr_readw(p), p + nr);	scr_memsetw(q, vc->vc_video_erase_char, nr * 2);	vc->vc_need_wrap = 0;	if (DO_UPDATE(vc)) {		unsigned short oldattr = vc->vc_attr;		vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,				     vc->vc_cols - vc->vc_x - nr);		vc->vc_attr = vc->vc_video_erase_char >> 8;		while (nr--)			vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);		vc->vc_attr = oldattr;	}}static void delete_char(struct vc_data *vc, unsigned int nr){	unsigned int i = vc->vc_x;	unsigned short *p = (unsigned short *)vc->vc_pos;	while (++i <= vc->vc_cols - nr) {		scr_writew(scr_readw(p+nr), p);		p++;	}	scr_memsetw(p, vc->vc_video_erase_char, nr * 2);	vc->vc_need_wrap = 0;	if (DO_UPDATE(vc)) {		unsigned short oldattr = vc->vc_attr;		vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,				     vc->vc_cols - vc->vc_x - nr);		vc->vc_attr = vc->vc_video_erase_char >> 8;		while (nr--)			vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,				     vc->vc_cols - 1 - nr);		vc->vc_attr = oldattr;	}}static int softcursor_original;static void add_softcursor(struct vc_data *vc){	int i = scr_readw((u16 *) vc->vc_pos);	u32 type = vc->vc_cursor_type;	if (! (type & 0x10)) return;	if (softcursor_original != -1) return;	softcursor_original = i;	i |= ((type >> 8) & 0xff00 );	i ^= ((type) & 0xff00 );	if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;	if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;	scr_writew(i, (u16 *) vc->vc_pos);	if (DO_UPDATE(vc))		vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);}static void hide_softcursor(struct vc_data *vc){	if (softcursor_original != -1) {		scr_writew(softcursor_original, (u16 *)vc->vc_pos);		if (DO_UPDATE(vc))			vc->vc_sw->con_putc(vc, softcursor_original,					vc->vc_y, vc->vc_x);		softcursor_original = -1;	}}static void hide_cursor(struct vc_data *vc){	if (vc == sel_cons)		clear_selection();	vc->vc_sw->con_cursor(vc, CM_ERASE);	hide_softcursor(vc);}static void set_cursor(struct vc_data *vc){	if (!IS_FG(vc) || console_blanked ||	    vc->vc_mode == KD_GRAPHICS)		return;	if (vc->vc_deccm) {		if (vc == sel_cons)			clear_selection();		add_softcursor(vc);		if ((vc->vc_cursor_type & 0x0f) != 1)			vc->vc_sw->con_cursor(vc, CM_DRAW);	} else		hide_cursor(vc);}static void set_origin(struct vc_data *vc){	WARN_CONSOLE_UNLOCKED();	if (!CON_IS_VISIBLE(vc) ||	    !vc->vc_sw->con_set_origin ||	    !vc->vc_sw->con_set_origin(vc))		vc->vc_origin = (unsigned long)vc->vc_screenbuf;	vc->vc_visible_origin = vc->vc_origin;	vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;	vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;}static inline void save_screen(struct vc_data *vc){	WARN_CONSOLE_UNLOCKED();	if (vc->vc_sw->con_save_screen)		vc->vc_sw->con_save_screen(vc);}/* *	Redrawing of screen */static void clear_buffer_attributes(struct vc_data *vc){	unsigned short *p = (unsigned short *)vc->vc_origin;	int count = vc->vc_screenbuf_size / 2;	int mask = vc->vc_hi_font_mask | 0xff;	for (; count > 0; count--, p++) {		scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);	}}void redraw_screen(struct vc_data *vc, int is_switch){	int redraw = 0;	WARN_CONSOLE_UNLOCKED();	if (!vc) {		/* strange ... */		/* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */		return;	}	if (is_switch) {		struct vc_data *old_vc = vc_cons[fg_console].d;		if (old_vc == vc)			return;		if (!CON_IS_VISIBLE(vc))			redraw = 1;		*vc->vc_display_fg = vc;		fg_console = vc->vc_num;		hide_cursor(old_vc);		if (!CON_IS_VISIBLE(old_vc)) {			save_screen(old_vc);			set_origin(old_vc);		}	} else {		hide_cursor(vc);		redraw = 1;	}	if (redraw) {		int update;		int old_was_color = vc->vc_can_do_color;		set_origin(vc);		update = vc->vc_sw->con_switch(vc);		set_palette(vc);		/*		 * If console changed from mono<->color, the best we can do		 * is to clear the buffer attributes. As it currently stands,		 * rebuilding new attributes from the old buffer is not doable		 * without overly complex code.		 */		if (old_was_color != vc->vc_can_do_color) {			update_attr(vc);			clear_buffer_attributes(vc);		}		if (update && vc->vc_mode != KD_GRAPHICS)			do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);	}	set_cursor(vc);	if (is_switch) {		set_leds();		compute_shiftstate();	}}/* *	Allocation, freeing and resizing of VTs. */int vc_cons_allocated(unsigned int i){	return (i < MAX_NR_CONSOLES && vc_cons[i].d);}static void visual_init(struct vc_data *vc, int num, int init){	/* ++Geert: vc->vc_sw->con_init determines console size */	if (vc->vc_sw)		module_put(vc->vc_sw->owner);	vc->vc_sw = conswitchp;#ifndef VT_SINGLE_DRIVER	if (con_driver_map[num])		vc->vc_sw = con_driver_map[num];#endif	__module_get(vc->vc_sw->owner);	vc->vc_num = num;	vc->vc_display_fg = &master_display_fg;	vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;	vc->vc_uni_pagedir = 0;	vc->vc_hi_font_mask = 0;	vc->vc_complement_mask = 0;	vc->vc_can_do_color = 0;	vc->vc_sw->con_init(vc, init);	if (!vc->vc_complement_mask)		vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;	vc->vc_s_complement_mask = vc->vc_complement_mask;	vc->vc_size_row = vc->vc_cols << 1;	vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;}int vc_allocate(unsigned int currcons)	/* return 0 on success */{	WARN_CONSOLE_UNLOCKED();	if (currcons >= MAX_NR_CONSOLES)		return -ENXIO;	if (!vc_cons[currcons].d) {	    struct vc_data *vc;	    struct vt_notifier_param param;	    /* prevent users from taking too much memory */	    if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))	      return -EPERM;	    /* due to the granularity of kmalloc, we waste some memory here */	    /* the alloc is done in two steps, to optimize the common situation	       of a 25x80 console (structsize=216, screenbuf_size=4000) */	    /* although the numbers above are not valid since long ago, the	       point is still up-to-date and the comment still has its value	       even if only as a historical artifact.  --mj, July 1998 */	    param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);	    if (!vc)		return -ENOMEM;	    vc_cons[currcons].d = vc;	    INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);	    visual_init(vc, currcons, 1);	    if (!*vc->vc_uni_pagedir_loc)		con_set_default_unimap(vc);	    if (!vc->vc_kmalloced)		vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);	    if (!vc->vc_screenbuf) {		kfree(vc);		vc_cons[currcons].d = NULL;		return -ENOMEM;	    }	    vc->vc_kmalloced = 1;	    vc_init(vc, vc->vc_rows, vc->vc_cols, 1);	    atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);	}	return 0;}static inline int resize_screen(struct vc_data *vc, int width, int height,				int user){	/* Resizes the resolution of the display adapater */	int err = 0;	if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)		err = vc->vc_sw->con_resize(vc, width, height, user);	return err;}/* * Change # of rows and columns (0 means unchanged/the size of fg_console) * [this is to be used together with some user program * like resize that changes the hardware videomode] */#define VC_RESIZE_MAXCOL (32767)#define VC_RESIZE_MAXROW (32767)int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines){	unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;	unsigned int old_cols, old_rows, old_row_size, old_screen_size;	unsigned int new_cols, new_rows, new_row_size, new_screen_size;	unsigned int end, user;	unsigned short *newscreen;	WARN_CONSOLE_UNLOCKED();	if (!vc)		return -ENXIO;	user = vc->vc_resize_user;	vc->vc_resize_user = 0;	if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)		return -EINVAL;	new_cols = (cols ? cols : vc->vc_cols);	new_rows = (lines ? lines : vc->vc_rows);	new_row_size = new_cols << 1;	new_screen_size = new_row_size * new_rows;	if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)		return 0;	newscreen = kmalloc(new_screen_size, GFP_USER);	if (!newscreen)		return -ENOMEM;	old_rows = vc->vc_rows;	old_cols = vc->vc_cols;	old_row_size = vc->vc_size_row;	old_screen_size = vc->vc_screenbuf_size;	err = resize_screen(vc, new_cols, new_rows, user);	if (err) {		kfree(newscreen);		return err;	}	vc->vc_rows = new_rows;	vc->vc_cols = new_cols;	vc->vc_size_row = new_row_size;	vc->vc_screenbuf_size = new_screen_size;	rlth = min(old_row_size, new_row_size);	rrem = new_row_size - rlth;	old_origin = vc->vc_origin;	new_origin = (long) newscreen;	new_scr_end = new_origin + new_screen_size;	if (vc->vc_y > new_rows) {		if (old_rows - vc->vc_y < new_rows) {			/*			 * Cursor near the bottom, copy contents from the			 * bottom of buffer			 */			old_origin += (old_rows - new_rows) * old_row_size;			end = vc->vc_scr_end;		} else {			/*			 * Cursor is in no man's land, copy 1/2 screenful			 * from the top and bottom of cursor position			 */			old_origin += (vc->vc_y - new_rows/2) * old_row_size;			end = old_origin + (old_row_size * new_rows);		}	} else		/*		 * Cursor near the top, copy contents from the top of buffer		 */		end = (old_rows > new_rows) ? old_origin +			(old_row_size * new_rows) :			vc->vc_scr_end;	update_attr(vc);	while (old_origin < end) {		scr_memcpyw((unsigned short *) new_origin,			    (unsigned short *) old_origin, rlth);		if (rrem)			scr_memsetw((void *)(new_origin + rlth),				    vc->vc_video_erase_char, rrem);		old_origin += old_row_size;		new_origin += new_row_size;	}	if (new_scr_end > new_origin)		scr_memsetw((void *)new_origin, vc->vc_video_erase_char,			    new_scr_end - new_origin);	if (vc->vc_kmalloced)		kfree(vc->vc_screenbuf);	vc->vc_screenbuf = newscreen;	vc->vc_kmalloced = 1;	vc->vc_screenbuf_size = new_screen_size;	set_origin(vc);	/* do part of a reset_terminal() */	vc->vc_top = 0;	vc->vc_bottom = vc->vc_rows;	gotoxy(vc, vc->vc_x, vc->vc_y);	save_cur(vc);	if (vc->vc_tty) {		struct winsize ws, *cws = &vc->vc_tty->winsize;		memset(&ws, 0, sizeof(ws));		ws.ws_row = vc->vc_rows;		ws.ws_col = vc->vc_cols;		ws.ws_ypixel = vc->vc_scan_lines;		if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&		    vc->vc_tty->pgrp)			kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1);		*cws = ws;	}	if (CON_IS_VISIBLE(vc))		update_screen(vc);	return err;}int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines){	int rc;	acquire_console_sem();	rc = vc_resize(vc, cols, lines);	release_console_sem();	return rc;}void vc_deallocate(unsigned int currcons){	WARN_CONSOLE_UNLOCKED();	if (vc_cons_allocated(currcons)) {		struct vc_data *vc = vc_cons[currcons].d;		struct vt_notifier_param param = { .vc = vc };		atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);		vc->vc_sw->con_deinit(vc);		put_pid(vc->vt_pid);		module_put(vc->vc_sw->owner);		if (vc->vc_kmalloced)			kfree(vc->vc_screenbuf);		if (currcons >= MIN_NR_CONSOLES)			kfree(vc);		vc_cons[currcons].d = NULL;	}}/* *	VT102 emulator */#define set_kbd(vc, x)	set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))#define clr_kbd(vc, x)	clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))#define is_kbd(vc, x)	vc_kbd_mode(kbd_table + (vc)->vc_num, (x))#define decarm		VC_REPEAT#define decckm		VC_CKMODE#define kbdapplic	VC_APPLIC#define lnm		VC_CRLF/* * this is what the terminal answers to a ESC-Z or csi0c query. */#define VT100ID "\033[?1;2c"#define VT102ID "\033[?6c"unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,				       8,12,10,14, 9,13,11,15 };/* the default colour table, for VGA+ colour systems */int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);/* * gotoxy() must verify all boundaries, because the arguments * might also be negative. If the given position is out of * bounds, the cursor is placed at the nearest margin. */static void gotoxy(struct vc_data *vc, int new_x, int new_y){	int min_y, max_y;	if (new_x < 0)		vc->vc_x = 0;	else {		if (new_x >= vc->vc_cols)			vc->vc_x = vc->vc_cols - 1;		else			vc->vc_x = new_x;	} 	if (vc->vc_decom) {		min_y = vc->vc_top;		max_y = vc->vc_bottom;	} else {		min_y = 0;		max_y = vc->vc_rows;	}	if (new_y < min_y)		vc->vc_y = min_y;	else if (new_y >= max_y)		vc->vc_y = max_y - 1;	else		vc->vc_y = new_y;	vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);	vc->vc_need_wrap = 0;}/* for absolute user moves, when decom is set */static void gotoxay(struct vc_data *vc, int new_x, int new_y){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?