vt_ioctl.c
来自「linux 内核源代码」· C语言 代码 · 共 1,305 行 · 第 1/3 页
C
1,305 行
acquire_console_sem(); for (i=1; i<MAX_NR_CONSOLES; i++) if (! VT_BUSY(i)) vc_deallocate(i); release_console_sem(); } else { /* deallocate a single console, if possible */ arg--; if (VT_BUSY(arg)) return -EBUSY; if (arg) { /* leave 0 */ acquire_console_sem(); vc_deallocate(arg); release_console_sem(); } } return 0; case VT_RESIZE: { struct vt_sizes __user *vtsizes = up; struct vc_data *vc; ushort ll,cc; if (!perm) return -EPERM; if (get_user(ll, &vtsizes->v_rows) || get_user(cc, &vtsizes->v_cols)) return -EFAULT; for (i = 0; i < MAX_NR_CONSOLES; i++) { vc = vc_cons[i].d; if (vc) { vc->vc_resize_user = 1; vc_lock_resize(vc_cons[i].d, cc, ll); } } return 0; } case VT_RESIZEX: { struct vt_consize __user *vtconsize = up; ushort ll,cc,vlin,clin,vcol,ccol; if (!perm) return -EPERM; if (!access_ok(VERIFY_READ, vtconsize, sizeof(struct vt_consize))) return -EFAULT; __get_user(ll, &vtconsize->v_rows); __get_user(cc, &vtconsize->v_cols); __get_user(vlin, &vtconsize->v_vlin); __get_user(clin, &vtconsize->v_clin); __get_user(vcol, &vtconsize->v_vcol); __get_user(ccol, &vtconsize->v_ccol); vlin = vlin ? vlin : vc->vc_scan_lines; if (clin) { if (ll) { if (ll != vlin/clin) return -EINVAL; /* Parameters don't add up */ } else ll = vlin/clin; } if (vcol && ccol) { if (cc) { if (cc != vcol/ccol) return -EINVAL; } else cc = vcol/ccol; } if (clin > 32) return -EINVAL; for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons[i].d) continue; acquire_console_sem(); if (vlin) vc_cons[i].d->vc_scan_lines = vlin; if (clin) vc_cons[i].d->vc_font.height = clin; vc_cons[i].d->vc_resize_user = 1; vc_resize(vc_cons[i].d, cc, ll); release_console_sem(); } return 0; } case PIO_FONT: { if (!perm) return -EPERM; op.op = KD_FONT_OP_SET; op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ op.width = 8; op.height = 0; op.charcount = 256; op.data = up; return con_font_op(vc_cons[fg_console].d, &op); } case GIO_FONT: { op.op = KD_FONT_OP_GET; op.flags = KD_FONT_FLAG_OLD; op.width = 8; op.height = 32; op.charcount = 256; op.data = up; return con_font_op(vc_cons[fg_console].d, &op); } case PIO_CMAP: if (!perm) return -EPERM; return con_set_cmap(up); case GIO_CMAP: return con_get_cmap(up); case PIO_FONTX: case GIO_FONTX: return do_fontx_ioctl(cmd, up, perm, &op); case PIO_FONTRESET: { if (!perm) return -EPERM;#ifdef BROKEN_GRAPHICS_PROGRAMS /* With BROKEN_GRAPHICS_PROGRAMS defined, the default font is not saved. */ return -ENOSYS;#else { op.op = KD_FONT_OP_SET_DEFAULT; op.data = NULL; i = con_font_op(vc_cons[fg_console].d, &op); if (i) return i; con_set_default_unimap(vc_cons[fg_console].d); return 0; }#endif } case KDFONTOP: { if (copy_from_user(&op, up, sizeof(op))) return -EFAULT; if (!perm && op.op != KD_FONT_OP_GET) return -EPERM; i = con_font_op(vc, &op); if (i) return i; if (copy_to_user(up, &op, sizeof(op))) return -EFAULT; return 0; } case PIO_SCRNMAP: if (!perm) return -EPERM; return con_set_trans_old(up); case GIO_SCRNMAP: return con_get_trans_old(up); case PIO_UNISCRNMAP: if (!perm) return -EPERM; return con_set_trans_new(up); case GIO_UNISCRNMAP: return con_get_trans_new(up); case PIO_UNIMAPCLR: { struct unimapinit ui; if (!perm) return -EPERM; i = copy_from_user(&ui, up, sizeof(struct unimapinit)); if (i) return -EFAULT; con_clear_unimap(vc, &ui); return 0; } case PIO_UNIMAP: case GIO_UNIMAP: return do_unimap_ioctl(cmd, up, perm, vc); case VT_LOCKSWITCH: if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; vt_dont_switch = 1; return 0; case VT_UNLOCKSWITCH: if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; vt_dont_switch = 0; return 0; case VT_GETHIFONTMASK: return put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg); default: return -ENOIOCTLCMD; }}/* * Sometimes we want to wait until a particular VT has been activated. We * do it in a very simple manner. Everybody waits on a single queue and * get woken up at once. Those that are satisfied go on with their business, * while those not ready go back to sleep. Seems overkill to add a wait * to each vt just for this - usually this does nothing! */static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue);/* * Sleeps until a vt is activated, or the task is interrupted. Returns * 0 if activation, -EINTR if interrupted by a signal handler. */int vt_waitactive(int vt){ int retval; DECLARE_WAITQUEUE(wait, current); add_wait_queue(&vt_activate_queue, &wait); for (;;) { retval = 0; /* * Synchronize with redraw_screen(). By acquiring the console * semaphore we make sure that the console switch is completed * before we return. If we didn't wait for the semaphore, we * could return at a point where fg_console has already been * updated, but the console switch hasn't been completed. */ acquire_console_sem(); set_current_state(TASK_INTERRUPTIBLE); if (vt == fg_console) { release_console_sem(); break; } release_console_sem(); retval = -ERESTARTNOHAND; if (signal_pending(current)) break; schedule(); } remove_wait_queue(&vt_activate_queue, &wait); __set_current_state(TASK_RUNNING); return retval;}#define vt_wake_waitactive() wake_up(&vt_activate_queue)void reset_vc(struct vc_data *vc){ vc->vc_mode = KD_TEXT; kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; vc->vt_mode.mode = VT_AUTO; vc->vt_mode.waitv = 0; vc->vt_mode.relsig = 0; vc->vt_mode.acqsig = 0; vc->vt_mode.frsig = 0; put_pid(vc->vt_pid); vc->vt_pid = NULL; vc->vt_newvt = -1; if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ reset_palette(vc);}void vc_SAK(struct work_struct *work){ struct vc *vc_con = container_of(work, struct vc, SAK_work); struct vc_data *vc; struct tty_struct *tty; acquire_console_sem(); vc = vc_con->d; if (vc) { tty = vc->vc_tty; /* * SAK should also work in all raw modes and reset * them properly. */ if (tty) __do_SAK(tty); reset_vc(vc); } release_console_sem();}/* * Performs the back end of a vt switch */static void complete_change_console(struct vc_data *vc){ unsigned char old_vc_mode; last_console = fg_console; /* * If we're switching, we could be going from KD_GRAPHICS to * KD_TEXT mode or vice versa, which means we need to blank or * unblank the screen later. */ old_vc_mode = vc_cons[fg_console].d->vc_mode; switch_screen(vc); /* * This can't appear below a successful kill_pid(). If it did, * then the *blank_screen operation could occur while X, having * received acqsig, is waking up on another processor. This * condition can lead to overlapping accesses to the VGA range * and the framebuffer (causing system lockups). * * To account for this we duplicate this code below only if the * controlling process is gone and we've called reset_vc. */ if (old_vc_mode != vc->vc_mode) { if (vc->vc_mode == KD_TEXT) do_unblank_screen(1); else do_blank_screen(1); } /* * If this new console is under process control, send it a signal * telling it that it has acquired. Also check if it has died and * clean up (similar to logic employed in change_console()) */ if (vc->vt_mode.mode == VT_PROCESS) { /* * Send the signal as privileged - kill_pid() will * tell us if the process has gone or something else * is awry */ if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { /* * The controlling process has died, so we revert back to * normal operation. In this case, we'll also change back * to KD_TEXT mode. I'm not sure if this is strictly correct * but it saves the agony when the X server dies and the screen * remains blanked due to KD_GRAPHICS! It would be nice to do * this outside of VT_PROCESS but there is no single process * to account for and tracking tty count may be undesirable. */ reset_vc(vc); if (old_vc_mode != vc->vc_mode) { if (vc->vc_mode == KD_TEXT) do_unblank_screen(1); else do_blank_screen(1); } } } /* * Wake anyone waiting for their VT to activate */ vt_wake_waitactive(); return;}/* * Performs the front-end of a vt switch */void change_console(struct vc_data *new_vc){ struct vc_data *vc; if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch) return; /* * If this vt is in process mode, then we need to handshake with * that process before switching. Essentially, we store where that * vt wants to switch to and wait for it to tell us when it's done * (via VT_RELDISP ioctl). * * We also check to see if the controlling process still exists. * If it doesn't, we reset this vt to auto mode and continue. * This is a cheap way to track process control. The worst thing * that can happen is: we send a signal to a process, it dies, and * the switch gets "lost" waiting for a response; hopefully, the * user will try again, we'll detect the process is gone (unless * the user waits just the right amount of time :-) and revert the * vt to auto control. */ vc = vc_cons[fg_console].d; if (vc->vt_mode.mode == VT_PROCESS) { /* * Send the signal as privileged - kill_pid() will * tell us if the process has gone or something else * is awry. * * We need to set vt_newvt *before* sending the signal or we * have a race. */ vc->vt_newvt = new_vc->vc_num; if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { /* * It worked. Mark the vt to switch to and * return. The process needs to send us a * VT_RELDISP ioctl to complete the switch. */ return; } /* * The controlling process has died, so we revert back to * normal operation. In this case, we'll also change back * to KD_TEXT mode. I'm not sure if this is strictly correct * but it saves the agony when the X server dies and the screen * remains blanked due to KD_GRAPHICS! It would be nice to do * this outside of VT_PROCESS but there is no single process * to account for and tracking tty count may be undesirable. */ reset_vc(vc); /* * Fall through to normal (VT_AUTO) handling of the switch... */ } /* * Ignore all switches in KD_GRAPHICS+VT_AUTO mode */ if (vc->vc_mode == KD_GRAPHICS) return; complete_change_console(new_vc);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?