📄 console.c
字号:
return; case 'D': if (!par[0]) par[0]++; gotoxy(currcons,x-par[0],y); return; case 'E': if (!par[0]) par[0]++; gotoxy(currcons,0,y+par[0]); return; case 'F': if (!par[0]) par[0]++; gotoxy(currcons,0,y-par[0]); return; case 'd': if (par[0]) par[0]--; gotoxay(currcons,x,par[0]); return; case 'H': case 'f': if (par[0]) par[0]--; if (par[1]) par[1]--; gotoxay(currcons,par[1],par[0]); return; case 'J': csi_J(currcons,par[0]); return; case 'K': csi_K(currcons,par[0]); return; case 'L': csi_L(currcons,par[0]); return; case 'M': csi_M(currcons,par[0]); return; case 'P': csi_P(currcons,par[0]); return; case 'c': if (!par[0]) respond_ID(tty); return; case 'g': if (!par[0]) tab_stop[x >> 5] &= ~(1 << (x & 31)); else if (par[0] == 3) { tab_stop[0] = tab_stop[1] = tab_stop[2] = tab_stop[3] = tab_stop[4] = 0; } return; case 'm': csi_m(currcons); return; case 'q': /* DECLL - but only 3 leds */ /* map 0,1,2,3 to 0,1,2,4 */ if (par[0] < 4) setledstate(kbd_table + currcons, (par[0] < 3) ? par[0] : 4); return; case 'r': if (!par[0]) par[0]++; if (!par[1]) par[1] = video_num_lines; /* Minimum allowed region is 2 lines */ if (par[0] < par[1] && par[1] <= video_num_lines) { top=par[0]-1; bottom=par[1]; gotoxay(currcons,0,0); } return; case 's': save_cur(currcons); return; case 'u': restore_cur(currcons); return; case 'X': csi_X(currcons, par[0]); return; case '@': csi_at(currcons,par[0]); return; case ']': /* setterm functions */ setterm_command(currcons); return; } return; case ESpercent: vc_state = ESnormal; switch (c) { case '@': /* defined in ISO 2022 */ utf = 0; return; case 'G': /* prelim official escape code */ case '8': /* retained for compatibility */ utf = 1; return; } return; case ESfunckey: vc_state = ESnormal; return; case EShash: vc_state = ESnormal; if (c == '8') { /* DEC screen alignment test. kludge :-) */ video_erase_char = (video_erase_char & 0xff00) | 'E'; csi_J(currcons, 2); video_erase_char = (video_erase_char & 0xff00) | ' '; do_update_region(currcons, origin, screenbuf_size/2); } return; case ESsetG0: if (c == '0') G0_charset = GRAF_MAP; else if (c == 'B') G0_charset = LAT1_MAP; else if (c == 'U') G0_charset = IBMPC_MAP; else if (c == 'K') G0_charset = USER_MAP; if (charset == 0) translate = set_translate(G0_charset,currcons); vc_state = ESnormal; return; case ESsetG1: if (c == '0') G1_charset = GRAF_MAP; else if (c == 'B') G1_charset = LAT1_MAP; else if (c == 'U') G1_charset = IBMPC_MAP; else if (c == 'K') G1_charset = USER_MAP; if (charset == 1) translate = set_translate(G1_charset,currcons); vc_state = ESnormal; return; default: vc_state = ESnormal; }}/* This is a temporary buffer used to prepare a tty console write * so that we can easily avoid touching user space while holding the * console spinlock. It is allocated in con_init and is shared by * this code and the vc_screen read/write tty calls. * * We have to allocate this statically in the kernel data section * since console_init (and thus con_init) are called before any * kernel memory allocation is available. */char con_buf[PAGE_SIZE];#define CON_BUF_SIZE PAGE_SIZEDECLARE_MUTEX(con_buf_sem);static int do_con_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count){#ifdef VT_BUF_VRAM_ONLY#define FLUSH do { } while(0);#else#define FLUSH if (draw_x >= 0) { \ sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \ draw_x = -1; \ }#endif int c, tc, ok, n = 0, draw_x = -1; unsigned int currcons; unsigned long draw_from = 0, draw_to = 0; struct vt_struct *vt = (struct vt_struct *)tty->driver_data; u16 himask, charmask; const unsigned char *orig_buf = NULL; int orig_count; currcons = vt->vc_num; if (!vc_cons_allocated(currcons)) { /* could this happen? */ static int error = 0; if (!error) { error = 1; printk("con_write: tty %d not allocated\n", currcons+1); } return 0; } orig_buf = buf; orig_count = count; if (from_user) { down(&con_buf_sem);again: if (count > CON_BUF_SIZE) count = CON_BUF_SIZE; if (copy_from_user(con_buf, buf, count)) { n = 0; /* ?? are error codes legal here ?? */ goto out; } buf = con_buf; } /* At this point 'buf' is guarenteed to be a kernel buffer * and therefore no access to userspace (and therefore sleeping) * will be needed. The con_buf_sem serializes all tty based * console rendering and vcs write/read operations. We hold * the console spinlock during the entire write. */ spin_lock_irq(&console_lock); himask = hi_font_mask; charmask = himask ? 0x1ff : 0xff; /* undraw cursor first */ if (IS_FG) hide_cursor(currcons); while (!tty->stopped && count) { c = *buf; buf++; n++; count--; if (utf) { /* Combine UTF-8 into Unicode */ /* Incomplete characters silently ignored */ if(c > 0x7f) { if (utf_count > 0 && (c & 0xc0) == 0x80) { utf_char = (utf_char << 6) | (c & 0x3f); utf_count--; if (utf_count == 0) tc = c = utf_char; else continue; } else { if ((c & 0xe0) == 0xc0) { utf_count = 1; utf_char = (c & 0x1f); } else if ((c & 0xf0) == 0xe0) { utf_count = 2; utf_char = (c & 0x0f); } else if ((c & 0xf8) == 0xf0) { utf_count = 3; utf_char = (c & 0x07); } else if ((c & 0xfc) == 0xf8) { utf_count = 4; utf_char = (c & 0x03); } else if ((c & 0xfe) == 0xfc) { utf_count = 5; utf_char = (c & 0x01); } else utf_count = 0; continue; } } else { tc = c; utf_count = 0; } } else { /* no utf */ tc = translate[toggle_meta ? (c|0x80) : c]; } /* If the original code was a control character we * only allow a glyph to be displayed if the code is * not normally used (such as for cursor movement) or * if the disp_ctrl mode has been explicitly enabled. * Certain characters (as given by the CTRL_ALWAYS * bitmap) are always displayed as control characters, * as the console would be pretty useless without * them; to display an arbitrary font position use the * direct-to-font zone in UTF-8 mode. */ ok = tc && (c >= 32 || (!utf && !(((disp_ctrl ? CTRL_ALWAYS : CTRL_ACTION) >> c) & 1))) && (c != 127 || disp_ctrl) && (c != 128+27); if (vc_state == ESnormal && ok) { /* Now try to find out how to display it */ tc = conv_uni_to_pc(vc_cons[currcons].d, tc); if ( tc == -4 ) { /* If we got -4 (not found) then see if we have defined a replacement character (U+FFFD) */ tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd); /* One reason for the -4 can be that we just did a clear_unimap(); try at least to show something. */ if (tc == -4) tc = c; } else if ( tc == -3 ) { /* Bad hash table -- hope for the best */ tc = c; } if (tc & ~charmask) continue; /* Conversion failed */ if (need_wrap || decim) FLUSH if (need_wrap) { cr(currcons); lf(currcons); } if (decim) insert_char(currcons, 1); scr_writew(himask ? ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : (attr << 8) + tc, (u16 *) pos); if (DO_UPDATE && draw_x < 0) { draw_x = x; draw_from = pos; } if (x == video_num_columns - 1) { need_wrap = decawm; draw_to = pos+2; } else { x++; draw_to = (pos+=2); } continue; } FLUSH do_con_trol(tty, currcons, c); } FLUSH spin_unlock_irq(&console_lock);out: if (from_user) { /* If the user requested something larger than * the CON_BUF_SIZE, and the tty is not stopped, * keep going. */ if ((orig_count > CON_BUF_SIZE) && !tty->stopped) { orig_count -= CON_BUF_SIZE; orig_buf += CON_BUF_SIZE; count = orig_count; buf = orig_buf; goto again; } up(&con_buf_sem); } return n;#undef FLUSH}/* * This is the console switching tasklet. * * Doing console switching in a tasklet allows * us to do the switches asynchronously (needed when we want * to switch due to a keyboard interrupt). Synchronization * with other console code and prevention of re-entrancy is * ensured with console_lock. */static void console_softint(unsigned long ignored){ /* Runs the task queue outside of the console lock. These * callbacks can come back into the console code and thus * will perform their own locking. */ run_task_queue(&con_task_queue); spin_lock_irq(&console_lock); if (want_console >= 0) { if (want_console != fg_console && vc_cons_allocated(want_console)) { hide_cursor(fg_console); change_console(want_console); /* we only changed when the console had already been allocated - a new console is not created in an interrupt routine */ } want_console = -1; } if (do_poke_blanked_console) { /* do not unblank for a LED change */ do_poke_blanked_console = 0; poke_blanked_console(); } if (scrollback_delta) { int currcons = fg_console; clear_selection(); if (vcmode == KD_TEXT) sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta); scrollback_delta = 0; } spin_unlock_irq(&console_lock);}#ifdef CONFIG_VT_CONSOLE/* * Console on virtual terminal * * The console_lock must be held when we get here. */void vt_console_print(struct console *co, const char * b, unsigned count){ int currcons = fg_console; unsigned char c; static unsigned long printing; const ushort *start; ushort cnt = 0; ushort myx; /* console busy or not yet initialized */ if (!printable || test_and_set_bit(0, &printing)) return; pm_access(pm_con); if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) currcons = kmsg_redirect - 1; /* read `x' only after setting currecons properly (otherwise the `x' macro will read the x of the foreground console). */ myx = x; if (!vc_cons_allocated(currcons)) { /* impossible */ /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ goto quit; } if (vcmode != KD_TEXT) goto quit; /* undraw cursor first */ if (IS_FG) hide_cursor(currcons); start = (ushort *)pos; /* Contrived structure to try to emulate original need_wrap behaviour * Problems caused when we have need_wrap set on '\n' character */ while (count--) { c = *b++; if (c == 10 || c == 13 || c == 8 || need_wrap) { if (cnt > 0) { if (IS_VISIBLE) sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); x += cnt; if (need_wrap) x--; cnt = 0; } if (c == 8) { /* backspace */ bs(currcons); start = (ushort *)pos; myx = x; continue; } if (c != 13) lf(currcons); cr(currcons); start = (ushort *)pos; myx = x; if (c == 10 || c == 13) continue; } scr_writew((attr << 8) + c, (unsigned short *) pos); cnt++; if (myx == video_num_columns - 1) { need_wrap = 1; continue; } pos+=2; myx++; } if (cnt > 0) { if (IS_VISIBLE) sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); x += cnt; if (x == video_num_columns) { x--; need_wrap = 1; } } set_cursor(currcons);quit: clear_bit(0, &printing);}static kdev_t vt_console_device(struct console *c){ return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);}struct console vt_console_driver = { name: "tty", write: vt_console_print, device: vt_console_device, wait_key: keyboard_wait_for_keypress, unblank: unblank_screen, flags: CON_PRINTBUFFER, index: -1,};#endif/* * Handling of Linux-specific VC ioctls */int tioclinux(struct tty_struct *tty, unsigned long arg){ char type, data; if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) return -EINVAL; if (current->tty != tty && !suser()) return -EPERM; if (get_user(type, (char *)arg)) return -EFAULT; switch (type) { case 2: return set_selection(arg, tty, 1); case 3: return paste_selection(tty); case 4: unblank_screen(); return 0; case 5: return sel_loadlut(arg); case 6: /* * Make it possible to react to Shift+Mousebutton. * Note that 'shift_state' is an undocumented * kernel-internal variable; programs not closely * related to the kernel should not use this. */ data = shift_state;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -