📄 console.c
字号:
set_leds();}/* * Turn the Scroll-Lock LED off when the console is started */static void con_start(struct tty_struct *tty){ int console_num; if (!tty) return; console_num = MINOR(tty->device) - (tty->driver.minor_start); if (!vc_cons_allocated(console_num)) return; clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); set_leds();}static void con_flush_chars(struct tty_struct *tty){ struct vt_struct *vt = (struct vt_struct *)tty->driver_data; set_cursor(vt->vc_num);}/* * Allocate the console screen memory. */static int con_open(struct tty_struct *tty, struct file * filp){ unsigned int currcons; int i; currcons = MINOR(tty->device) - tty->driver.minor_start; i = vc_allocate(currcons); if (i) return i; vt_cons[currcons]->vc_num = currcons; tty->driver_data = vt_cons[currcons]; if (!tty->winsize.ws_row && !tty->winsize.ws_col) { tty->winsize.ws_row = video_num_lines; tty->winsize.ws_col = video_num_columns; } return 0;}static void con_close(struct tty_struct *tty, struct file * filp){ if (tty->count == 1) tty->driver_data = 0;}static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear){ int j, k ; video_num_columns = cols; video_num_lines = rows; video_size_row = cols<<1; screenbuf_size = video_num_lines * video_size_row; set_origin(currcons); pos = origin; reset_vc(currcons); for (j=k=0; j<16; j++) { vc_cons[currcons].d->vc_palette[k++] = default_red[j] ; vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ; vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ; } def_color = 0x07; /* white */ ulcolor = 0x0f; /* bold white */ halfcolor = 0x08; /* grey */ vt_cons[currcons]->paste_wait = 0; reset_terminal(currcons, do_clear);}/* * This routine initializes console interrupts, and does nothing * else. If you want the screen to clear, call tty_write with * the appropriate escape-sequence. */struct tty_driver console_driver;static int console_refcount;__initfunc(unsigned long con_init(unsigned long kmem_start)){ const char *display_desc = NULL; unsigned int currcons = 0; if (conswitchp) display_desc = conswitchp->con_startup(); if (!display_desc) { fg_console = 0; return kmem_start; } memset(&console_driver, 0, sizeof(struct tty_driver)); console_driver.magic = TTY_DRIVER_MAGIC; console_driver.name = "tty"; console_driver.name_base = 1; console_driver.major = TTY_MAJOR; console_driver.minor_start = 1; console_driver.num = MAX_NR_CONSOLES; console_driver.type = TTY_DRIVER_TYPE_CONSOLE; console_driver.init_termios = tty_std_termios; console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; console_driver.refcount = &console_refcount; console_driver.table = console_table; console_driver.termios = console_termios; console_driver.termios_locked = console_termios_locked; console_driver.open = con_open; console_driver.close = con_close; console_driver.write = con_write; console_driver.write_room = con_write_room; console_driver.put_char = con_put_char; console_driver.flush_chars = con_flush_chars; console_driver.chars_in_buffer = con_chars_in_buffer; console_driver.ioctl = vt_ioctl; console_driver.stop = con_stop; console_driver.start = con_start; console_driver.throttle = con_throttle; console_driver.unthrottle = con_unthrottle; if (tty_register_driver(&console_driver)) panic("Couldn't register console driver\n"); timer_table[BLANK_TIMER].fn = blank_screen; timer_table[BLANK_TIMER].expires = 0; if (blankinterval) { timer_table[BLANK_TIMER].expires = jiffies + blankinterval; timer_active |= 1<<BLANK_TIMER; } /* Unfortunately, kmalloc is not running yet */ /* Due to kmalloc roundup allocating statically is more efficient - so provide MIN_NR_CONSOLES for people with very little memory */ for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { int j, k ; vc_cons[currcons].d = (struct vc_data *) kmem_start; kmem_start += sizeof(struct vc_data); vt_cons[currcons] = (struct vt_struct *) kmem_start; kmem_start += sizeof(struct vt_struct); visual_init(currcons, 1); screenbuf = (unsigned short *) kmem_start; kmem_start += screenbuf_size; kmalloced = 0; vc_init(currcons, video_num_lines, video_num_columns, currcons || !sw->con_save_screen); for (j=k=0; j<16; j++) { vc_cons[currcons].d->vc_palette[k++] = default_red[j] ; vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ; vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ; } } currcons = fg_console = 0; master_display_fg = vc_cons[currcons].d; set_origin(currcons); save_screen(currcons); gotoxy(currcons,x,y); csi_J(currcons, 0); update_screen(fg_console); printk("Console: %s %s %dx%d", can_do_color ? "colour" : "mono", display_desc, video_num_columns, video_num_lines); printable = 1; printk("\n");#ifdef CONFIG_VT_CONSOLE register_console(&vt_console_driver);#endif init_bh(CONSOLE_BH, console_bh); return kmem_start;}#ifndef VT_SINGLE_DRIVERstatic void clear_buffer_attributes(int currcons){ unsigned short *p = (unsigned short *) origin; int count = screenbuf_size/2; int mask = hi_font_mask | 0xff; for (; count > 0; count--, p++) { scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p); }}/* * If we support more console drivers, this function is used * when a driver wants to take over some existing consoles * and become default driver for newly opened ones. */void take_over_console(struct consw *csw, int first, int last, int deflt){ int i, j = -1; const char *desc; desc = csw->con_startup(); if (!desc) return; if (deflt) conswitchp = csw; for (i = first; i <= last; i++) { int old_was_color; int currcons = i; con_driver_map[i] = csw; if (!vc_cons[i].d || !vc_cons[i].d->vc_sw) continue; j = i; if (IS_VISIBLE) save_screen(i); old_was_color = vc_cons[i].d->vc_can_do_color; vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d); visual_init(i, 0); update_attr(i); /* If the console changed between mono <-> color, then * the attributes in the screenbuf will be wrong. The * following resets all attributes to something sane. */ if (old_was_color != vc_cons[i].d->vc_can_do_color) clear_buffer_attributes(i); if (IS_VISIBLE) update_screen(i); } printk("Console: switching "); if (!deflt) printk("consoles %d-%d ", first+1, last+1); if (j >= 0) printk("to %s %s %dx%d\n", vc_cons[j].d->vc_can_do_color ? "colour" : "mono", desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows); else printk("to %s\n", desc);}void give_up_console(struct consw *csw){ int i; for(i = 0; i < MAX_NR_CONSOLES; i++) if (con_driver_map[i] == csw) con_driver_map[i] = NULL;}#endif/* * Screen blanking */static void set_vesa_blanking(unsigned long arg){ char *argp = (char *)arg + 1; unsigned int mode; get_user(mode, argp); vesa_blank_mode = (mode < 4) ? mode : 0;}static void vesa_powerdown(void){ struct vc_data *c = vc_cons[fg_console].d; /* * Power down if currently suspended (1 or 2), * suspend if currently blanked (0), * else do nothing (i.e. already powered down (3)). * Called only if powerdown features are allowed. */ switch (vesa_blank_mode) { case VESA_NO_BLANKING: c->vc_sw->con_blank(c, VESA_VSYNC_SUSPEND+1); break; case VESA_VSYNC_SUSPEND: case VESA_HSYNC_SUSPEND: c->vc_sw->con_blank(c, VESA_POWERDOWN+1); break; }}static void vesa_powerdown_screen(void){ timer_active &= ~(1<<BLANK_TIMER); timer_table[BLANK_TIMER].fn = unblank_screen; vesa_powerdown();}void do_blank_screen(int entering_gfx){ int currcons = fg_console; int i; if (console_blanked) return; /* entering graphics mode? */ if (entering_gfx) { hide_cursor(currcons); save_screen(currcons); sw->con_blank(vc_cons[currcons].d, -1); console_blanked = fg_console + 1; set_origin(currcons); return; } /* don't blank graphics */ if (vcmode != KD_TEXT) { console_blanked = fg_console + 1; return; } hide_cursor(currcons); if (vesa_off_interval) { timer_table[BLANK_TIMER].fn = vesa_powerdown_screen; timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval; timer_active |= (1<<BLANK_TIMER); } else { timer_active &= ~(1<<BLANK_TIMER); timer_table[BLANK_TIMER].fn = unblank_screen; } save_screen(currcons); /* In case we need to reset origin, blanking hook returns 1 */ i = sw->con_blank(vc_cons[currcons].d, 1); console_blanked = fg_console + 1; if (i) set_origin(currcons);#ifdef CONFIG_APM if (apm_display_blank()) return;#endif if (vesa_blank_mode) sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1);}void unblank_screen(void){ int currcons; if (!console_blanked) return; if (!vc_cons_allocated(fg_console)) { /* impossible */ printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); return; } timer_table[BLANK_TIMER].fn = blank_screen; if (blankinterval) { timer_table[BLANK_TIMER].expires = jiffies + blankinterval; timer_active |= 1<<BLANK_TIMER; } currcons = fg_console; console_blanked = 0;#ifdef CONFIG_APM apm_display_unblank();#endif if (sw->con_blank(vc_cons[currcons].d, 0)) /* Low-level driver cannot restore -> do it ourselves */ update_screen(fg_console); set_cursor(fg_console);}static void blank_screen(void){ do_blank_screen(0);}void poke_blanked_console(void){ timer_active &= ~(1<<BLANK_TIMER); if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) return; if (console_blanked) { timer_table[BLANK_TIMER].fn = unblank_screen; timer_table[BLANK_TIMER].expires = jiffies; /* Now */ timer_active |= 1<<BLANK_TIMER; } else if (blankinterval) { timer_table[BLANK_TIMER].expires = jiffies + blankinterval; timer_active |= 1<<BLANK_TIMER; }}/* * Palettes */void set_palette(int currcons){ if (vcmode != KD_GRAPHICS) sw->con_set_palette(vc_cons[currcons].d, color_table);}static int set_get_cmap(unsigned char *arg, int set){ int i, j, k; for (i = 0; i < 16; i++) if (set) { get_user(default_red[i], arg++); get_user(default_grn[i], arg++); get_user(default_blu[i], arg++); } else { put_user(default_red[i], arg++); put_user(default_grn[i], arg++); put_user(default_blu[i], arg++); } if (set) { for (i = 0; i < MAX_NR_CONSOLES; i++) if (vc_cons_allocated(i)) { for (j = k = 0; j < 16; j++) { vc_cons[i].d->vc_palette[k++] = default_red[j]; vc_cons[i].d->vc_palette[k++] = default_grn[j]; vc_cons[i].d->vc_palette[k++] = default_blu[j]; } set_palette(i); } } return 0;}/* * Load palette into the DAC registers. arg points to a colour * map, 3 bytes per colour, 16 colours, range from 0 to 255. */int con_set_cmap(unsigned char *arg){ return set_get_cmap (arg,1);}int con_get_cmap(unsigned char *arg){ return set_get_cmap (arg,0);}void reset_palette(int currcons){ int j, k; for (j=k=0; j<16; j++) { palette[k++] = default_red[j]; palette[k++] = default_grn[j]; palette[k++] = default_blu[j]; } set_palette(currcons);}/* * Font switching * * Currently we only support fonts up to 32 pixels wide, at a maximum height * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, * depending on width) reserved for each character which is kinda wasty, but * this is done in order to maintain compatibility with the EGA/VGA fonts. It * is upto the actual low-level console-driver convert data into its favorite * format (maybe we should add a `fontoffset' field to the `display' * structure so we wont have to convert the fontdata all the time. * /Jes */#define max_font_size 65536int con_font_op(int currcons, struct console_font_op *op){ int rc = -EINVAL; int size = max_font_size, set; u8 *temp = NULL; struct console_font_op old_op; if (vt_cons[currcons]->vc_mode != KD_TEXT) goto quit; memcpy(&old_op, op, sizeof(old_op)); if (op->op == KD_FONT_OP_SET) { if (!op->data) return -EINVAL; if (op->charcount > 512) goto quit; if (!op->height) { /* Need to guess font height [compat] */ int h, i; u8 *charmap = op->data, tmp; /* If from KDFONTOP ioctl, don't allow things which can be done in userland, so that we can get rid of this soon */ if (!(op->flags & KD_FONT_FLAG_OLD)) goto quit; rc = -EFAULT; for (h = 32; h > 0; h--) for (i = 0; i < op->charcount; i++) { if (get_user(tmp, &charmap[32*i+h-1])) goto quit; if (tmp) goto nonzero; } rc = -EINVAL; goto quit; nonzero: rc = -EINVAL; op->height = h; } if (op->width > 32 || op->height > 32) goto quit; size = (op->width+7)/8 * 32 * op->charcount; if (size > max_font_size) return -ENOSPC; set = 1; } else if (op->op == KD_FONT_OP_GET) set = 0; else return sw->con_font_op(vc_cons[currcons].d, op); if (op->data) { temp = kmalloc(size, GFP_KERNEL); if (!temp) return -ENOMEM; if (set && copy_from_user(temp, op->data, size)) { rc = -EFAULT; goto quit; } op->data = temp; } disable_bh(CONSOLE_BH); rc = sw->con_font_op(vc_cons[currcons].d, op); enable_bh(CONSOLE_BH); op->data = old_op.data; if (!rc && !set) { int c = (op->width+7)/8 * 32 * op->charcount; if (op->data && op->charcount > old_op.charcount) rc = -ENOSPC; if (!(op->flags & KD_FONT_FLAG_OLD)) { if (op->width > old_op.width || op->height > old_op.height) rc = -ENOSPC; } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -