vt_ioctl.c revision 8c9a9dd0fa3a269d380eaae2dc1bee39e865fae1
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  linux/drivers/char/vt_ioctl.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 1992 obz under the linux copyright
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Some code moved for less code duplication - Andi Kleen - Mar 1997
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kd.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vt.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h>
2604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault#include <linux/consolemap.h>
277ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl#include <linux/signal.h>
28bcc8ca09920755520ba8a1e2d9f72fe8ff892643Emmanuel Colbus#include <linux/timex.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kbd_kern.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vt_kern.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kbd_diacr.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/selection.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38b257bc051f06607beb3004d9a1c297085e728becAndrew Johnsonchar vt_dont_switch;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern struct tty_driver *console_driver;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VT_IS_IN_USE(i)	(console_driver->ttys[i] && console_driver->ttys[i]->count)
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VT_BUSY(i)	(VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * experimentation and study of X386 SYSV handling.
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the current console is done by the main ioctl code.
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/syscalls.h>
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void complete_change_console(struct vc_data *vc);
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * these are the valid i/o ports we're allowed to change. they map all the
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * video ports
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GPFIRST 0x3b4
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GPLAST 0x3df
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GPNUM (GPLAST - GPFIRST + 1)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define i (tmp.kb_index)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define s (tmp.kb_table)
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define v (tmp.kb_value)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kbentry tmp;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort *key_map, val, ov;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
83e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti	if (!capable(CAP_SYS_TTY_CONFIG))
84e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti		perm = 0;
85e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBENT:
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key_map = key_maps[s];
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (key_map) {
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    val = U(key_map[i]);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val = K_HOLE;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    val = (i ? K_HOLE : K_NOSUCHMAP);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return put_user(val, &user_kbe->kb_value);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBENT:
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!i && v == K_NOSUCHMAP) {
100ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox			/* deallocate map */
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			key_map = key_maps[s];
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (s && key_map) {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    key_maps[s] = NULL;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    if (key_map[0] == U(K_ALLOCATED)) {
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					kfree(key_map);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					keymap_count--;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    }
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (KTYP(v) < NR_TYPES) {
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (KVAL(v) > max_vals[KTYP(v)])
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EINVAL;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (kbd->kbdmode != VC_UNICODE)
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EINVAL;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ++Geert: non-PC keyboards may generate keycode zero */
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if !defined(__mc68000__) && !defined(__powerpc__)
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* assignment to entry 0 only tests validity of args */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!i)
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(key_map = key_maps[s])) {
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int j;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    !capable(CAP_SYS_RESOURCE))
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EPERM;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1335cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day			key_map = kmalloc(sizeof(plain_map),
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						     GFP_KERNEL);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!key_map)
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			key_maps[s] = key_map;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			key_map[0] = U(K_ALLOCATED);
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (j = 1; j < NR_KEYS; j++)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				key_map[j] = U(K_HOLE);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			keymap_count++;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ov = U(key_map[i]);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (v == ov)
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;	/* nothing to do */
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Attention Key.
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key_map[i] = U(v);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			compute_shiftstate();
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef i
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef s
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef v
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kbkeycode tmp;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int kc = 0;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGETKEYCODE:
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kc = getkeycode(tmp.scancode);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (kc >= 0)
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kc = put_user(kc, &user_kbkc->keycode);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSETKEYCODE:
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kc = setkeycode(tmp.scancode, tmp.keycode);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return kc;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kbsentry *kbs;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *p;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char *q;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char __user *up;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sz;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int delta;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *first_free, *fj, *fnw;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, k;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1980b360adbdb54d5b98b78d57ba0916bc4b8871968Andrew Morton	if (!capable(CAP_SYS_TTY_CONFIG))
199e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti		perm = 0;
2000b360adbdb54d5b98b78d57ba0916bc4b8871968Andrew Morton
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!kbs) {
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto reterr;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we mostly copy too much here (512bytes), but who cares ;) */
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EFAULT;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto reterr;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = kbs->kb_func;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBSENT:
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sz = sizeof(kbs->kb_string) - 1; /* sz should have been
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  a struct member */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up = user_kdgkb->kb_string;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p = func_table[i];
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(p)
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for ( ; *p && sz; p++, sz--)
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (put_user(*p, up++)) {
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ret = -EFAULT;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto reterr;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (put_user('\0', up)) {
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = -EFAULT;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto reterr;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(kbs);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ((p && *p) ? -EOVERFLOW : 0);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBSENT:
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm) {
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = -EPERM;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto reterr;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q = func_table[i];
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		first_free = funcbufptr + (funcbufsize - funcbufleft);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (j < MAX_NR_FUNC)
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fj = func_table[j];
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fj = first_free;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (delta <= funcbufleft) { 	/* it fits in current buf */
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (j < MAX_NR_FUNC) {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memmove(fj + delta, fj, first_free - fj);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (k = j; k < MAX_NR_FUNC; k++)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    if (func_table[k])
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func_table[k] += delta;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    }
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (!q)
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      func_table[i] = fj;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    funcbufleft -= delta;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {			/* allocate a larger buffer */
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    sz = 256;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    while (sz < funcbufsize - funcbufleft + delta)
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      sz <<= 1;
2635cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day		    fnw = kmalloc(sz, GFP_KERNEL);
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if(!fnw) {
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      ret = -ENOMEM;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      goto reterr;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    }
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (!q)
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      func_table[i] = fj;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (fj > funcbufptr)
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memmove(fnw, funcbufptr, fj - funcbufptr);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    for (k = 0; k < j; k++)
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      if (func_table[k])
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func_table[k] = fnw + (func_table[k] - funcbufptr);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (first_free > fj) {
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (k = j; k < MAX_NR_FUNC; k++)
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  if (func_table[k])
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    }
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (funcbufptr != func_buf)
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      kfree(funcbufptr);
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    funcbufptr = fnw;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    funcbufleft = funcbufleft - delta + sz - funcbufsize;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    funcbufsize = sz;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(func_table[i], kbs->kb_string);
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = 0;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreterr:
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(kbs);
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct consolefontdesc cfdarg;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc)))
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_FONTX:
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->op = KD_FONT_OP_SET;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->flags = KD_FONT_FLAG_OLD;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->width = 8;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->height = cfdarg.charheight;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->charcount = cfdarg.charcount;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->data = cfdarg.chardata;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return con_font_op(vc_cons[fg_console].d, op);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_FONTX: {
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->op = KD_FONT_OP_GET;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->flags = KD_FONT_FLAG_OLD;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->width = 8;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->height = cfdarg.charheight;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->charcount = cfdarg.charcount;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->data = cfdarg.chardata;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = con_font_op(vc_cons[fg_console].d, op);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i)
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return i;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfdarg.charheight = op->height;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfdarg.charcount = op->charcount;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct unimapdesc tmp;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&tmp, user_ud, sizeof tmp))
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tmp.entries)
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!access_ok(VERIFY_WRITE, tmp.entries,
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp.entry_ct*sizeof(struct unipair)))
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_UNIMAP:
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_UNIMAP:
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm && fg_console != vc->vc_num)
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We handle the console-specific ioctl's here.  We allow the
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * capability to modify any console, not just the fg_console.
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint vt_ioctl(struct tty_struct *tty, struct file * file,
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     unsigned int cmd, unsigned long arg)
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct vc_data *vc = (struct vc_data *)tty->driver_data;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct console_font_op op;	/* used in multiple places here */
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kbd_struct * kbd;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int console;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char ucval;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __user *up = (void __user *)arg;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, perm;
3769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	int ret = 0;
3779cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	console = vc->vc_num;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3809cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	lock_kernel();
3819cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox
3829cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	if (!vc_cons_allocated(console)) { 	/* impossible? */
3839cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = -ENOIOCTLCMD;
3849cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		goto out;
3859cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	}
3869cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * To have permissions to do most of the vt ioctls, we either have
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	perm = 0;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		perm = 1;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd = kbd_table + console;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KIOCSOUND:
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
4009cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg)
402bcc8ca09920755520ba8a1e2d9f72fe8ff892643Emmanuel Colbus			arg = CLOCK_TICK_RATE / arg;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kd_mksound(arg, 0);
4049cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDMKTONE:
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
4089cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int ticks, count;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Generate the tone for the appropriate number of ticks.
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * If the time is zero, turn off sound ourselves.
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = ticks ? (arg & 0xffff) : 0;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (count)
419bcc8ca09920755520ba8a1e2d9f72fe8ff892643Emmanuel Colbus			count = CLOCK_TICK_RATE / count;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kd_mksound(count, ticks);
4219cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBTYPE:
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this is naive.
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = KB_101;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto setchar;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * These cannot be implemented on any machine that implements
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ioperm() in user level (such as Alpha PCs) or not at all.
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * XXX: you should never use these, just call ioperm directly..
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDADDIO:
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDDELIO:
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * KDADDIO and KDDELIO may be able to add ports beyond what
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * we reject here, but to be safe...
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4449cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (arg < GPFIRST || arg > GPLAST) {
4459cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
4469cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
4479cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
4489cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
4499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDENABIO:
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDDISABIO:
4539cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = sys_ioperm(GPFIRST, GPNUM,
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  (cmd == KDENABIO)) ? -ENXIO : 0;
4559cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDKBDREP:
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct kbd_repeat kbrep;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_SYS_TTY_CONFIG))
4659cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4679cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
4689cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret =  -EFAULT;
4699cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
4709cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
4719cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = kbd_rate(&kbrep);
4729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (ret)
4739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
4759cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
4769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSETMODE:
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * currently, setting the mode from KD_TEXT to KD_GRAPHICS
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * doesn't do a whole lot. i'm not sure if it should do any
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * restoration of modes or what...
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * XXX It should at least call into the driver, fbdev's definitely
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * need to restore their engine state. --BenH
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
4899cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (arg) {
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case KD_GRAPHICS:
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case KD_TEXT0:
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case KD_TEXT1:
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			arg = KD_TEXT;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case KD_TEXT:
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
4999cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
5009cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto out;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (vc->vc_mode == (unsigned char) arg)
5039cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vc->vc_mode = (unsigned char) arg;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (console != fg_console)
5069cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * explicitly blank/unblank the screen if switching modes
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acquire_console_sem();
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg == KD_TEXT)
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_unblank_screen(1);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_blank_screen(1);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_console_sem();
5169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGETMODE:
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = vc->vc_mode;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto setint;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDMAPDISP:
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDUNMAPDISP:
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * these work like a combination of mmap and KDENABIO.
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this could be easily finished.
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5289cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = -EINVAL;
5299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBMODE:
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
5339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(arg) {
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_RAW:
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kbd->kbdmode = VC_RAW;
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_MEDIUMRAW:
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kbd->kbdmode = VC_MEDIUMRAW;
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_XLATE:
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kbd->kbdmode = VC_XLATE;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			compute_shiftstate();
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_UNICODE:
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kbd->kbdmode = VC_UNICODE;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			compute_shiftstate();
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  default:
5509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
5519cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto out;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_ldisc_flush(tty);
5549cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBMODE:
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 K_XLATE);
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto setint;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* this could be folded into KDSKBMODE, but for compatibility
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBMETA:
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(arg) {
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_METABIT:
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			clr_vc_kbd_mode(kbd, VC_META);
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_ESCPREFIX:
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_vc_kbd_mode(kbd, VC_META);
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  default:
5749cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBMETA:
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	setint:
5819cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = put_user(ucval, (int __user *)arg);
5829cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGETKEYCODE:
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSETKEYCODE:
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(!capable(CAP_SYS_TTY_CONFIG))
5879cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			perm = 0;
5889cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = do_kbkeycode_ioctl(cmd, up, perm);
5899cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBENT:
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBENT:
5939cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = do_kdsk_ioctl(cmd, up, perm, kbd);
5949cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBSENT:
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBSENT:
5989cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = do_kdgkb_ioctl(cmd, up, perm);
5999cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBDIACR:
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct kbdiacrs __user *a = up;
60404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		struct kbdiacr diacr;
60504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		int i;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6079cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (put_user(accent_table_size, &a->kb_cnt)) {
6089cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
6099cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
6109cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
61104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		for (i = 0; i < accent_table_size; i++) {
61204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
61304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			diacr.base = conv_uni_to_8bit(accent_table[i].base);
61404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			diacr.result = conv_uni_to_8bit(accent_table[i].result);
6159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
6169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				ret = -EFAULT;
6179cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				break;
6189cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			}
61904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		}
6209cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
62104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	}
62204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	case KDGKBDIACRUC:
62304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	{
62404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		struct kbdiacrsuc __user *a = up;
62504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault
62604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		if (put_user(accent_table_size, &a->kb_cnt))
6279cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
6289cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else if (copy_to_user(a->kbdiacruc, accent_table,
6299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				accent_table_size*sizeof(struct kbdiacruc)))
6309cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
6319cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBDIACR:
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct kbdiacrs __user *a = up;
63704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		struct kbdiacr diacr;
63804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		unsigned int ct;
63904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		int i;
64004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault
64104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		if (!perm)
6429cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
6439cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (get_user(ct,&a->kb_cnt)) {
6449cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
6459cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
6469cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
6479cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (ct >= MAX_DIACR) {
6489cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
6499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
6509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
65104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		accent_table_size = ct;
65204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		for (i = 0; i < ct; i++) {
6539cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
6549cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				ret = -EFAULT;
6559cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				break;
6569cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			}
65704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
65804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			accent_table[i].base = conv_8bit_to_uni(diacr.base);
65904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			accent_table[i].result = conv_8bit_to_uni(diacr.result);
66004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		}
6619cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
66204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	}
66304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault
66404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	case KDSKBDIACRUC:
66504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	{
66604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		struct kbdiacrsuc __user *a = up;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int ct;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
6709cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
6719cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (get_user(ct,&a->kb_cnt)) {
6729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
6739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
6749cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
6759cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (ct >= MAX_DIACR) {
6769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
6779cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
6789cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		accent_table_size = ct;
68004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
6819cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
6829cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the ioctls below read/set the flags usually shown in the leds */
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* don't use them - they will go away without warning */
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBLED:
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto setchar;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBLED:
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
6939cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
6949cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (arg & ~0x77) {
6959cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
6969cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
6979cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kbd->ledflagstate = (arg & 7);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kbd->default_ledflagstate = ((arg >> 4) & 7);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_leds();
7019cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the ioctls below only set the lights, not the functions */
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* for those, see KDGKBLED and KDSKBLED above */
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGETLED:
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = getledstate();
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	setchar:
7089cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = put_user(ucval, (char __user *)arg);
7099cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSETLED:
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
7139cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		setledstate(kbd, arg);
7159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * A process can indicate its willingness to accept signals
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * generated by pressing an appropriate key combination.
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Thus, one can have a daemon that e.g. spawns a new console
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * upon a keypress and then changes to it.
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * See also the kbrequest field of inittab(5).
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSIGACCEPT:
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm || !capable(CAP_KILL))
7279cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
7287ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl		if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
7299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
7309cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else {
7319cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			spin_lock_irq(&vt_spawn_con.lock);
7329cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			put_pid(vt_spawn_con.pid);
7339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			vt_spawn_con.pid = get_pid(task_pid(current));
7349cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			vt_spawn_con.sig = arg;
7359cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			spin_unlock_irq(&vt_spawn_con.lock);
7369cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
7379cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_SETMODE:
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct vt_mode tmp;
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
7459cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
7469cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
7479cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
7489cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto out;
7499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
7509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
7519cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
7529cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto out;
7539cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acquire_console_sem();
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vc->vt_mode = tmp;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* the frsig is ignored, so we set it to 0 */
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vc->vt_mode.frsig = 0;
7588b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		put_pid(vc->vt_pid);
7598b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		vc->vt_pid = get_pid(task_pid(current));
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* no switch is required -- saw@shade.msu.ru */
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vc->vt_newvt = -1;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_console_sem();
7639cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_GETMODE:
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct vt_mode tmp;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int rc;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acquire_console_sem();
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_console_sem();
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
7769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (rc)
7779cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
7789cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Returns global vt state. Note that VT 0 is always open, since
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it's an alias for the current VT, and people can't use it here.
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We cannot return state for more than 16 VTs, since v_state is short.
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_GETSTATE:
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct vt_stat __user *vtstat = up;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned short state, mask;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (put_user(fg_console + 1, &vtstat->v_active))
7929cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
7939cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else {
7949cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			state = 1;	/* /dev/tty0 is always open */
7959cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
7969cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox							++i, mask <<= 1)
7979cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				if (VT_IS_IN_USE(i))
7989cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					state |= mask;
7999cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = put_user(state, &vtstat->v_state);
8009cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
8019cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Returns the first available (non-opened) console.
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_OPENQRY:
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < MAX_NR_CONSOLES; ++i)
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (! VT_IS_IN_USE(i))
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = i < MAX_NR_CONSOLES ? (i+1) : -1;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto setint;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * with num >= 1 (switches to vt 0, our console, are not allowed, just
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to preserve sanity).
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_ACTIVATE:
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
8219cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg == 0 || arg > MAX_NR_CONSOLES)
8239cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret =  -ENXIO;
8249cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else {
8259cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			arg--;
8269cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			acquire_console_sem();
8279cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = vc_allocate(arg);
8289cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			release_console_sem();
8299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			if (ret)
8309cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				break;
8319cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			set_console(arg);
8329cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
8339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * wait until the specified VT has been activated
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_WAITACTIVE:
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
8409cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg == 0 || arg > MAX_NR_CONSOLES)
8429cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -ENXIO;
8439cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else
8449cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = vt_waitactive(arg - 1);
8459cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If a vt is under process control, the kernel will not switch to it
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * immediately, but postpone the operation until the process calls this
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ioctl, allowing the switch to complete.
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * According to the X sources this is the behavior:
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	0:	pending switch-from not OK
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	1:	pending switch-from OK
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	2:	completed switch-to OK
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_RELDISP:
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
8599cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8619cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (vc->vt_mode.mode != VT_PROCESS) {
8629cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
8639cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
8649cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Switching-from response
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
8688792f961ba8057d9f27987def3600253a3ba060fSamuel Ortiz		acquire_console_sem();
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (vc->vt_newvt >= 0) {
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (arg == 0)
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Switch disallowed, so forget we were trying
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * to do it.
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				vc->vt_newvt = -1;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else {
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * The current vt has been released, so
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * complete the switch.
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int newvt;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				newvt = vc->vt_newvt;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				vc->vt_newvt = -1;
8859cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				ret = vc_allocate(newvt);
8869cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				if (ret) {
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					release_console_sem();
8889cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					break;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * When we actually do the console switch,
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * make sure we are atomic with respect to
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * other console switches..
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				complete_change_console(vc_cons[newvt].d);
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8979cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		} else {
8989cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			/*
8999cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			 * Switched-to response
9009cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			 */
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * If it's just an ACK, ignore it
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
9049cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			if (arg != VT_ACKACQ)
9059cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				ret = -EINVAL;
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9078792f961ba8057d9f27987def3600253a3ba060fSamuel Ortiz		release_console_sem();
9089cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 /*
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  * Disallocate memory associated to VT (but leave VT1)
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  */
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 case VT_DISALLOCATE:
9149cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (arg > MAX_NR_CONSOLES) {
9159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -ENXIO;
9169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
9179cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg == 0) {
919ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox		    /* deallocate all unused consoles, but leave 0 */
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			acquire_console_sem();
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i=1; i<MAX_NR_CONSOLES; i++)
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (! VT_BUSY(i))
923ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox					vc_deallocate(i);
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_console_sem();
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
926ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox			/* deallocate a single console, if possible */
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			arg--;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (VT_BUSY(arg))
9299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				ret = -EBUSY;
9309cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			else if (arg) {			      /* leave 0 */
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				acquire_console_sem();
932ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox				vc_deallocate(arg);
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				release_console_sem();
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9369cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_RESIZE:
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct vt_sizes __user *vtsizes = up;
941e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas		struct vc_data *vc;
942e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ushort ll,cc;
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
9459cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (get_user(ll, &vtsizes->v_rows) ||
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    get_user(cc, &vtsizes->v_cols))
9489cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
9499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else {
9508c9a9dd0fa3a269d380eaae2dc1bee39e865fae1Alan Cox			acquire_console_sem();
9519cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			for (i = 0; i < MAX_NR_CONSOLES; i++) {
9529cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				vc = vc_cons[i].d;
953e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas
9549cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				if (vc) {
9559cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					vc->vc_resize_user = 1;
9568c9a9dd0fa3a269d380eaae2dc1bee39e865fae1Alan Cox					vc_resize(vc_cons[i].d, cc, ll);
9579cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				}
958e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas			}
9598c9a9dd0fa3a269d380eaae2dc1bee39e865fae1Alan Cox			release_console_sem();
960e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas		}
9619cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_RESIZEX:
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct vt_consize __user *vtconsize = up;
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ushort ll,cc,vlin,clin,vcol,ccol;
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
9699cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!access_ok(VERIFY_READ, vtconsize,
9719cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				sizeof(struct vt_consize))) {
9729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
9739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
9749cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
9759cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		/* FIXME: Should check the copies properly */
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(ll, &vtconsize->v_rows);
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(cc, &vtconsize->v_cols);
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(vlin, &vtconsize->v_vlin);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(clin, &vtconsize->v_clin);
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(vcol, &vtconsize->v_vcol);
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(ccol, &vtconsize->v_ccol);
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vlin = vlin ? vlin : vc->vc_scan_lines;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clin) {
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ll) {
9859cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				if (ll != vlin/clin) {
9869cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					/* Parameters don't add up */
9879cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					ret = -EINVAL;
9889cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					break;
9899cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				}
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ll = vlin/clin;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (vcol && ccol) {
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cc) {
9959cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				if (cc != vcol/ccol) {
9969cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					ret = -EINVAL;
9979cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					break;
9989cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				}
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cc = vcol/ccol;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10039cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (clin > 32) {
10049cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret =  -EINVAL;
10059cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
10069cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < MAX_NR_CONSOLES; i++) {
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!vc_cons[i].d)
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			acquire_console_sem();
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (vlin)
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				vc_cons[i].d->vc_scan_lines = vlin;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (clin)
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				vc_cons[i].d->vc_font.height = clin;
1016e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas			vc_cons[i].d->vc_resize_user = 1;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			vc_resize(vc_cons[i].d, cc, ll);
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_console_sem();
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10209cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_FONT: {
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
10259cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.op = KD_FONT_OP_SET;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC;	/* Compatibility */
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.width = 8;
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.height = 0;
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.charcount = 256;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.data = up;
10329cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_font_op(vc_cons[fg_console].d, &op);
10339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_FONT: {
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.op = KD_FONT_OP_GET;
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.flags = KD_FONT_FLAG_OLD;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.width = 8;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.height = 32;
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.charcount = 256;
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.data = up;
10439cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_font_op(vc_cons[fg_console].d, &op);
10449cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_CMAP:
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (!perm)
10499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EPERM;
10509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else
10519cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	                ret = con_set_cmap(up);
10529cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_CMAP:
10559cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox                ret = con_get_cmap(up);
10569cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_FONTX:
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_FONTX:
10609cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = do_fontx_ioctl(cmd, up, perm, &op);
10619cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_FONTRESET:
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
10669cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BROKEN_GRAPHICS_PROGRAMS
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   font is not saved. */
10719cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = -ENOSYS;
10729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.op = KD_FONT_OP_SET_DEFAULT;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.data = NULL;
10779cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_font_op(vc_cons[fg_console].d, &op);
10789cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (ret)
10799cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		con_set_default_unimap(vc_cons[fg_console].d);
10819cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDFONTOP: {
10879cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (copy_from_user(&op, up, sizeof(op))) {
10889cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
10899cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
10909cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm && op.op != KD_FONT_OP_GET)
10929cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
10939cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_font_op(vc, &op);
10949cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (ret)
10959cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(up, &op, sizeof(op)))
10979cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
10989cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_SCRNMAP:
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
11039cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EPERM;
11049cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else
11059cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = con_set_trans_old(up);
11069cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_SCRNMAP:
11099cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_get_trans_old(up);
11109cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_UNISCRNMAP:
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
11149cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EPERM;
11159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else
11169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = con_set_trans_new(up);
11179cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_UNISCRNMAP:
11209cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_get_trans_new(up);
11219cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_UNIMAPCLR:
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      { struct unimapinit ui;
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
11269cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
11279cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
11289cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (!ret)
11299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			con_clear_unimap(vc, &ui);
11309cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      }
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_UNIMAP:
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_UNIMAP:
11359cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = do_unimap_ioctl(cmd, up, perm, vc);
11369cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_LOCKSWITCH:
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_SYS_TTY_CONFIG))
11409cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vt_dont_switch = 1;
11429cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_UNLOCKSWITCH:
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_SYS_TTY_CONFIG))
11459cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vt_dont_switch = 0;
11479cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
1148533475d3d48eb839be2b57f6b020150abae91063Samuel Thibault	case VT_GETHIFONTMASK:
11499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = put_user(vc->vc_hi_font_mask,
11509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					(unsigned short __user *)arg);
11519cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
11539cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = -ENOIOCTLCMD;
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11559cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Coxout:
11569cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	unlock_kernel();
11579cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	return ret;
11589cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Coxeperm:
11599cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	ret = -EPERM;
11609cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	goto out;
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sometimes we want to wait until a particular VT has been activated. We
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do it in a very simple manner. Everybody waits on a single queue and
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get woken up at once. Those that are satisfied go on with their business,
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * while those not ready go back to sleep. Seems overkill to add a wait
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to each vt just for this - usually this does nothing!
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue);
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sleeps until a vt is activated, or the task is interrupted. Returns
117470cb97935b8859f27296772885104b599f560576Linus Torvalds * 0 if activation, -EINTR if interrupted by a signal handler.
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint vt_waitactive(int vt)
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DECLARE_WAITQUEUE(wait, current);
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_wait_queue(&vt_activate_queue, &wait);
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (;;) {
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		retval = 0;
1184f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski
1185f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		/*
1186f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		 * Synchronize with redraw_screen(). By acquiring the console
1187f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		 * semaphore we make sure that the console switch is completed
1188f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		 * before we return. If we didn't wait for the semaphore, we
1189f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		 * could return at a point where fg_console has already been
1190f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		 * updated, but the console switch hasn't been completed.
1191f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		 */
1192f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		acquire_console_sem();
1193f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		set_current_state(TASK_INTERRUPTIBLE);
1194f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		if (vt == fg_console) {
1195f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski			release_console_sem();
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1197f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		}
1198f991519c197534811046e5e47389b6fafcdf1e48Michal Januszewski		release_console_sem();
119970cb97935b8859f27296772885104b599f560576Linus Torvalds		retval = -ERESTARTNOHAND;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (signal_pending(current))
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		schedule();
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	remove_wait_queue(&vt_activate_queue, &wait);
1205cc0a8fbb7ce00f65dc337dd91389b7151f44ed30Milind Arun Choudhary	__set_current_state(TASK_RUNNING);
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retval;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define vt_wake_waitactive() wake_up(&vt_activate_queue)
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid reset_vc(struct vc_data *vc)
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vc_mode = KD_TEXT;
12142e8ecb9db0bcc19e1cc8bb51e9252fe6a86a9863Bill Nottingham	kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_mode.mode = VT_AUTO;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_mode.waitv = 0;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_mode.relsig = 0;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_mode.acqsig = 0;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_mode.frsig = 0;
12208b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	put_pid(vc->vt_pid);
12218b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	vc->vt_pid = NULL;
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_newvt = -1;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reset_palette(vc);
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12278b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biedermanvoid vc_SAK(struct work_struct *work)
12288b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman{
12298b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	struct vc *vc_con =
12308b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		container_of(work, struct vc, SAK_work);
12318b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	struct vc_data *vc;
12328b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	struct tty_struct *tty;
12338b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman
12348b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	acquire_console_sem();
12358b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	vc = vc_con->d;
12368b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	if (vc) {
12378b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		tty = vc->vc_tty;
12388b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		/*
12398b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		 * SAK should also work in all raw modes and reset
12408b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		 * them properly.
12418b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		 */
12428b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		if (tty)
12438b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman			__do_SAK(tty);
12448b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		reset_vc(vc);
12458b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	}
12468b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	release_console_sem();
12478b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman}
12488b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Performs the back end of a vt switch
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void complete_change_console(struct vc_data *vc)
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char old_vc_mode;
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	last_console = fg_console;
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we're switching, we could be going from KD_GRAPHICS to
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * KD_TEXT mode or vice versa, which means we need to blank or
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * unblank the screen later.
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_vc_mode = vc_cons[fg_console].d->vc_mode;
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_screen(vc);
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
12673dfcaf16135150d0f025047a7525664a41bb2adfEric W. Biederman	 * This can't appear below a successful kill_pid().  If it did,
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * then the *blank_screen operation could occur while X, having
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * received acqsig, is waking up on another processor.  This
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * condition can lead to overlapping accesses to the VGA range
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * and the framebuffer (causing system lockups).
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * To account for this we duplicate this code below only if the
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * controlling process is gone and we've called reset_vc.
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old_vc_mode != vc->vc_mode) {
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (vc->vc_mode == KD_TEXT)
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_unblank_screen(1);
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_blank_screen(1);
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If this new console is under process control, send it a signal
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * telling it that it has acquired. Also check if it has died and
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * clean up (similar to logic employed in change_console())
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vc->vt_mode.mode == VT_PROCESS) {
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
12903dfcaf16135150d0f025047a7525664a41bb2adfEric W. Biederman		 * Send the signal as privileged - kill_pid() will
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * tell us if the process has gone or something else
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * is awry
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1294bde0d2c98bcfc9acc83ac79c33a6ac1335b95a92Eric W. Biederman		if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * The controlling process has died, so we revert back to
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * normal operation. In this case, we'll also change back
12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to KD_TEXT mode. I'm not sure if this is strictly correct
12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * but it saves the agony when the X server dies and the screen
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * remains blanked due to KD_GRAPHICS! It would be nice to do
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this outside of VT_PROCESS but there is no single process
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to account for and tracking tty count may be undesirable.
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			reset_vc(vc);
13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (old_vc_mode != vc->vc_mode) {
13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (vc->vc_mode == KD_TEXT)
13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					do_unblank_screen(1);
13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					do_blank_screen(1);
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Wake anyone waiting for their VT to activate
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vt_wake_waitactive();
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Performs the front-end of a vt switch
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid change_console(struct vc_data *new_vc)
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct vc_data *vc;
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If this vt is in process mode, then we need to handshake with
13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * that process before switching. Essentially, we store where that
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * vt wants to switch to and wait for it to tell us when it's done
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (via VT_RELDISP ioctl).
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We also check to see if the controlling process still exists.
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If it doesn't, we reset this vt to auto mode and continue.
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This is a cheap way to track process control. The worst thing
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * that can happen is: we send a signal to a process, it dies, and
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the switch gets "lost" waiting for a response; hopefully, the
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * user will try again, we'll detect the process is gone (unless
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the user waits just the right amount of time :-) and revert the
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * vt to auto control.
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc = vc_cons[fg_console].d;
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vc->vt_mode.mode == VT_PROCESS) {
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
13503dfcaf16135150d0f025047a7525664a41bb2adfEric W. Biederman		 * Send the signal as privileged - kill_pid() will
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * tell us if the process has gone or something else
1352a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe		 * is awry.
1353a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe		 *
1354a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe		 * We need to set vt_newvt *before* sending the signal or we
1355a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe		 * have a race.
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1357a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe		vc->vt_newvt = new_vc->vc_num;
1358bde0d2c98bcfc9acc83ac79c33a6ac1335b95a92Eric W. Biederman		if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * It worked. Mark the vt to switch to and
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * return. The process needs to send us a
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * VT_RELDISP ioctl to complete the switch.
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return;
13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * The controlling process has died, so we revert back to
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * normal operation. In this case, we'll also change back
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to KD_TEXT mode. I'm not sure if this is strictly correct
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * but it saves the agony when the X server dies and the screen
13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * remains blanked due to KD_GRAPHICS! It would be nice to do
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this outside of VT_PROCESS but there is no single process
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to account for and tracking tty count may be undesirable.
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reset_vc(vc);
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Fall through to normal (VT_AUTO) handling of the switch...
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vc->vc_mode == KD_GRAPHICS)
13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	complete_change_console(new_vc);
13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1391