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, ¶m); } 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, ¶m); 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 + -
显示快捷键?