vt_ioctl.c revision 8ce73264b75be4d5ed480440ac32dfc1f25ff678
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>
19e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann#include <linux/compat.h>
208d233558cd99a888571bb5a88a74970879e0aba4Alan Cox#include <linux/module.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kd.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vt.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h>
2804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault#include <linux/consolemap.h>
297ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl#include <linux/signal.h>
30405f55712dfe464b3240d7816cc4fe4174831be2Alexey Dobriyan#include <linux/smp_lock.h>
31bcc8ca09920755520ba8a1e2d9f72fe8ff892643Emmanuel Colbus#include <linux/timex.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kbd_kern.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vt_kern.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kbd_diacr.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/selection.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41b257bc051f06607beb3004d9a1c297085e728becAndrew Johnsonchar vt_dont_switch;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern struct tty_driver *console_driver;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VT_IS_IN_USE(i)	(console_driver->ttys[i] && console_driver->ttys[i]->count)
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VT_BUSY(i)	(VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * experimentation and study of X386 SYSV handling.
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the current console is done by the main ioctl code.
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/syscalls.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void complete_change_console(struct vc_data *vc);
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
678b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	User space VT_EVENT handlers
688b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox */
698b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
708b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstruct vt_event_wait {
718b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	struct list_head list;
728b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	struct vt_event event;
738b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	int done;
748b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox};
758b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
768b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstatic LIST_HEAD(vt_events);
778b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstatic DEFINE_SPINLOCK(vt_event_lock);
788b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstatic DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue);
798b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
808b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox/**
818b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	vt_event_post
828b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	@event: the event that occurred
838b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	@old: old console
848b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	@new: new console
858b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *
868b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	Post an VT event to interested VT handlers
878b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox */
888b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
898b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxvoid vt_event_post(unsigned int event, unsigned int old, unsigned int new)
908b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox{
918b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	struct list_head *pos, *head;
928b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	unsigned long flags;
938b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	int wake = 0;
948b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
958b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	spin_lock_irqsave(&vt_event_lock, flags);
968b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	head = &vt_events;
978b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
988b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	list_for_each(pos, head) {
998b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		struct vt_event_wait *ve = list_entry(pos,
1008b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox						struct vt_event_wait, list);
1018b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		if (!(ve->event.event & event))
1028b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox			continue;
1038b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		ve->event.event = event;
1048b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		/* kernel view is consoles 0..n-1, user space view is
1058b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		   console 1..n with 0 meaning current, so we must bias */
106308efab5e231d1510cd35931d87629bf5171caaeAlan Cox		ve->event.oldev = old + 1;
107308efab5e231d1510cd35931d87629bf5171caaeAlan Cox		ve->event.newev = new + 1;
1088b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		wake = 1;
1098b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		ve->done = 1;
1108b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	}
1118b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	spin_unlock_irqrestore(&vt_event_lock, flags);
1128b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	if (wake)
1138b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		wake_up_interruptible(&vt_event_waitqueue);
1148b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox}
1158b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
1168b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox/**
1178b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	vt_event_wait		-	wait for an event
1188b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	@vw: our event
1198b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *
1208b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	Waits for an event to occur which completes our vt_event_wait
1218b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	structure. On return the structure has wv->done set to 1 for success
1228b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	or 0 if some event such as a signal ended the wait.
1238b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox */
1248b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
1258b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstatic void vt_event_wait(struct vt_event_wait *vw)
1268b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox{
1278b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	unsigned long flags;
1288b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	/* Prepare the event */
1298b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	INIT_LIST_HEAD(&vw->list);
1308b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	vw->done = 0;
1318b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	/* Queue our event */
1328b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	spin_lock_irqsave(&vt_event_lock, flags);
1338b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	list_add(&vw->list, &vt_events);
1348b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	spin_unlock_irqrestore(&vt_event_lock, flags);
1358b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	/* Wait for it to pass */
1368b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	wait_event_interruptible(vt_event_waitqueue, vw->done);
1378b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	/* Dequeue it */
1388b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	spin_lock_irqsave(&vt_event_lock, flags);
1398b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	list_del(&vw->list);
1408b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	spin_unlock_irqrestore(&vt_event_lock, flags);
1418b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox}
1428b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
1438b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox/**
1448b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	vt_event_wait_ioctl	-	event ioctl handler
1458b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	@arg: argument to ioctl
1468b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *
1478b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	Implement the VT_WAITEVENT ioctl using the VT event interface
1488b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox */
1498b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
1508b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstatic int vt_event_wait_ioctl(struct vt_event __user *event)
1518b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox{
1528b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	struct vt_event_wait vw;
1538b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
1548b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	if (copy_from_user(&vw.event, event, sizeof(struct vt_event)))
1558b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		return -EFAULT;
1568b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	/* Highest supported event for now */
1578b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	if (vw.event.event & ~VT_MAX_EVENT)
1588b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		return -EINVAL;
1598b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
1608b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	vt_event_wait(&vw);
1618b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	/* If it occurred report it */
1628b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	if (vw.done) {
1638b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		if (copy_to_user(event, &vw.event, sizeof(struct vt_event)))
1648b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox			return -EFAULT;
1658b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		return 0;
1668b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	}
1678b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	return -EINTR;
1688b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox}
1698b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
1708b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox/**
1718b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	vt_waitactive	-	active console wait
1728b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	@event: event code
1738b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	@n: new console
1748b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *
1758b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	Helper for event waits. Used to implement the legacy
1768b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox *	event waiting ioctls in terms of events
1778b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox */
1788b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
1798b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxint vt_waitactive(int n)
1808b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox{
1818b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	struct vt_event_wait vw;
1828b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	do {
1838b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		if (n == fg_console + 1)
1848b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox			break;
1858b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		vw.event.event = VT_EVENT_SWITCH;
1868b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		vt_event_wait(&vw);
1878b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		if (vw.done == 0)
1888b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox			return -EINTR;
189308efab5e231d1510cd35931d87629bf5171caaeAlan Cox	} while (vw.event.newev != n);
1908b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	return 0;
1918b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox}
1928b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
1938b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox/*
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * these are the valid i/o ports we're allowed to change. they map all the
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * video ports
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GPFIRST 0x3b4
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GPLAST 0x3df
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GPNUM (GPLAST - GPFIRST + 1)
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define i (tmp.kb_index)
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define s (tmp.kb_table)
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define v (tmp.kb_value)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kbentry tmp;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ushort *key_map, val, ov;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
213e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti	if (!capable(CAP_SYS_TTY_CONFIG))
214e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti		perm = 0;
215e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBENT:
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key_map = key_maps[s];
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (key_map) {
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    val = U(key_map[i]);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val = K_HOLE;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    val = (i ? K_HOLE : K_NOSUCHMAP);
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return put_user(val, &user_kbe->kb_value);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBENT:
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!i && v == K_NOSUCHMAP) {
230ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox			/* deallocate map */
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			key_map = key_maps[s];
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (s && key_map) {
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    key_maps[s] = NULL;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    if (key_map[0] == U(K_ALLOCATED)) {
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					kfree(key_map);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					keymap_count--;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    }
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (KTYP(v) < NR_TYPES) {
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (KVAL(v) > max_vals[KTYP(v)])
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EINVAL;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (kbd->kbdmode != VC_UNICODE)
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EINVAL;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* ++Geert: non-PC keyboards may generate keycode zero */
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if !defined(__mc68000__) && !defined(__powerpc__)
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* assignment to entry 0 only tests validity of args */
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!i)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(key_map = key_maps[s])) {
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int j;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    !capable(CAP_SYS_RESOURCE))
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EPERM;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2635cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day			key_map = kmalloc(sizeof(plain_map),
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						     GFP_KERNEL);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!key_map)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENOMEM;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			key_maps[s] = key_map;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			key_map[0] = U(K_ALLOCATED);
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (j = 1; j < NR_KEYS; j++)
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				key_map[j] = U(K_HOLE);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			keymap_count++;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ov = U(key_map[i]);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (v == ov)
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;	/* nothing to do */
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Attention Key.
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		key_map[i] = U(v);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			compute_shiftstate();
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef i
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef s
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef v
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kbkeycode tmp;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int kc = 0;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGETKEYCODE:
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kc = getkeycode(tmp.scancode);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (kc >= 0)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kc = put_user(kc, &user_kbkc->keycode);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSETKEYCODE:
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kc = setkeycode(tmp.scancode, tmp.keycode);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return kc;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kbsentry *kbs;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *p;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char *q;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_char __user *up;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sz;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int delta;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *first_free, *fj, *fnw;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, k;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3280b360adbdb54d5b98b78d57ba0916bc4b8871968Andrew Morton	if (!capable(CAP_SYS_TTY_CONFIG))
329e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti		perm = 0;
3300b360adbdb54d5b98b78d57ba0916bc4b8871968Andrew Morton
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!kbs) {
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto reterr;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we mostly copy too much here (512bytes), but who cares ;) */
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EFAULT;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto reterr;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = kbs->kb_func;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBSENT:
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sz = sizeof(kbs->kb_string) - 1; /* sz should have been
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  a struct member */
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up = user_kdgkb->kb_string;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		p = func_table[i];
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(p)
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for ( ; *p && sz; p++, sz--)
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (put_user(*p, up++)) {
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ret = -EFAULT;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto reterr;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (put_user('\0', up)) {
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = -EFAULT;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto reterr;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(kbs);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ((p && *p) ? -EOVERFLOW : 0);
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBSENT:
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm) {
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = -EPERM;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto reterr;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		q = func_table[i];
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		first_free = funcbufptr + (funcbufsize - funcbufleft);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (j < MAX_NR_FUNC)
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fj = func_table[j];
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			fj = first_free;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (delta <= funcbufleft) { 	/* it fits in current buf */
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (j < MAX_NR_FUNC) {
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memmove(fj + delta, fj, first_free - fj);
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (k = j; k < MAX_NR_FUNC; k++)
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    if (func_table[k])
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				func_table[k] += delta;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    }
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (!q)
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      func_table[i] = fj;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    funcbufleft -= delta;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {			/* allocate a larger buffer */
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    sz = 256;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    while (sz < funcbufsize - funcbufleft + delta)
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      sz <<= 1;
3935cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day		    fnw = kmalloc(sz, GFP_KERNEL);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if(!fnw) {
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      ret = -ENOMEM;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      goto reterr;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    }
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (!q)
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      func_table[i] = fj;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (fj > funcbufptr)
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memmove(fnw, funcbufptr, fj - funcbufptr);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    for (k = 0; k < j; k++)
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      if (func_table[k])
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			func_table[k] = fnw + (func_table[k] - funcbufptr);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (first_free > fj) {
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (k = j; k < MAX_NR_FUNC; k++)
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  if (func_table[k])
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    }
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    if (funcbufptr != func_buf)
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      kfree(funcbufptr);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    funcbufptr = fnw;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    funcbufleft = funcbufleft - delta + sz - funcbufsize;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    funcbufsize = sz;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(func_table[i], kbs->kb_string);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = 0;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreterr:
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(kbs);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct consolefontdesc cfdarg;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc)))
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_FONTX:
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->op = KD_FONT_OP_SET;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->flags = KD_FONT_FLAG_OLD;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->width = 8;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->height = cfdarg.charheight;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->charcount = cfdarg.charcount;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->data = cfdarg.chardata;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return con_font_op(vc_cons[fg_console].d, op);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_FONTX: {
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->op = KD_FONT_OP_GET;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->flags = KD_FONT_FLAG_OLD;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->width = 8;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->height = cfdarg.charheight;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->charcount = cfdarg.charcount;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op->data = cfdarg.chardata;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i = con_font_op(vc_cons[fg_console].d, op);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (i)
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return i;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfdarg.charheight = op->height;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cfdarg.charcount = op->charcount;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct unimapdesc tmp;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&tmp, user_ud, sizeof tmp))
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tmp.entries)
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!access_ok(VERIFY_WRITE, tmp.entries,
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				tmp.entry_ct*sizeof(struct unipair)))
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_UNIMAP:
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_UNIMAP:
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm && fg_console != vc->vc_num)
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4928b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
4938b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We handle the console-specific ioctl's here.  We allow the
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * capability to modify any console, not just the fg_console.
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint vt_ioctl(struct tty_struct *tty, struct file * file,
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     unsigned int cmd, unsigned long arg)
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
501c9f19e96a2f33cd56c2bd19f87a0c4982d011c2bAlan Cox	struct vc_data *vc = tty->driver_data;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct console_font_op op;	/* used in multiple places here */
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct kbd_struct * kbd;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int console;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char ucval;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __user *up = (void __user *)arg;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, perm;
5089cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	int ret = 0;
5099cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	console = vc->vc_num;
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5129cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	lock_kernel();
5139cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox
5149cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	if (!vc_cons_allocated(console)) { 	/* impossible? */
5159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = -ENOIOCTLCMD;
5169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		goto out;
5179cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	}
5189cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * To have permissions to do most of the vt ioctls, we either have
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	perm = 0;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		perm = 1;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kbd = kbd_table + console;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
530e6885107736a4dd23e7d3bc103fe6d043c63c4deAlan Cox	case TIOCLINUX:
531a115902f67ef51fbbe83e214fb761aaa9734c1ceJiri Slaby		ret = tioclinux(tty, arg);
532a115902f67ef51fbbe83e214fb761aaa9734c1ceJiri Slaby		break;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KIOCSOUND:
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
5359cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
536fab892232e275e4e9351a50d018c0a9513155814Alan Cox		/* FIXME: This is an old broken API but we need to keep it
537fab892232e275e4e9351a50d018c0a9513155814Alan Cox		   supported and somehow separate the historic advertised
538fab892232e275e4e9351a50d018c0a9513155814Alan Cox		   tick rate from any real one */
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg)
540bcc8ca09920755520ba8a1e2d9f72fe8ff892643Emmanuel Colbus			arg = CLOCK_TICK_RATE / arg;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kd_mksound(arg, 0);
5429cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDMKTONE:
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
5469cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int ticks, count;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Generate the tone for the appropriate number of ticks.
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * If the time is zero, turn off sound ourselves.
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = ticks ? (arg & 0xffff) : 0;
556fab892232e275e4e9351a50d018c0a9513155814Alan Cox		/* FIXME: This is an old broken API but we need to keep it
557fab892232e275e4e9351a50d018c0a9513155814Alan Cox		   supported and somehow separate the historic advertised
558fab892232e275e4e9351a50d018c0a9513155814Alan Cox		   tick rate from any real one */
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (count)
560bcc8ca09920755520ba8a1e2d9f72fe8ff892643Emmanuel Colbus			count = CLOCK_TICK_RATE / count;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kd_mksound(count, ticks);
5629cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBTYPE:
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this is naive.
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = KB_101;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto setchar;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * These cannot be implemented on any machine that implements
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ioperm() in user level (such as Alpha PCs) or not at all.
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * XXX: you should never use these, just call ioperm directly..
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDADDIO:
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDDELIO:
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * KDADDIO and KDDELIO may be able to add ports beyond what
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * we reject here, but to be safe...
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5859cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (arg < GPFIRST || arg > GPLAST) {
5869cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
5879cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
5889cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
5899cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
5909cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDENABIO:
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDDISABIO:
5949cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = sys_ioperm(GPFIRST, GPNUM,
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  (cmd == KDENABIO)) ? -ENXIO : 0;
5969cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDKBDREP:
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct kbd_repeat kbrep;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_SYS_TTY_CONFIG))
6069cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6089cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
6099cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret =  -EFAULT;
6109cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
6119cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
6129cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = kbd_rate(&kbrep);
6139cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (ret)
6149cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
6169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
6179cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSETMODE:
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * currently, setting the mode from KD_TEXT to KD_GRAPHICS
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * doesn't do a whole lot. i'm not sure if it should do any
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * restoration of modes or what...
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * XXX It should at least call into the driver, fbdev's definitely
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * need to restore their engine state. --BenH
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
6309cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (arg) {
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case KD_GRAPHICS:
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case KD_TEXT0:
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case KD_TEXT1:
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			arg = KD_TEXT;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case KD_TEXT:
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
6409cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
6419cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto out;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (vc->vc_mode == (unsigned char) arg)
6449cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vc->vc_mode = (unsigned char) arg;
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (console != fg_console)
6479cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * explicitly blank/unblank the screen if switching modes
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acquire_console_sem();
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg == KD_TEXT)
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_unblank_screen(1);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_blank_screen(1);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_console_sem();
6579cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGETMODE:
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = vc->vc_mode;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto setint;
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDMAPDISP:
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDUNMAPDISP:
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * these work like a combination of mmap and KDENABIO.
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this could be easily finished.
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
6699cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = -EINVAL;
6709cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBMODE:
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
6749cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(arg) {
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_RAW:
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kbd->kbdmode = VC_RAW;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_MEDIUMRAW:
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kbd->kbdmode = VC_MEDIUMRAW;
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_XLATE:
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kbd->kbdmode = VC_XLATE;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			compute_shiftstate();
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_UNICODE:
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kbd->kbdmode = VC_UNICODE;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			compute_shiftstate();
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  default:
6919cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
6929cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto out;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tty_ldisc_flush(tty);
6959cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBMODE:
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 K_XLATE);
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto setint;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* this could be folded into KDSKBMODE, but for compatibility
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBMETA:
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(arg) {
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_METABIT:
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			clr_vc_kbd_mode(kbd, VC_META);
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  case K_ESCPREFIX:
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_vc_kbd_mode(kbd, VC_META);
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		  default:
7159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7179cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBMETA:
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	setint:
7229cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = put_user(ucval, (int __user *)arg);
7239cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGETKEYCODE:
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSETKEYCODE:
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(!capable(CAP_SYS_TTY_CONFIG))
7289cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			perm = 0;
7299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = do_kbkeycode_ioctl(cmd, up, perm);
7309cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBENT:
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBENT:
7349cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = do_kdsk_ioctl(cmd, up, perm, kbd);
7359cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBSENT:
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBSENT:
7399cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = do_kdgkb_ioctl(cmd, up, perm);
7409cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBDIACR:
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct kbdiacrs __user *a = up;
74504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		struct kbdiacr diacr;
74604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		int i;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7489cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (put_user(accent_table_size, &a->kb_cnt)) {
7499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
7509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
7519cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
75204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		for (i = 0; i < accent_table_size; i++) {
75304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
75404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			diacr.base = conv_uni_to_8bit(accent_table[i].base);
75504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			diacr.result = conv_uni_to_8bit(accent_table[i].result);
7569cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
7579cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				ret = -EFAULT;
7589cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				break;
7599cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			}
76004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		}
7619cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
76204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	}
76304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	case KDGKBDIACRUC:
76404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	{
76504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		struct kbdiacrsuc __user *a = up;
76604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault
76704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		if (put_user(accent_table_size, &a->kb_cnt))
7689cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
7699cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else if (copy_to_user(a->kbdiacruc, accent_table,
7709cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				accent_table_size*sizeof(struct kbdiacruc)))
7719cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
7729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBDIACR:
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct kbdiacrs __user *a = up;
77804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		struct kbdiacr diacr;
77904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		unsigned int ct;
78004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		int i;
78104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault
78204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		if (!perm)
7839cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
7849cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (get_user(ct,&a->kb_cnt)) {
7859cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
7869cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
7879cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
7889cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (ct >= MAX_DIACR) {
7899cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
7909cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
7919cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
79204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		accent_table_size = ct;
79304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		for (i = 0; i < ct; i++) {
7949cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
7959cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				ret = -EFAULT;
7969cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				break;
7979cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			}
79804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
79904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			accent_table[i].base = conv_8bit_to_uni(diacr.base);
80004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault			accent_table[i].result = conv_8bit_to_uni(diacr.result);
80104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		}
8029cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
80304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	}
80404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault
80504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	case KDSKBDIACRUC:
80604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault	{
80704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		struct kbdiacrsuc __user *a = up;
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int ct;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
8119cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
8129cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (get_user(ct,&a->kb_cnt)) {
8139cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
8149cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
8159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
8169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (ct >= MAX_DIACR) {
8179cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
8189cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
8199cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		accent_table_size = ct;
82104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault		if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
8229cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
8239cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the ioctls below read/set the flags usually shown in the leds */
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* don't use them - they will go away without warning */
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGKBLED:
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto setchar;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSKBLED:
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
8349cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
8359cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (arg & ~0x77) {
8369cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
8379cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
8389cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kbd->ledflagstate = (arg & 7);
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kbd->default_ledflagstate = ((arg >> 4) & 7);
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_leds();
8429cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the ioctls below only set the lights, not the functions */
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* for those, see KDGKBLED and KDSKBLED above */
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDGETLED:
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = getledstate();
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	setchar:
8499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = put_user(ucval, (char __user *)arg);
8509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSETLED:
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
8549cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		setledstate(kbd, arg);
8569cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * A process can indicate its willingness to accept signals
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * generated by pressing an appropriate key combination.
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Thus, one can have a daemon that e.g. spawns a new console
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * upon a keypress and then changes to it.
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * See also the kbrequest field of inittab(5).
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDSIGACCEPT:
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm || !capable(CAP_KILL))
8689cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
8697ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl		if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
8709cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
8719cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else {
8729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			spin_lock_irq(&vt_spawn_con.lock);
8739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			put_pid(vt_spawn_con.pid);
8749cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			vt_spawn_con.pid = get_pid(task_pid(current));
8759cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			vt_spawn_con.sig = arg;
8769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			spin_unlock_irq(&vt_spawn_con.lock);
8779cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
8789cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_SETMODE:
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct vt_mode tmp;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
8869cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
8879cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
8889cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
8899cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto out;
8909cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
89187a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
8929cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
8939cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto out;
8949cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acquire_console_sem();
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vc->vt_mode = tmp;
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* the frsig is ignored, so we set it to 0 */
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vc->vt_mode.frsig = 0;
8998b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		put_pid(vc->vt_pid);
9008b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		vc->vt_pid = get_pid(task_pid(current));
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* no switch is required -- saw@shade.msu.ru */
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vc->vt_newvt = -1;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_console_sem();
9049cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_GETMODE:
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct vt_mode tmp;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int rc;
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		acquire_console_sem();
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_console_sem();
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
9179cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (rc)
9189cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
9199cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Returns global vt state. Note that VT 0 is always open, since
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * it's an alias for the current VT, and people can't use it here.
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We cannot return state for more than 16 VTs, since v_state is short.
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_GETSTATE:
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct vt_stat __user *vtstat = up;
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned short state, mask;
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (put_user(fg_console + 1, &vtstat->v_active))
9339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
9349cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else {
9359cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			state = 1;	/* /dev/tty0 is always open */
9369cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
9379cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox							++i, mask <<= 1)
9389cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				if (VT_IS_IN_USE(i))
9399cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					state |= mask;
9409cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = put_user(state, &vtstat->v_state);
9419cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
9429cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Returns the first available (non-opened) console.
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_OPENQRY:
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < MAX_NR_CONSOLES; ++i)
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (! VT_IS_IN_USE(i))
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucval = i < MAX_NR_CONSOLES ? (i+1) : -1;
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto setint;
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * with num >= 1 (switches to vt 0, our console, are not allowed, just
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to preserve sanity).
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_ACTIVATE:
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
9629cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg == 0 || arg > MAX_NR_CONSOLES)
9649cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret =  -ENXIO;
9659cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else {
9669cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			arg--;
9679cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			acquire_console_sem();
9689cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = vc_allocate(arg);
9699cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			release_console_sem();
9709cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			if (ret)
9719cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				break;
9729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			set_console(arg);
9739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
9749cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
976d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox	case VT_SETACTIVATE:
977d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox	{
978d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox		struct vt_setactivate vsa;
979d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox
980d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox		if (!perm)
981d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			goto eperm;
982d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox
983d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox		if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
984a09efb07b5025fb75f42e903d31767a3cafede89Jiri Slaby					sizeof(struct vt_setactivate))) {
985a09efb07b5025fb75f42e903d31767a3cafede89Jiri Slaby			ret = -EFAULT;
986a09efb07b5025fb75f42e903d31767a3cafede89Jiri Slaby			goto out;
987a09efb07b5025fb75f42e903d31767a3cafede89Jiri Slaby		}
988d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox		if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
989d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			ret = -ENXIO;
990d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox		else {
991d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			vsa.console--;
992d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			acquire_console_sem();
993d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			ret = vc_allocate(vsa.console);
994d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			if (ret == 0) {
995d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox				struct vc_data *nvc;
996d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox				/* This is safe providing we don't drop the
997d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox				   console sem between vc_allocate and
998d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox				   finishing referencing nvc */
999d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox				nvc = vc_cons[vsa.console].d;
1000d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox				nvc->vt_mode = vsa.mode;
1001d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox				nvc->vt_mode.frsig = 0;
1002d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox				put_pid(nvc->vt_pid);
1003d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox				nvc->vt_pid = get_pid(task_pid(current));
1004d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			}
1005d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			release_console_sem();
1006d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			if (ret)
1007d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox				break;
1008d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			/* Commence switch and lock */
1009d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox			set_console(arg);
1010d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox		}
1011d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox	}
1012d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * wait until the specified VT has been activated
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_WAITACTIVE:
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
10189cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg == 0 || arg > MAX_NR_CONSOLES)
10209cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -ENXIO;
10219cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else
10228b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox			ret = vt_waitactive(arg);
10239cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If a vt is under process control, the kernel will not switch to it
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * immediately, but postpone the operation until the process calls this
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ioctl, allowing the switch to complete.
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * According to the X sources this is the behavior:
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	0:	pending switch-from not OK
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	1:	pending switch-from OK
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	2:	completed switch-to OK
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_RELDISP:
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
10379cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10399cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (vc->vt_mode.mode != VT_PROCESS) {
10409cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EINVAL;
10419cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
10429cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Switching-from response
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
10468792f961ba8057d9f27987def3600253a3ba060fSamuel Ortiz		acquire_console_sem();
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (vc->vt_newvt >= 0) {
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (arg == 0)
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * Switch disallowed, so forget we were trying
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * to do it.
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				vc->vt_newvt = -1;
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else {
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * The current vt has been released, so
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * complete the switch.
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int newvt;
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				newvt = vc->vt_newvt;
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				vc->vt_newvt = -1;
10639cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				ret = vc_allocate(newvt);
10649cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				if (ret) {
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					release_console_sem();
10669cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					break;
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * When we actually do the console switch,
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * make sure we are atomic with respect to
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * other console switches..
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				complete_change_console(vc_cons[newvt].d);
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
10759cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		} else {
10769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			/*
10779cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			 * Switched-to response
10789cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			 */
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * If it's just an ACK, ignore it
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
10829cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			if (arg != VT_ACKACQ)
10839cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				ret = -EINVAL;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10858792f961ba8057d9f27987def3600253a3ba060fSamuel Ortiz		release_console_sem();
10869cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 /*
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  * Disallocate memory associated to VT (but leave VT1)
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  */
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 case VT_DISALLOCATE:
10929cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (arg > MAX_NR_CONSOLES) {
10939cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -ENXIO;
10949cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
10959cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (arg == 0) {
1097ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox		    /* deallocate all unused consoles, but leave 0 */
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			acquire_console_sem();
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i=1; i<MAX_NR_CONSOLES; i++)
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (! VT_BUSY(i))
1101ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox					vc_deallocate(i);
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_console_sem();
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
1104ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox			/* deallocate a single console, if possible */
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			arg--;
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (VT_BUSY(arg))
11079cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				ret = -EBUSY;
11089cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			else if (arg) {			      /* leave 0 */
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				acquire_console_sem();
1110ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox				vc_deallocate(arg);
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				release_console_sem();
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11149cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_RESIZE:
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct vt_sizes __user *vtsizes = up;
1119e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas		struct vc_data *vc;
1120e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ushort ll,cc;
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
11239cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (get_user(ll, &vtsizes->v_rows) ||
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    get_user(cc, &vtsizes->v_cols))
11269cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
11279cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else {
11288c9a9dd0fa3a269d380eaae2dc1bee39e865fae1Alan Cox			acquire_console_sem();
11299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			for (i = 0; i < MAX_NR_CONSOLES; i++) {
11309cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				vc = vc_cons[i].d;
1131e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas
11329cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				if (vc) {
11339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					vc->vc_resize_user = 1;
11348c9a9dd0fa3a269d380eaae2dc1bee39e865fae1Alan Cox					vc_resize(vc_cons[i].d, cc, ll);
11359cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				}
1136e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas			}
11378c9a9dd0fa3a269d380eaae2dc1bee39e865fae1Alan Cox			release_console_sem();
1138e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas		}
11399cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_RESIZEX:
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct vt_consize __user *vtconsize = up;
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ushort ll,cc,vlin,clin,vcol,ccol;
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
11479cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!access_ok(VERIFY_READ, vtconsize,
11499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				sizeof(struct vt_consize))) {
11509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
11519cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
11529cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
11539cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		/* FIXME: Should check the copies properly */
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(ll, &vtconsize->v_rows);
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(cc, &vtconsize->v_cols);
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(vlin, &vtconsize->v_vlin);
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(clin, &vtconsize->v_clin);
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(vcol, &vtconsize->v_vcol);
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__get_user(ccol, &vtconsize->v_ccol);
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vlin = vlin ? vlin : vc->vc_scan_lines;
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (clin) {
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ll) {
11639cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				if (ll != vlin/clin) {
11649cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					/* Parameters don't add up */
11659cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					ret = -EINVAL;
11669cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					break;
11679cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				}
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ll = vlin/clin;
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (vcol && ccol) {
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (cc) {
11739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				if (cc != vcol/ccol) {
11749cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					ret = -EINVAL;
11759cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					break;
11769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox				}
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cc = vcol/ccol;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11819cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (clin > 32) {
11829cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret =  -EINVAL;
11839cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
11849cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < MAX_NR_CONSOLES; i++) {
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!vc_cons[i].d)
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				continue;
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			acquire_console_sem();
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (vlin)
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				vc_cons[i].d->vc_scan_lines = vlin;
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (clin)
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				vc_cons[i].d->vc_font.height = clin;
1194e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas			vc_cons[i].d->vc_resize_user = 1;
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			vc_resize(vc_cons[i].d, cc, ll);
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_console_sem();
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11989cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_FONT: {
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
12039cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.op = KD_FONT_OP_SET;
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC;	/* Compatibility */
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.width = 8;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.height = 0;
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.charcount = 256;
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.data = up;
12109cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_font_op(vc_cons[fg_console].d, &op);
12119cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_FONT: {
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.op = KD_FONT_OP_GET;
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.flags = KD_FONT_FLAG_OLD;
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.width = 8;
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.height = 32;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.charcount = 256;
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.data = up;
12219cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_font_op(vc_cons[fg_console].d, &op);
12229cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_CMAP:
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                if (!perm)
12279cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EPERM;
12289cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else
12299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	                ret = con_set_cmap(up);
12309cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_CMAP:
12339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox                ret = con_get_cmap(up);
12349cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_FONTX:
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_FONTX:
12389cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = do_fontx_ioctl(cmd, up, perm, &op);
12399cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_FONTRESET:
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
12449cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BROKEN_GRAPHICS_PROGRAMS
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   font is not saved. */
12499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = -ENOSYS;
12509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.op = KD_FONT_OP_SET_DEFAULT;
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.data = NULL;
12559cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_font_op(vc_cons[fg_console].d, &op);
12569cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (ret)
12579cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		con_set_default_unimap(vc_cons[fg_console].d);
12599cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case KDFONTOP: {
12659cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (copy_from_user(&op, up, sizeof(op))) {
12669cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
12679cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
12689cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		}
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm && op.op != KD_FONT_OP_GET)
12709cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
12719cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_font_op(vc, &op);
12729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		if (ret)
12739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			break;
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(up, &op, sizeof(op)))
12759cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EFAULT;
12769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_SCRNMAP:
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
12819cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EPERM;
12829cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else
12839cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = con_set_trans_old(up);
12849cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_SCRNMAP:
12879cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_get_trans_old(up);
12889cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_UNISCRNMAP:
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
12929cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = -EPERM;
12939cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		else
12949cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			ret = con_set_trans_new(up);
12959cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_UNISCRNMAP:
12989cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = con_get_trans_new(up);
12999cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_UNIMAPCLR:
13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      { struct unimapinit ui;
13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!perm)
13049cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
13059cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
13063fde85df5421eb01f563fef6f111ba73ab0d120eDan Carpenter		if (ret)
13073fde85df5421eb01f563fef6f111ba73ab0d120eDan Carpenter			ret = -EFAULT;
13083fde85df5421eb01f563fef6f111ba73ab0d120eDan Carpenter		else
13099cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			con_clear_unimap(vc, &ui);
13109cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      }
13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PIO_UNIMAP:
13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case GIO_UNIMAP:
13159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = do_unimap_ioctl(cmd, up, perm, vc);
13169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_LOCKSWITCH:
13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_SYS_TTY_CONFIG))
13209cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vt_dont_switch = 1;
13229cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT_UNLOCKSWITCH:
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!capable(CAP_SYS_TTY_CONFIG))
13259cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox			goto eperm;
13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vt_dont_switch = 0;
13279cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
1328533475d3d48eb839be2b57f6b020150abae91063Samuel Thibault	case VT_GETHIFONTMASK:
13299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = put_user(vc->vc_hi_font_mask,
13309cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox					(unsigned short __user *)arg);
13319cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		break;
13328b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	case VT_WAITEVENT:
13338b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
13348b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox		break;
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
13369cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox		ret = -ENOIOCTLCMD;
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13389cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Coxout:
13399cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	unlock_kernel();
13409cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	return ret;
13419cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Coxeperm:
13429cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	ret = -EPERM;
13439cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox	goto out;
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid reset_vc(struct vc_data *vc)
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vc_mode = KD_TEXT;
13492e8ecb9db0bcc19e1cc8bb51e9252fe6a86a9863Bill Nottingham	kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_mode.mode = VT_AUTO;
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_mode.waitv = 0;
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_mode.relsig = 0;
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_mode.acqsig = 0;
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_mode.frsig = 0;
13558b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	put_pid(vc->vt_pid);
13568b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	vc->vt_pid = NULL;
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc->vt_newvt = -1;
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		reset_palette(vc);
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13628b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biedermanvoid vc_SAK(struct work_struct *work)
13638b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman{
13648b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	struct vc *vc_con =
13658b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		container_of(work, struct vc, SAK_work);
13668b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	struct vc_data *vc;
13678b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	struct tty_struct *tty;
13688b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman
13698b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	acquire_console_sem();
13708b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	vc = vc_con->d;
13718b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	if (vc) {
13728ce73264b75be4d5ed480440ac32dfc1f25ff678Alan Cox		tty = vc->port.tty;
13738b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		/*
13748b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		 * SAK should also work in all raw modes and reset
13758b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		 * them properly.
13768b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		 */
13778b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		if (tty)
13788b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman			__do_SAK(tty);
13798b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman		reset_vc(vc);
13808b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	}
13818b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman	release_console_sem();
13828b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman}
13838b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman
1384e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann#ifdef CONFIG_COMPAT
1385e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1386e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstruct compat_consolefontdesc {
1387e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	unsigned short charcount;       /* characters in font (256 or 512) */
1388e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	unsigned short charheight;      /* scan lines per character (1-32) */
1389e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	compat_caddr_t chardata;	/* font data in expanded form */
1390e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann};
1391e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1392e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstatic inline int
1393e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmanncompat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
1394e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann			 int perm, struct console_font_op *op)
1395e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann{
1396e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	struct compat_consolefontdesc cfdarg;
1397e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	int i;
1398e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1399e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
1400e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		return -EFAULT;
1401e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1402e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	switch (cmd) {
1403e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case PIO_FONTX:
1404e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		if (!perm)
1405e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann			return -EPERM;
1406e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->op = KD_FONT_OP_SET;
1407e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->flags = KD_FONT_FLAG_OLD;
1408e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->width = 8;
1409e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->height = cfdarg.charheight;
1410e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->charcount = cfdarg.charcount;
1411e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->data = compat_ptr(cfdarg.chardata);
1412e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		return con_font_op(vc_cons[fg_console].d, op);
1413e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case GIO_FONTX:
1414e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->op = KD_FONT_OP_GET;
1415e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->flags = KD_FONT_FLAG_OLD;
1416e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->width = 8;
1417e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->height = cfdarg.charheight;
1418e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->charcount = cfdarg.charcount;
1419e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		op->data = compat_ptr(cfdarg.chardata);
1420e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		i = con_font_op(vc_cons[fg_console].d, op);
1421e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		if (i)
1422e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann			return i;
1423e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		cfdarg.charheight = op->height;
1424e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		cfdarg.charcount = op->charcount;
1425e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
1426e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann			return -EFAULT;
1427e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		return 0;
1428e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	}
1429e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	return -EINVAL;
1430e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann}
1431e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1432e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstruct compat_console_font_op {
1433e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	compat_uint_t op;        /* operation code KD_FONT_OP_* */
1434e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	compat_uint_t flags;     /* KD_FONT_FLAG_* */
1435e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	compat_uint_t width, height;     /* font size */
1436e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	compat_uint_t charcount;
1437e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	compat_caddr_t data;    /* font data with height fixed to 32 */
1438e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann};
1439e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1440e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstatic inline int
1441e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmanncompat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
1442e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann			 int perm, struct console_font_op *op, struct vc_data *vc)
1443e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann{
1444e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	int i;
1445e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1446e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
1447e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		return -EFAULT;
1448e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	if (!perm && op->op != KD_FONT_OP_GET)
1449e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		return -EPERM;
1450e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
1451e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	op->flags |= KD_FONT_FLAG_OLD;
1452e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	i = con_font_op(vc, op);
1453e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	if (i)
1454e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		return i;
1455e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
1456e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
1457e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		return -EFAULT;
1458e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	return 0;
1459e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann}
1460e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1461e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstruct compat_unimapdesc {
1462e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	unsigned short entry_ct;
1463e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	compat_caddr_t entries;
1464e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann};
1465e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1466e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstatic inline int
1467e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmanncompat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
1468e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann			 int perm, struct vc_data *vc)
1469e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann{
1470e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	struct compat_unimapdesc tmp;
1471e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	struct unipair __user *tmp_entries;
1472e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1473e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	if (copy_from_user(&tmp, user_ud, sizeof tmp))
1474e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		return -EFAULT;
1475e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	tmp_entries = compat_ptr(tmp.entries);
1476e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	if (tmp_entries)
1477e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		if (!access_ok(VERIFY_WRITE, tmp_entries,
1478e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann				tmp.entry_ct*sizeof(struct unipair)))
1479e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann			return -EFAULT;
1480e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	switch (cmd) {
1481e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case PIO_UNIMAP:
1482e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		if (!perm)
1483e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann			return -EPERM;
1484e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
1485e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case GIO_UNIMAP:
1486e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		if (!perm && fg_console != vc->vc_num)
1487e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann			return -EPERM;
1488e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
1489e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	}
1490e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	return 0;
1491e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann}
1492e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1493e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannlong vt_compat_ioctl(struct tty_struct *tty, struct file * file,
1494e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	     unsigned int cmd, unsigned long arg)
1495e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann{
1496e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	struct vc_data *vc = tty->driver_data;
1497e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	struct console_font_op op;	/* used in multiple places here */
1498e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	struct kbd_struct *kbd;
1499e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	unsigned int console;
1500e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	void __user *up = (void __user *)arg;
1501e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	int perm;
1502e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	int ret = 0;
1503e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1504e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	console = vc->vc_num;
1505e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1506e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	lock_kernel();
1507e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1508e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	if (!vc_cons_allocated(console)) { 	/* impossible? */
1509e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		ret = -ENOIOCTLCMD;
1510e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		goto out;
1511e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	}
1512e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1513e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	/*
1514e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	 * To have permissions to do most of the vt ioctls, we either have
1515e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
1516e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	 */
1517e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	perm = 0;
1518e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
1519e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		perm = 1;
1520e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1521e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	kbd = kbd_table + console;
1522e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	switch (cmd) {
1523e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	/*
1524e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	 * these need special handlers for incompatible data structures
1525e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	 */
1526e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case PIO_FONTX:
1527e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case GIO_FONTX:
1528e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		ret = compat_fontx_ioctl(cmd, up, perm, &op);
1529e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		break;
1530e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1531e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDFONTOP:
1532e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		ret = compat_kdfontop_ioctl(up, perm, &op, vc);
1533e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		break;
1534e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1535e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case PIO_UNIMAP:
1536e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case GIO_UNIMAP:
15374b1fe7797270e866adc17fc603bddf8768bc187fAndreas Schwab		ret = compat_unimap_ioctl(cmd, up, perm, vc);
1538e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		break;
1539e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1540e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	/*
1541e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	 * all these treat 'arg' as an integer
1542e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	 */
1543e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KIOCSOUND:
1544e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDMKTONE:
1545e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann#ifdef CONFIG_X86
1546e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDADDIO:
1547e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDDELIO:
1548e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann#endif
1549e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDSETMODE:
1550e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDMAPDISP:
1551e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDUNMAPDISP:
1552e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDSKBMODE:
1553e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDSKBMETA:
1554e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDSKBLED:
1555e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDSETLED:
1556e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case KDSIGACCEPT:
1557e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case VT_ACTIVATE:
1558e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case VT_WAITACTIVE:
1559e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case VT_RELDISP:
1560e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case VT_DISALLOCATE:
1561e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case VT_RESIZE:
1562e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	case VT_RESIZEX:
1563e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		goto fallback;
1564e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1565e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	/*
1566e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	 * the rest has a compatible data structure behind arg,
1567e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	 * but we have to convert it to a proper 64 bit pointer.
1568e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	 */
1569e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	default:
1570e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		arg = (unsigned long)compat_ptr(arg);
1571e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann		goto fallback;
1572e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	}
1573e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannout:
1574e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	unlock_kernel();
1575e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	return ret;
1576e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1577e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannfallback:
1578e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	unlock_kernel();
1579e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann	return vt_ioctl(tty, file, cmd, arg);
1580e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann}
1581e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1582e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1583e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann#endif /* CONFIG_COMPAT */
1584e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
1585e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1587d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox * Performs the back end of a vt switch. Called under the console
1588d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox * semaphore.
15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void complete_change_console(struct vc_data *vc)
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char old_vc_mode;
15938b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	int old = fg_console;
15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	last_console = fg_console;
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If we're switching, we could be going from KD_GRAPHICS to
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * KD_TEXT mode or vice versa, which means we need to blank or
16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * unblank the screen later.
16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_vc_mode = vc_cons[fg_console].d->vc_mode;
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch_screen(vc);
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16063dfcaf16135150d0f025047a7525664a41bb2adfEric W. Biederman	 * This can't appear below a successful kill_pid().  If it did,
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * then the *blank_screen operation could occur while X, having
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * received acqsig, is waking up on another processor.  This
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * condition can lead to overlapping accesses to the VGA range
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * and the framebuffer (causing system lockups).
16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * To account for this we duplicate this code below only if the
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * controlling process is gone and we've called reset_vc.
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old_vc_mode != vc->vc_mode) {
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (vc->vc_mode == KD_TEXT)
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_unblank_screen(1);
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			do_blank_screen(1);
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If this new console is under process control, send it a signal
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * telling it that it has acquired. Also check if it has died and
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * clean up (similar to logic employed in change_console())
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
162787a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman	if (vc->vt_mode.mode == VT_PROCESS) {
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
16293dfcaf16135150d0f025047a7525664a41bb2adfEric W. Biederman		 * Send the signal as privileged - kill_pid() will
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * tell us if the process has gone or something else
16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * is awry
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1633bde0d2c98bcfc9acc83ac79c33a6ac1335b95a92Eric W. Biederman		if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * The controlling process has died, so we revert back to
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * normal operation. In this case, we'll also change back
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to KD_TEXT mode. I'm not sure if this is strictly correct
16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * but it saves the agony when the X server dies and the screen
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * remains blanked due to KD_GRAPHICS! It would be nice to do
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * this outside of VT_PROCESS but there is no single process
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * to account for and tracking tty count may be undesirable.
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			reset_vc(vc);
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (old_vc_mode != vc->vc_mode) {
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (vc->vc_mode == KD_TEXT)
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					do_unblank_screen(1);
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					do_blank_screen(1);
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Wake anyone waiting for their VT to activate
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16578b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox	vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Performs the front-end of a vt switch
16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid change_console(struct vc_data *new_vc)
16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct vc_data *vc;
16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If this vt is in process mode, then we need to handshake with
16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * that process before switching. Essentially, we store where that
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * vt wants to switch to and wait for it to tell us when it's done
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (via VT_RELDISP ioctl).
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We also check to see if the controlling process still exists.
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If it doesn't, we reset this vt to auto mode and continue.
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This is a cheap way to track process control. The worst thing
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * that can happen is: we send a signal to a process, it dies, and
16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the switch gets "lost" waiting for a response; hopefully, the
16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * user will try again, we'll detect the process is gone (unless
16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the user waits just the right amount of time :-) and revert the
16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * vt to auto control.
16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vc = vc_cons[fg_console].d;
168787a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman	if (vc->vt_mode.mode == VT_PROCESS) {
16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
16893dfcaf16135150d0f025047a7525664a41bb2adfEric W. Biederman		 * Send the signal as privileged - kill_pid() will
16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * tell us if the process has gone or something else
1691a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe		 * is awry.
1692a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe		 *
1693a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe		 * We need to set vt_newvt *before* sending the signal or we
1694a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe		 * have a race.
16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1696a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe		vc->vt_newvt = new_vc->vc_num;
1697bde0d2c98bcfc9acc83ac79c33a6ac1335b95a92Eric W. Biederman		if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
169987a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman			 * It worked. Mark the vt to switch to and
170087a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman			 * return. The process needs to send us a
170187a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman			 * VT_RELDISP ioctl to complete the switch.
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
170387a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman			return;
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
170787a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		 * The controlling process has died, so we revert back to
170887a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		 * normal operation. In this case, we'll also change back
170987a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		 * to KD_TEXT mode. I'm not sure if this is strictly correct
171087a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		 * but it saves the agony when the X server dies and the screen
171187a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		 * remains blanked due to KD_GRAPHICS! It would be nice to do
171287a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		 * this outside of VT_PROCESS but there is no single process
171387a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		 * to account for and tracking tty count may be undesirable.
171487a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		 */
171587a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		reset_vc(vc);
171687a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman
171787a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		/*
171887a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman		 * Fall through to normal (VT_AUTO) handling of the switch...
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vc->vc_mode == KD_GRAPHICS)
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	complete_change_console(new_vc);
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
17308d233558cd99a888571bb5a88a74970879e0aba4Alan Cox
17318d233558cd99a888571bb5a88a74970879e0aba4Alan Cox/* Perform a kernel triggered VT switch for suspend/resume */
17328d233558cd99a888571bb5a88a74970879e0aba4Alan Cox
17338d233558cd99a888571bb5a88a74970879e0aba4Alan Coxstatic int disable_vt_switch;
17348d233558cd99a888571bb5a88a74970879e0aba4Alan Cox
17358d233558cd99a888571bb5a88a74970879e0aba4Alan Coxint vt_move_to_console(unsigned int vt, int alloc)
17368d233558cd99a888571bb5a88a74970879e0aba4Alan Cox{
17378d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	int prev;
17388d233558cd99a888571bb5a88a74970879e0aba4Alan Cox
17398d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	acquire_console_sem();
17408d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	/* Graphics mode - up to X */
17418d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	if (disable_vt_switch) {
17428d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		release_console_sem();
17438d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		return 0;
17448d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	}
17458d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	prev = fg_console;
17468d233558cd99a888571bb5a88a74970879e0aba4Alan Cox
17478d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	if (alloc && vc_allocate(vt)) {
17488d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		/* we can't have a free VC for now. Too bad,
17498d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		 * we don't want to mess the screen for now. */
17508d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		release_console_sem();
17518d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		return -ENOSPC;
17528d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	}
17538d233558cd99a888571bb5a88a74970879e0aba4Alan Cox
17548d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	if (set_console(vt)) {
17558d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		/*
17568d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		 * We're unable to switch to the SUSPEND_CONSOLE.
17578d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		 * Let the calling function know so it can decide
17588d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		 * what to do.
17598d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		 */
17608d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		release_console_sem();
17618d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		return -EIO;
17628d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	}
17638d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	release_console_sem();
1764797938b5e33991dadf4dd9228b932cc69c3e905aJiri Slaby	if (vt_waitactive(vt + 1)) {
17658d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		pr_debug("Suspend: Can't switch VCs.");
17668d233558cd99a888571bb5a88a74970879e0aba4Alan Cox		return -EINTR;
17678d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	}
17688d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	return prev;
17698d233558cd99a888571bb5a88a74970879e0aba4Alan Cox}
17708d233558cd99a888571bb5a88a74970879e0aba4Alan Cox
17718d233558cd99a888571bb5a88a74970879e0aba4Alan Cox/*
17728d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * Normally during a suspend, we allocate a new console and switch to it.
17738d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * When we resume, we switch back to the original console.  This switch
17748d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * can be slow, so on systems where the framebuffer can handle restoration
17758d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * of video registers anyways, there's little point in doing the console
17768d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * switch.  This function allows you to disable it by passing it '0'.
17778d233558cd99a888571bb5a88a74970879e0aba4Alan Cox */
17788d233558cd99a888571bb5a88a74970879e0aba4Alan Coxvoid pm_set_vt_switch(int do_switch)
17798d233558cd99a888571bb5a88a74970879e0aba4Alan Cox{
17808d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	acquire_console_sem();
17818d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	disable_vt_switch = !do_switch;
17828d233558cd99a888571bb5a88a74970879e0aba4Alan Cox	release_console_sem();
17838d233558cd99a888571bb5a88a74970879e0aba4Alan Cox}
17848d233558cd99a888571bb5a88a74970879e0aba4Alan CoxEXPORT_SYMBOL(pm_set_vt_switch);
1785