📄 vt.c
字号:
vt = vt_con_data + idx; if ((i = vt_allocate (vt)) < 0) return i; tty->driver_data = vt; if (!tty->winsize.ws_row && !tty->winsize.ws_col) { tty->winsize.ws_row = vtdata.numrows; tty->winsize.ws_col = vtdata.numcolumns; } return 0;}static void vt_vtd_flush_chars (const struct vt *vt, struct vt_struct *vtd){ unsigned long flags; save_flags (flags); if (vtd->xmitting) return; vtd->xmitting = 1; while (1) { int c; cli (); c = MIN(vtd->xmit_cnt, CON_XMIT_SIZE - vtd->xmit_out); if (c <= 0) break; restore_flags (flags); c = vcd_write (vt, 0, vtd->xmit_buf + vtd->xmit_out, c); cli (); if (c <= 0) break; vtd->xmit_out = (vtd->xmit_out + c) & (CON_XMIT_SIZE - 1); vtd->xmit_cnt -= c; } vtd->xmitting = 0; restore_flags (flags); if (*vt->tty) wake_up_interruptible (&(*vt->tty)->write_wait);}static int vt_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count){ static unsigned long last_error = 0; const struct vt *vt = (struct vt *)tty->driver_data; if (vt_allocated (vt)) { if (vt->vtd->xmit_cnt) vt_vtd_flush_chars (vt, vt->vtd); return vcd_write (vt, from_user, buf, count); } if (jiffies > last_error + 10*HZ) { printk ("vt_write: tty %d not allocated\n", vt->num); last_error = jiffies; } return 0;}static void vt_put_char (struct tty_struct *tty, unsigned char ch){ const struct vt *vt = (struct vt *)tty->driver_data; unsigned long flags; if (!vt_allocated (vt)) return; save_flags_cli (flags); if (vt->vtd->xmit_cnt < CON_XMIT_SIZE - 1) { vt->vtd->xmit_buf[vt->vtd->xmit_in++] = ch; vt->vtd->xmit_in &= CON_XMIT_SIZE - 1; vt->vtd->xmit_cnt ++; } restore_flags (flags);}static void vt_flush_chars (struct tty_struct *tty){ const struct vt *vt = (struct vt *)tty->driver_data; if (!vt_allocated (vt) || !vt->vtd->xmit_cnt || tty->stopped) return; vt_vtd_flush_chars (vt, vt->vtd);}static int vt_write_room (struct tty_struct *tty){ const struct vt *vt = (struct vt *)tty->driver_data; int r; if (!vt_allocated (vt)) return 0; r = CON_XMIT_SIZE - vt->vtd->xmit_cnt - 8; /* allow 8 char overflow */ if (r < 0) return 0; else return r;}static int vt_chars_in_buffer (struct tty_struct *tty){ const struct vt *vt = (struct vt *)tty->driver_data; if (!vt_allocated (vt)) return CON_XMIT_SIZE; return vt->vtd->xmit_cnt;}#if 0static void vt_flush_buffer (struct tty_struct *tty){ const struct vt *vt = (struct vt *)tty->driver_data; if (!vt_allocated (vt)) return; cli (); vt->vtd->xmit_cnt = vt->vtd->xmit_out = vt->vtd->xmit_in = 0; sti ();}#endifstatic int vt_ioctl (struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg){ struct vt *vt = tty->driver_data; int perm, i; if (!vt_allocated (vt)) /* impossible ? */ return -ENOIOCTLCMD; /* * To have permissions to do most of the vt ioctls, we either * have to be the owner of the tty, or super-user. */ perm = 0; if (current->tty == tty || suser ()) perm = 1;#define PERM if (!perm) return -EPERM switch (cmd) { case KDGETMODE: i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned long)); if (!i) put_user (vt->vtd->vc_mode, (unsigned long *)arg); return i; case KDSETMODE: PERM; return vt_kdsetmode (vt, arg); case VT_GETMODE: i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (struct vt_mode)); if (i) return i; memcpy_tofs ((void *)arg, &vt->vtd->vt_mode, sizeof (struct vt_mode)); return 0; case VT_SETMODE: { struct vt_mode vtmode; PERM; i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct vt_mode)); if (i) return i; memcpy_fromfs (&vtmode, (void *)arg, sizeof (struct vt_mode)); return vt_setmode (vt, &vtmode); } case VT_GETSTATE: { /* * Returns global VT state. Note that VT 0 is always open, since * it's an alias for the current VT, and people can't use it here. * We cannot return state for more than 16 VTs, since v_state is short. */ struct vt_stat *vtstat = (struct vt_stat *)arg; unsigned short state = 1, mask = 2; i = verify_area (VERIFY_WRITE, vtstat, sizeof (struct vt_stat)); if (i) return i; for (i = 0; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) if (VT_IS_IN_USE(i)) state |= mask; put_user (vtdata.fgconsole->num, &vtstat->v_active); put_user (state, &vtstat->v_state); return 0; } case VT_OPENQRY: /* * Returns the first available (non-open) console */ i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (unsigned long)); if (i) return i; for (i = 0; i < MAX_NR_CONSOLES; i++) if (!VT_IS_IN_USE(i)) break; if (i < MAX_NR_CONSOLES) put_user (i + 1, (unsigned long *)arg); else put_user (-1, (unsigned long *)arg); return 0; case VT_ACTIVATE: PERM; /* * VT activate will cause us to switch to vt #num with num >= 1 * (switches to vt0, our console, are not allowed, just to preserve * sanity) */ if (arg == 0 || arg > MAX_NR_CONSOLES) return -ENXIO; vt = vt_con_data + (arg - 1); i = vt_allocate (vt); if (i) return i; vt_changeconsole (vt); return 0; case VT_WAITACTIVE: PERM; /* * wait until the specified VT has been activated */ if (arg == 0 || arg > MAX_NR_CONSOLES) return -ENXIO; vt = vt_con_data + (arg - 1); while (vt != vtdata.fgconsole) { if (vt_waitonactivate () < 0) return -EINTR; } return 0; case VT_RELDISP: PERM; return vt_reldisp (vt, arg); case VT_RESIZE: { struct vt_sizes *vtsizes = (struct vt_sizes *)arg; ushort ll, cc; PERM; i = verify_area (VERIFY_READ, (void *)vtsizes, sizeof (struct vt_sizes)); if (i) return i; ll = get_user (&vtsizes->v_rows); cc = get_user (&vtsizes->v_cols); return vt_resize (cc, ll); } case KIOCSOUND: PERM; vt_mksound (arg, 72, 5); return 0; case KDMKTONE: { unsigned int freq = get_user ((unsigned long *)arg); unsigned int vol = get_user ((unsigned long *)(arg + 4)); unsigned int ticks = get_user ((unsigned long *)(arg + 8)); PERM; /* * Generate the tone for the apropriate number of ticks. * If time is zero, turn off sound ourselves. */ vt_mksound (freq, vol, ticks); return 0; } case VT_DISALLOCATE: if (arg > MAX_NR_CONSOLES) return -ENXIO; return vt_deallocate (arg); case VT_GETSCRINFO: /* * Get screen dimentions */ i = verify_area (VERIFY_WRITE, (void *)arg, 5 * sizeof (unsigned long)); if (!i) { put_user (0, (unsigned long *)arg); put_user (vtdata.numcolumns * 8, (unsigned long *)(arg + 4)); put_user (vtdata.numrows * 8, (unsigned long *)(arg + 8)); put_user (vtdata.screen.bitsperpix, (unsigned long *)(arg + 12)); /* bpp */#ifndef HAS_VIDC20 put_user (4, (unsigned long *)(arg + 16)); /* depth */#else put_user (8, (unsigned long *)(arg + 16)); /* depth */#endif } return i; case VT_LOCKSWITCH: if (!suser()) return -EPERM; vt_dont_switch = 1; return 0; case VT_UNLOCKSWITCH: if (!suser()) return -EPERM; vt_dont_switch = 0; return 0; case KDMAPDISP: case KDUNMAPDISP: case KDSKBMODE: case KDSKBMETA: case KDSETKEYCODE: case KDSKBENT: case KDSKBSENT: case KDSKBDIACR: case KDSKBLED: case KDSETLED: case KDSIGACCEPT: PERM; case KDGKBTYPE: case KDADDIO: case KDDELIO: case KDENABIO: case KDDISABIO: case KDGKBMODE: case KDGKBMETA: case KDGETKEYCODE: case KDGKBENT: case KDGKBSENT: case KDGKBDIACR: case KDGKBLED: case KDGETLED: return kbd_ioctl (vt, cmd, arg); case VT_SETPALETTE: case PIO_FONT: case PIO_SCRNMAP: case PIO_UNISCRNMAP: case PIO_UNIMAPCLR: case PIO_UNIMAP: PERM; case VT_GETPALETTE: case GIO_FONT: case GIO_SCRNMAP: case GIO_UNISCRNMAP: case GIO_UNIMAP: return vcd_ioctl (vt, cmd, arg); } return -ENOIOCTLCMD;}/* * Turn the Scroll-Lock LED on when the tty is stopped */static void vt_stop (struct tty_struct *tty){ if (tty) { const struct vt *vt = (struct vt *)tty->driver_data; if (vt_allocated (vt)) { set_vc_kbd_led (vt->kbd, VC_SCROLLOCK); set_leds (); } }}/* * Turn the Scroll-Lock LED off when the tty is started */static void vt_start (struct tty_struct *tty){ if (tty) { const struct vt *vt = (struct vt *)tty->driver_data; if (vt_allocated (vt)) { clr_vc_kbd_led (vt->kbd, VC_SCROLLOCK); set_leds (); } if (vt->vtd->xmit_cnt) vt_vtd_flush_chars (vt, vt->vtd); }}/* * vt_throttle and vt_unthrottle are only used for * paste_selection(), which has to stuff in a large number * of characters... */static void vt_throttle (struct tty_struct *tty){}static void vt_unthrottle (struct tty_struct *tty){ const struct vt *vt = (struct vt *)tty->driver_data; if (vt_allocated (vt)) wake_up_interruptible (&vt->vtd->paste_wait);}/* * This is the console switching bottom half handler. * * Doing console switching in a bottom half handler allows * us to do ths switches asynchronously (needed when we want * to switch due to a keyboard interrupt), while still giving * us the option to easily disable it to avoid races when we * need to write to the console. */static void console_bh(void){ if (want_console) { if (want_console != vtdata.fgconsole) { vt_changeconsole(want_console); /* we only changed when the console had already been allocated - a new console is not created in an interrupt routine */ } want_console = NULL; } if (do_poke_blanked_console) { /* do not unblank for a LED change */ do_poke_blanked_console = 0; vt_pokeblankedconsole(); }}/* * We don't have kmalloc setup yet. We just want to get enough up so that printk * can work. * * Basically, we setup the VT structures for tty1. */unsigned long vt_pre_init (unsigned long kmem){ struct vt *vt = vt_con_data; memset (vt_con_data, 0, sizeof (vt_con_data)); vtdata.numcolumns = ORIG_VIDEO_COLS; vtdata.numrows = ORIG_VIDEO_LINES; vtdata.blanked = NULL; vtdata.fgconsole = vt_con_data; vtdata.screen.blankinterval = 10*60*HZ; vtdata.select.vt = NULL; vtdata.select.start = -1; vtdata.select.end = 0; vtdata.select.buffer = NULL; vt->vcd = (struct con_struct *)kmem; kmem += sizeof (struct con_struct); vt->kbd = (struct kbd_struct *)kmem; kmem += sizeof (struct kbd_struct); vt->vtd = (struct vt_struct *)kmem; kmem += sizeof (struct vt_struct); vt->vtd->xmit_buf = (unsigned char *)kmem; kmem += CON_XMIT_SIZE; vt->vtd->xmitting = vt->vtd->xmit_cnt = vt->vtd->xmit_out = vt->vtd->xmit_in = 0; vt->tty = &vt_table[0]; vt->num = 1; /* * vcd_init is called inside vcd_pre_init */ kbd_struct_init (vt, 0); vt_reset (vt); vt->allocinit = 1; kmem = vcd_pre_init (kmem, vt); init_bh(CONSOLE_BH, console_bh); return kmem;}/* * This is the post initialisation. We have kmalloc setup so we can use it... */void vt_post_init (void){ int i; memset (&vt_driver, 0, sizeof (struct tty_driver)); vt_driver.magic = TTY_DRIVER_MAGIC; vt_driver.name = "tty"; vt_driver.name_base = 1; vt_driver.major = TTY_MAJOR; vt_driver.minor_start = 1; vt_driver.num = MAX_NR_CONSOLES; vt_driver.type = TTY_DRIVER_TYPE_CONSOLE; vt_driver.init_termios = tty_std_termios; vt_driver.flags = TTY_DRIVER_REAL_RAW; vt_driver.refcount = &vt_refcount; vt_driver.table = vt_table; vt_driver.termios = vt_termios; vt_driver.termios_locked = vt_termios_locked; vt_driver.open = vt_open; vt_driver.write = vt_write; vt_driver.put_char = vt_put_char; vt_driver.flush_chars = vt_flush_chars; vt_driver.write_room = vt_write_room; vt_driver.chars_in_buffer = vt_chars_in_buffer;#if 0 vt_driver.flush_buffer = vt_flush_buffer;#endif vt_driver.ioctl = vt_ioctl; vt_driver.stop = vt_stop; vt_driver.start = vt_start; vt_driver.throttle = vt_throttle; vt_driver.unthrottle = vt_unthrottle; for (i = 1; i < MAX_NR_CONSOLES; i++) { struct vt *vt = vt_con_data + i; vt->tty = &vt_table[i]; vt->num = i + 1; vt->allocinit = 0; if (i < MIN_NR_CONSOLES) vt_allocate (vt); } if (tty_register_driver (&vt_driver)) panic ("Couldn't register console driver"); timer_table[BLANK_TIMER].fn = vt_blankscreen; if (vtdata.screen.blankinterval) { timer_table[BLANK_TIMER].expires = jiffies + vtdata.screen.blankinterval; timer_active |= 1 << BLANK_TIMER; } else timer_table[BLANK_TIMER].expires = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -