vt_ioctl.c revision 247ff8e610cb63c015de19191db9666754c2ed79
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1992 obz under the linux copyright 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Some code moved for less code duplication - Andi Kleen - Mar 1997 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 17e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann#include <linux/compat.h> 188d233558cd99a888571bb5a88a74970879e0aba4Alan Cox#include <linux/module.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kd.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vt.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h> 2604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault#include <linux/consolemap.h> 277ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl#include <linux/signal.h> 28bcc8ca09920755520ba8a1e2d9f72fe8ff892643Emmanuel Colbus#include <linux/timex.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kbd_kern.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vt_kern.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kbd_diacr.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/selection.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38b257bc051f06607beb3004d9a1c297085e728becAndrew Johnsonchar vt_dont_switch; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern struct tty_driver *console_driver; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VT_IS_IN_USE(i) (console_driver->ttys[i] && console_driver->ttys[i]->count) 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons) 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Console (vt and kd) routines, as defined by USL SVR4 manual, and by 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * experimentation and study of X386 SYSV handling. 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the current console is done by the main ioctl code. 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/syscalls.h> 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void complete_change_console(struct vc_data *vc); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 648b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * User space VT_EVENT handlers 658b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox */ 668b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 678b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstruct vt_event_wait { 688b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox struct list_head list; 698b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox struct vt_event event; 708b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox int done; 718b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox}; 728b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 738b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstatic LIST_HEAD(vt_events); 748b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstatic DEFINE_SPINLOCK(vt_event_lock); 758b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstatic DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue); 768b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 778b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox/** 788b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * vt_event_post 798b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * @event: the event that occurred 808b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * @old: old console 818b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * @new: new console 828b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * 838b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * Post an VT event to interested VT handlers 848b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox */ 858b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 868b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxvoid vt_event_post(unsigned int event, unsigned int old, unsigned int new) 878b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox{ 888b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox struct list_head *pos, *head; 898b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox unsigned long flags; 908b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox int wake = 0; 918b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 928b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox spin_lock_irqsave(&vt_event_lock, flags); 938b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox head = &vt_events; 948b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 958b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox list_for_each(pos, head) { 968b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox struct vt_event_wait *ve = list_entry(pos, 978b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox struct vt_event_wait, list); 988b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox if (!(ve->event.event & event)) 998b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox continue; 1008b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox ve->event.event = event; 1018b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox /* kernel view is consoles 0..n-1, user space view is 1028b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox console 1..n with 0 meaning current, so we must bias */ 103308efab5e231d1510cd35931d87629bf5171caaeAlan Cox ve->event.oldev = old + 1; 104308efab5e231d1510cd35931d87629bf5171caaeAlan Cox ve->event.newev = new + 1; 1058b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox wake = 1; 1068b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox ve->done = 1; 1078b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox } 1088b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox spin_unlock_irqrestore(&vt_event_lock, flags); 1098b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox if (wake) 1108b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox wake_up_interruptible(&vt_event_waitqueue); 1118b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox} 1128b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 1138b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox/** 1148b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * vt_event_wait - wait for an event 1158b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * @vw: our event 1168b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * 1178b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * Waits for an event to occur which completes our vt_event_wait 1188b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * structure. On return the structure has wv->done set to 1 for success 1198b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * or 0 if some event such as a signal ended the wait. 1208b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox */ 1218b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 1228b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstatic void vt_event_wait(struct vt_event_wait *vw) 1238b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox{ 1248b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox unsigned long flags; 1258b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox /* Prepare the event */ 1268b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox INIT_LIST_HEAD(&vw->list); 1278b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox vw->done = 0; 1288b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox /* Queue our event */ 1298b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox spin_lock_irqsave(&vt_event_lock, flags); 1308b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox list_add(&vw->list, &vt_events); 1318b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox spin_unlock_irqrestore(&vt_event_lock, flags); 1328b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox /* Wait for it to pass */ 133be1bc2889a4db4961ef69f47fb471ecae9f23adeArnd Bergmann wait_event_interruptible_tty(vt_event_waitqueue, vw->done); 1348b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox /* Dequeue it */ 1358b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox spin_lock_irqsave(&vt_event_lock, flags); 1368b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox list_del(&vw->list); 1378b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox spin_unlock_irqrestore(&vt_event_lock, flags); 1388b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox} 1398b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 1408b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox/** 1418b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * vt_event_wait_ioctl - event ioctl handler 1428b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * @arg: argument to ioctl 1438b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * 1448b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * Implement the VT_WAITEVENT ioctl using the VT event interface 1458b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox */ 1468b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 1478b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxstatic int vt_event_wait_ioctl(struct vt_event __user *event) 1488b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox{ 1498b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox struct vt_event_wait vw; 1508b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 1518b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox if (copy_from_user(&vw.event, event, sizeof(struct vt_event))) 1528b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox return -EFAULT; 1538b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox /* Highest supported event for now */ 1548b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox if (vw.event.event & ~VT_MAX_EVENT) 1558b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox return -EINVAL; 1568b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 1578b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox vt_event_wait(&vw); 1588b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox /* If it occurred report it */ 1598b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox if (vw.done) { 1608b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox if (copy_to_user(event, &vw.event, sizeof(struct vt_event))) 1618b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox return -EFAULT; 1628b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox return 0; 1638b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox } 1648b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox return -EINTR; 1658b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox} 1668b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 1678b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox/** 1688b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * vt_waitactive - active console wait 1698b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * @event: event code 1708b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * @n: new console 1718b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * 1728b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * Helper for event waits. Used to implement the legacy 1738b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox * event waiting ioctls in terms of events 1748b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox */ 1758b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 1768b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Coxint vt_waitactive(int n) 1778b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox{ 1788b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox struct vt_event_wait vw; 1798b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox do { 1808b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox if (n == fg_console + 1) 1818b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox break; 1828b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox vw.event.event = VT_EVENT_SWITCH; 1838b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox vt_event_wait(&vw); 1848b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox if (vw.done == 0) 1858b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox return -EINTR; 186308efab5e231d1510cd35931d87629bf5171caaeAlan Cox } while (vw.event.newev != n); 1878b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox return 0; 1888b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox} 1898b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 1908b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox/* 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * these are the valid i/o ports we're allowed to change. they map all the 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * video ports 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GPFIRST 0x3b4 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GPLAST 0x3df 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GPNUM (GPLAST - GPFIRST + 1) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define i (tmp.kb_index) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define s (tmp.kb_table) 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define v (tmp.kb_value) 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbentry tmp; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort *key_map, val, ov; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 210e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti if (!capable(CAP_SYS_TTY_CONFIG)) 211e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti perm = 0; 212e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBENT: 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map = key_maps[s]; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (key_map) { 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = U(key_map[i]); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = K_HOLE; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (i ? K_HOLE : K_NOSUCHMAP); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(val, &user_kbe->kb_value); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBENT: 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i && v == K_NOSUCHMAP) { 227ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox /* deallocate map */ 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map = key_maps[s]; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s && key_map) { 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_maps[s] = NULL; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (key_map[0] == U(K_ALLOCATED)) { 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(key_map); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keymap_count--; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KTYP(v) < NR_TYPES) { 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KVAL(v) > max_vals[KTYP(v)]) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->kbdmode != VC_UNICODE) 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ++Geert: non-PC keyboards may generate keycode zero */ 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if !defined(__mc68000__) && !defined(__powerpc__) 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* assignment to entry 0 only tests validity of args */ 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i) 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(key_map = key_maps[s])) { 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !capable(CAP_SYS_RESOURCE)) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2605cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day key_map = kmalloc(sizeof(plain_map), 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GFP_KERNEL); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!key_map) 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_maps[s] = key_map; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map[0] = U(K_ALLOCATED); 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 1; j < NR_KEYS; j++) 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map[j] = U(K_HOLE); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keymap_count++; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ov = U(key_map[i]); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (v == ov) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* nothing to do */ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attention Key. 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map[i] = U(v); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds compute_shiftstate(); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef i 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef s 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef v 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm) 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbkeycode tmp; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int kc = 0; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGETKEYCODE: 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kc = getkeycode(tmp.scancode); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kc >= 0) 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kc = put_user(kc, &user_kbkc->keycode); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSETKEYCODE: 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kc = setkeycode(tmp.scancode, tmp.keycode); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return kc; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbsentry *kbs; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *p; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char *q; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char __user *up; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int sz; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int delta; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *first_free, *fj, *fnw; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j, k; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3250b360adbdb54d5b98b78d57ba0916bc4b8871968Andrew Morton if (!capable(CAP_SYS_TTY_CONFIG)) 326e3f17f0f6e98f58edb13cb38810d93e6d4808e68Marcelo Tosatti perm = 0; 3270b360adbdb54d5b98b78d57ba0916bc4b8871968Andrew Morton 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbs) { 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reterr; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we mostly copy too much here (512bytes), but who cares ;) */ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EFAULT; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reterr; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = kbs->kb_func; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBSENT: 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sz = sizeof(kbs->kb_string) - 1; /* sz should have been 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds a struct member */ 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up = user_kdgkb->kb_string; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = func_table[i]; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(p) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for ( ; *p && sz; p++, sz--) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user(*p, up++)) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EFAULT; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reterr; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user('\0', up)) { 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EFAULT; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reterr; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbs); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ((p && *p) ? -EOVERFLOW : 0); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBSENT: 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) { 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EPERM; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reterr; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q = func_table[i]; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds first_free = funcbufptr + (funcbufsize - funcbufleft); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (j < MAX_NR_FUNC) 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fj = func_table[j]; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fj = first_free; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (delta <= funcbufleft) { /* it fits in current buf */ 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (j < MAX_NR_FUNC) { 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memmove(fj + delta, fj, first_free - fj); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (k = j; k < MAX_NR_FUNC; k++) 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func_table[k]) 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func_table[k] += delta; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!q) 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func_table[i] = fj; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds funcbufleft -= delta; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* allocate a larger buffer */ 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sz = 256; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (sz < funcbufsize - funcbufleft + delta) 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sz <<= 1; 3905cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day fnw = kmalloc(sz, GFP_KERNEL); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(!fnw) { 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reterr; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!q) 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func_table[i] = fj; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fj > funcbufptr) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memmove(fnw, funcbufptr, fj - funcbufptr); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (k = 0; k < j; k++) 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func_table[k]) 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func_table[k] = fnw + (func_table[k] - funcbufptr); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (first_free > fj) { 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (k = j; k < MAX_NR_FUNC; k++) 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func_table[k]) 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (funcbufptr != func_buf) 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(funcbufptr); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds funcbufptr = fnw; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds funcbufleft = funcbufleft - delta + sz - funcbufsize; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds funcbufsize = sz; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(func_table[i], kbs->kb_string); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreterr: 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbs); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct consolefontdesc cfdarg; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIO_FONTX: 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->op = KD_FONT_OP_SET; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->flags = KD_FONT_FLAG_OLD; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->width = 8; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->height = cfdarg.charheight; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->charcount = cfdarg.charcount; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->data = cfdarg.chardata; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return con_font_op(vc_cons[fg_console].d, op); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GIO_FONTX: { 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->op = KD_FONT_OP_GET; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->flags = KD_FONT_FLAG_OLD; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->width = 8; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->height = cfdarg.charheight; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->charcount = cfdarg.charcount; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op->data = cfdarg.chardata; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = con_font_op(vc_cons[fg_console].d, op); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i) 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfdarg.charheight = op->height; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfdarg.charcount = op->charcount; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc) 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct unimapdesc tmp; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&tmp, user_ud, sizeof tmp)) 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp.entries) 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!access_ok(VERIFY_WRITE, tmp.entries, 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp.entry_ct*sizeof(struct unipair))) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIO_UNIMAP: 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return con_set_unimap(vc, tmp.entry_ct, tmp.entries); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GIO_UNIMAP: 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm && fg_console != vc->vc_num) 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4898b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 4908b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We handle the console-specific ioctl's here. We allow the 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * capability to modify any console, not just the fg_console. 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4956caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxint vt_ioctl(struct tty_struct *tty, 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, unsigned long arg) 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 498c9f19e96a2f33cd56c2bd19f87a0c4982d011c2bAlan Cox struct vc_data *vc = tty->driver_data; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct console_font_op op; /* used in multiple places here */ 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbd_struct * kbd; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int console; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char ucval; 5031e0ad2881d50becaeea70ec696a80afeadf944d2Graham Gower unsigned int uival; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *up = (void __user *)arg; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, perm; 5069cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox int ret = 0; 5079cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds console = vc->vc_num; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 510ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_lock(); 5119cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox 5129cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (!vc_cons_allocated(console)) { /* impossible? */ 5139cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -ENOIOCTLCMD; 5149cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto out; 5159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 5169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To have permissions to do most of the vt ioctls, we either have 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds perm = 0; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds perm = 1; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd = kbd_table + console; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 528e6885107736a4dd23e7d3bc103fe6d043c63c4deAlan Cox case TIOCLINUX: 529a115902f67ef51fbbe83e214fb761aaa9734c1ceJiri Slaby ret = tioclinux(tty, arg); 530a115902f67ef51fbbe83e214fb761aaa9734c1ceJiri Slaby break; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KIOCSOUND: 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 5339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 5342c4e9671edfef534e9726366707d64e63d44e7e6Arnd Bergmann /* 5352c4e9671edfef534e9726366707d64e63d44e7e6Arnd Bergmann * The use of PIT_TICK_RATE is historic, it used to be 5362c4e9671edfef534e9726366707d64e63d44e7e6Arnd Bergmann * the platform-dependent CLOCK_TICK_RATE between 2.6.12 5372c4e9671edfef534e9726366707d64e63d44e7e6Arnd Bergmann * and 2.6.36, which was a minor but unfortunate ABI 5382c4e9671edfef534e9726366707d64e63d44e7e6Arnd Bergmann * change. 5392c4e9671edfef534e9726366707d64e63d44e7e6Arnd Bergmann */ 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (arg) 5412c4e9671edfef534e9726366707d64e63d44e7e6Arnd Bergmann arg = PIT_TICK_RATE / arg; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kd_mksound(arg, 0); 5439cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDMKTONE: 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 5479cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ticks, count; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Generate the tone for the appropriate number of ticks. 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the time is zero, turn off sound ourselves. 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ticks = HZ * ((arg >> 16) & 0xffff) / 1000; 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = ticks ? (arg & 0xffff) : 0; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count) 5582c4e9671edfef534e9726366707d64e63d44e7e6Arnd Bergmann count = PIT_TICK_RATE / count; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kd_mksound(count, ticks); 5609cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBTYPE: 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this is naive. 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ucval = KB_101; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto setchar; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These cannot be implemented on any machine that implements 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ioperm() in user level (such as Alpha PCs) or not at all. 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX: you should never use these, just call ioperm directly.. 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_X86 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDADDIO: 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDDELIO: 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * KDADDIO and KDDELIO may be able to add ports beyond what 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we reject here, but to be safe... 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5839cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (arg < GPFIRST || arg > GPLAST) { 5849cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 5859cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 5869cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 5879cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; 5889cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDENABIO: 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDDISABIO: 5929cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = sys_ioperm(GPFIRST, GPNUM, 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cmd == KDENABIO)) ? -ENXIO : 0; 5949cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDKBDREP: 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbd_repeat kbrep; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_TTY_CONFIG)) 6049cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6069cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) { 6079cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EFAULT; 6089cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 6099cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 6109cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = kbd_rate(&kbrep); 6119cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (ret) 6129cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat))) 6149cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EFAULT; 6159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSETMODE: 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * currently, setting the mode from KD_TEXT to KD_GRAPHICS 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * doesn't do a whole lot. i'm not sure if it should do any 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * restoration of modes or what... 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX It should at least call into the driver, fbdev's definitely 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need to restore their engine state. --BenH 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 6289cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (arg) { 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KD_GRAPHICS: 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KD_TEXT0: 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KD_TEXT1: 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg = KD_TEXT; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KD_TEXT: 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 6389cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 6399cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto out; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vc->vc_mode == (unsigned char) arg) 6429cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vc_mode = (unsigned char) arg; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (console != fg_console) 6459cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * explicitly blank/unblank the screen if switching modes 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 649ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (arg == KD_TEXT) 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_unblank_screen(1); 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_blank_screen(1); 654ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 6559cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGETMODE: 6581e0ad2881d50becaeea70ec696a80afeadf944d2Graham Gower uival = vc->vc_mode; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto setint; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDMAPDISP: 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDUNMAPDISP: 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * these work like a combination of mmap and KDENABIO. 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this could be easily finished. 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6679cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 6689cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBMODE: 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 6729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(arg) { 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case K_RAW: 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->kbdmode = VC_RAW; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case K_MEDIUMRAW: 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->kbdmode = VC_MEDIUMRAW; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case K_XLATE: 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->kbdmode = VC_XLATE; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds compute_shiftstate(); 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case K_UNICODE: 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->kbdmode = VC_UNICODE; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds compute_shiftstate(); 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6889fc3de9c83565fcaa23df74c2fc414bb6e7efb0aArthur Taylor case K_OFF: 6899fc3de9c83565fcaa23df74c2fc414bb6e7efb0aArthur Taylor kbd->kbdmode = VC_OFF; 6909fc3de9c83565fcaa23df74c2fc414bb6e7efb0aArthur Taylor break; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 6929cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 6939cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto out; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_ldisc_flush(tty); 6969cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBMODE: 6996da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton switch (kbd->kbdmode) { 7006da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton case VC_RAW: 7016da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton uival = K_RAW; 7026da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton break; 7036da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton case VC_MEDIUMRAW: 7046da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton uival = K_MEDIUMRAW; 7056da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton break; 7066da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton case VC_UNICODE: 7076da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton uival = K_UNICODE; 7086da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton break; 7096da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton case VC_OFF: 7106da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton uival = K_OFF; 7116da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton break; 7126da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton default: 7136da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton uival = K_XLATE; 7146da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton break; 7156da9e95f7381fa27bc9c66c9840b11adde778618Andrew Morton } 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto setint; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this could be folded into KDSKBMODE, but for compatibility 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBMETA: 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(arg) { 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case K_METABIT: 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clr_vc_kbd_mode(kbd, VC_META); 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case K_ESCPREFIX: 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_vc_kbd_mode(kbd, VC_META); 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 7299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7319cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBMETA: 7341e0ad2881d50becaeea70ec696a80afeadf944d2Graham Gower uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setint: 7361e0ad2881d50becaeea70ec696a80afeadf944d2Graham Gower ret = put_user(uival, (int __user *)arg); 7379cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGETKEYCODE: 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSETKEYCODE: 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(!capable(CAP_SYS_TTY_CONFIG)) 7429cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox perm = 0; 7439cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = do_kbkeycode_ioctl(cmd, up, perm); 7449cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBENT: 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBENT: 7489cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = do_kdsk_ioctl(cmd, up, perm, kbd); 7499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBSENT: 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBSENT: 7539cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = do_kdgkb_ioctl(cmd, up, perm); 7549cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 756247ff8e610cb63c015de19191db9666754c2ed79Alan Cox /* Diacritical processing. Handled in keyboard.c as it has 757247ff8e610cb63c015de19191db9666754c2ed79Alan Cox to operate on the keyboard locks and structures */ 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBDIACR: 75904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault case KDGKBDIACRUC: 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBDIACR: 76104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault case KDSKBDIACRUC: 762247ff8e610cb63c015de19191db9666754c2ed79Alan Cox ret = vt_do_diacrit(cmd, up, perm); 7639cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the ioctls below read/set the flags usually shown in the leds */ 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* don't use them - they will go away without warning */ 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBLED: 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto setchar; 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBLED: 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 7739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 7749cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (arg & ~0x77) { 7759cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 7769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 7779cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->ledflagstate = (arg & 7); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->default_ledflagstate = ((arg >> 4) & 7); 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_leds(); 7819cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the ioctls below only set the lights, not the functions */ 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* for those, see KDGKBLED and KDSKBLED above */ 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGETLED: 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ucval = getledstate(); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setchar: 7889cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = put_user(ucval, (char __user *)arg); 7899cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSETLED: 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 7939cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setledstate(kbd, arg); 7959cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A process can indicate its willingness to accept signals 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * generated by pressing an appropriate key combination. 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thus, one can have a daemon that e.g. spawns a new console 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * upon a keypress and then changes to it. 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See also the kbrequest field of inittab(5). 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSIGACCEPT: 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm || !capable(CAP_KILL)) 8079cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 8087ed20e1ad521b5f5df61bf6559ae60738e393741Jesper Juhl if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) 8099cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 8109cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox else { 8119cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox spin_lock_irq(&vt_spawn_con.lock); 8129cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox put_pid(vt_spawn_con.pid); 8139cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox vt_spawn_con.pid = get_pid(task_pid(current)); 8149cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox vt_spawn_con.sig = arg; 8159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox spin_unlock_irq(&vt_spawn_con.lock); 8169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 8179cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_SETMODE: 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct vt_mode tmp; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 8259cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 8269cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) { 8279cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EFAULT; 8289cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto out; 8299cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 83087a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) { 8319cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 8329cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto out; 8339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 834ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_mode = tmp; 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the frsig is ignored, so we set it to 0 */ 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_mode.frsig = 0; 8388b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman put_pid(vc->vt_pid); 8398b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman vc->vt_pid = get_pid(task_pid(current)); 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* no switch is required -- saw@shade.msu.ru */ 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_newvt = -1; 842ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 8439cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_GETMODE: 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct vt_mode tmp; 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode)); 853ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = copy_to_user(up, &tmp, sizeof(struct vt_mode)); 8569cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (rc) 8579cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EFAULT; 8589cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns global vt state. Note that VT 0 is always open, since 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it's an alias for the current VT, and people can't use it here. 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We cannot return state for more than 16 VTs, since v_state is short. 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_GETSTATE: 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct vt_stat __user *vtstat = up; 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short state, mask; 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user(fg_console + 1, &vtstat->v_active)) 8729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EFAULT; 8739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox else { 8749cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox state = 1; /* /dev/tty0 is always open */ 8759cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; 8769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ++i, mask <<= 1) 8779cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (VT_IS_IN_USE(i)) 8789cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox state |= mask; 8799cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = put_user(state, &vtstat->v_state); 8809cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 8819cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns the first available (non-opened) console. 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_OPENQRY: 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < MAX_NR_CONSOLES; ++i) 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (! VT_IS_IN_USE(i)) 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8911e0ad2881d50becaeea70ec696a80afeadf944d2Graham Gower uival = i < MAX_NR_CONSOLES ? (i+1) : -1; 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto setint; 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with num >= 1 (switches to vt 0, our console, are not allowed, just 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to preserve sanity). 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_ACTIVATE: 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 9019cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (arg == 0 || arg > MAX_NR_CONSOLES) 9039cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -ENXIO; 9049cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox else { 9059cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox arg--; 906ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 9079cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = vc_allocate(arg); 908ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 9099cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (ret) 9109cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 9119cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox set_console(arg); 9129cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 9139cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 915d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox case VT_SETACTIVATE: 916d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox { 917d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox struct vt_setactivate vsa; 918d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox 919d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox if (!perm) 920d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox goto eperm; 921d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox 922d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg, 923a09efb07b5025fb75f42e903d31767a3cafede89Jiri Slaby sizeof(struct vt_setactivate))) { 924a09efb07b5025fb75f42e903d31767a3cafede89Jiri Slaby ret = -EFAULT; 925a09efb07b5025fb75f42e903d31767a3cafede89Jiri Slaby goto out; 926a09efb07b5025fb75f42e903d31767a3cafede89Jiri Slaby } 927d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES) 928d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox ret = -ENXIO; 929d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox else { 930d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox vsa.console--; 931ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 932d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox ret = vc_allocate(vsa.console); 933d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox if (ret == 0) { 934d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox struct vc_data *nvc; 935d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox /* This is safe providing we don't drop the 936d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox console sem between vc_allocate and 937d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox finishing referencing nvc */ 938d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox nvc = vc_cons[vsa.console].d; 939d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox nvc->vt_mode = vsa.mode; 940d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox nvc->vt_mode.frsig = 0; 941d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox put_pid(nvc->vt_pid); 942d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox nvc->vt_pid = get_pid(task_pid(current)); 943d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox } 944ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 945d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox if (ret) 946d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox break; 947d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox /* Commence switch and lock */ 948d637837583163a1a70331ce48097f697cac85e32Jiri Olsa set_console(vsa.console); 949d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox } 950d637837583163a1a70331ce48097f697cac85e32Jiri Olsa break; 951d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox } 952d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * wait until the specified VT has been activated 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_WAITACTIVE: 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 9589cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (arg == 0 || arg > MAX_NR_CONSOLES) 9609cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -ENXIO; 9619cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox else 9628b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox ret = vt_waitactive(arg); 9639cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a vt is under process control, the kernel will not switch to it 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * immediately, but postpone the operation until the process calls this 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ioctl, allowing the switch to complete. 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * According to the X sources this is the behavior: 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0: pending switch-from not OK 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1: pending switch-from OK 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2: completed switch-to OK 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_RELDISP: 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 9779cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9799cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (vc->vt_mode.mode != VT_PROCESS) { 9809cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 9819cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 9829cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Switching-from response 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 986ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vc->vt_newvt >= 0) { 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (arg == 0) 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Switch disallowed, so forget we were trying 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to do it. 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_newvt = -1; 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The current vt has been released, so 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete the switch. 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int newvt; 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newvt = vc->vt_newvt; 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_newvt = -1; 10039cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = vc_allocate(newvt); 10049cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (ret) { 1005ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 10069cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When we actually do the console switch, 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * make sure we are atomic with respect to 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * other console switches.. 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds complete_change_console(vc_cons[newvt].d); 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } else { 10169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox /* 10179cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox * Switched-to response 10189cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox */ 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it's just an ACK, ignore it 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10229cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (arg != VT_ACKACQ) 10239cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1025ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 10269cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disallocate memory associated to VT (but leave VT1) 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_DISALLOCATE: 10329cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (arg > MAX_NR_CONSOLES) { 10339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -ENXIO; 10349cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 10359cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (arg == 0) { 1037ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox /* deallocate all unused consoles, but leave 0 */ 1038ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=1; i<MAX_NR_CONSOLES; i++) 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (! VT_BUSY(i)) 1041ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox vc_deallocate(i); 1042ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1044ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox /* deallocate a single console, if possible */ 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arg--; 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (VT_BUSY(arg)) 10479cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EBUSY; 10489cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox else if (arg) { /* leave 0 */ 1049ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 1050ca9bda00b4aafc42cd3d1b9d32934463e2993b4cAlan Cox vc_deallocate(arg); 1051ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10549cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_RESIZE: 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct vt_sizes __user *vtsizes = up; 1059e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas struct vc_data *vc; 1060e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort ll,cc; 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 10639cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(ll, &vtsizes->v_rows) || 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_user(cc, &vtsizes->v_cols)) 10669cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EFAULT; 10679cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox else { 1068ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 10699cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox for (i = 0; i < MAX_NR_CONSOLES; i++) { 10709cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox vc = vc_cons[i].d; 1071e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas 10729cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (vc) { 10739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox vc->vc_resize_user = 1; 10748c9a9dd0fa3a269d380eaae2dc1bee39e865fae1Alan Cox vc_resize(vc_cons[i].d, cc, ll); 10759cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 1076e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas } 1077ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 1078e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas } 10799cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_RESIZEX: 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct vt_consize __user *vtconsize = up; 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort ll,cc,vlin,clin,vcol,ccol; 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 10879cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!access_ok(VERIFY_READ, vtconsize, 10899cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox sizeof(struct vt_consize))) { 10909cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EFAULT; 10919cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 10929cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 10939cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox /* FIXME: Should check the copies properly */ 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __get_user(ll, &vtconsize->v_rows); 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __get_user(cc, &vtconsize->v_cols); 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __get_user(vlin, &vtconsize->v_vlin); 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __get_user(clin, &vtconsize->v_clin); 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __get_user(vcol, &vtconsize->v_vcol); 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __get_user(ccol, &vtconsize->v_ccol); 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vlin = vlin ? vlin : vc->vc_scan_lines; 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clin) { 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ll) { 11039cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (ll != vlin/clin) { 11049cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox /* Parameters don't add up */ 11059cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 11069cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11079cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ll = vlin/clin; 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vcol && ccol) { 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cc) { 11139cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (cc != vcol/ccol) { 11149cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 11159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cc = vcol/ccol; 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11219cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (clin > 32) { 11229cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EINVAL; 11239cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11249cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < MAX_NR_CONSOLES; i++) { 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!vc_cons[i].d) 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1129ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vlin) 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc_cons[i].d->vc_scan_lines = vlin; 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clin) 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc_cons[i].d->vc_font.height = clin; 1134e400b6ec4ede4dc0aa8e5640425df5b29796fe0eAntonino A. Daplas vc_cons[i].d->vc_resize_user = 1; 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc_resize(vc_cons[i].d, cc, ll); 1136ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11389cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIO_FONT: { 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 11439cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.op = KD_FONT_OP_SET; 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.width = 8; 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.height = 0; 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.charcount = 256; 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.data = up; 11509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = con_font_op(vc_cons[fg_console].d, &op); 11519cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GIO_FONT: { 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.op = KD_FONT_OP_GET; 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.flags = KD_FONT_FLAG_OLD; 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.width = 8; 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.height = 32; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.charcount = 256; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.data = up; 11619cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = con_font_op(vc_cons[fg_console].d, &op); 11629cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIO_CMAP: 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 11679cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EPERM; 11689cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox else 11699cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = con_set_cmap(up); 11709cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GIO_CMAP: 11739cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = con_get_cmap(up); 11749cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIO_FONTX: 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GIO_FONTX: 11789cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = do_fontx_ioctl(cmd, up, perm, &op); 11799cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIO_FONTRESET: 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 11849cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BROKEN_GRAPHICS_PROGRAMS 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* With BROKEN_GRAPHICS_PROGRAMS defined, the default 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds font is not saved. */ 11899cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -ENOSYS; 11909cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.op = KD_FONT_OP_SET_DEFAULT; 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds op.data = NULL; 11959cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = con_font_op(vc_cons[fg_console].d, &op); 11969cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (ret) 11979cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds con_set_default_unimap(vc_cons[fg_console].d); 11999cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDFONTOP: { 12059cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (copy_from_user(&op, up, sizeof(op))) { 12069cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EFAULT; 12079cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12089cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox } 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm && op.op != KD_FONT_OP_GET) 12109cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 12119cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = con_font_op(vc, &op); 12129cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox if (ret) 12139cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(up, &op, sizeof(op))) 12159cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EFAULT; 12169cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIO_SCRNMAP: 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 12219cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EPERM; 12229cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox else 12239cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = con_set_trans_old(up); 12249cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GIO_SCRNMAP: 12279cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = con_get_trans_old(up); 12289cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIO_UNISCRNMAP: 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 12329cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EPERM; 12339cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox else 12349cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = con_set_trans_new(up); 12359cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GIO_UNISCRNMAP: 12389cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = con_get_trans_new(up); 12399cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIO_UNIMAPCLR: 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { struct unimapinit ui; 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 12449cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 12459cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); 12463fde85df5421eb01f563fef6f111ba73ab0d120eDan Carpenter if (ret) 12473fde85df5421eb01f563fef6f111ba73ab0d120eDan Carpenter ret = -EFAULT; 12483fde85df5421eb01f563fef6f111ba73ab0d120eDan Carpenter else 12499cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox con_clear_unimap(vc, &ui); 12509cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PIO_UNIMAP: 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case GIO_UNIMAP: 12559cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = do_unimap_ioctl(cmd, up, perm, vc); 12569cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_LOCKSWITCH: 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_TTY_CONFIG)) 12609cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vt_dont_switch = 1; 12629cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case VT_UNLOCKSWITCH: 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_TTY_CONFIG)) 12659cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto eperm; 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vt_dont_switch = 0; 12679cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 1268533475d3d48eb839be2b57f6b020150abae91063Samuel Thibault case VT_GETHIFONTMASK: 12699cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = put_user(vc->vc_hi_font_mask, 12709cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox (unsigned short __user *)arg); 12719cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox break; 12728b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox case VT_WAITEVENT: 12738b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox ret = vt_event_wait_ioctl((struct vt_event __user *)arg); 12748b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox break; 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12769cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -ENOIOCTLCMD; 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12789cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Coxout: 1279ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_unlock(); 12809cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox return ret; 12819cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Coxeperm: 12829cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox ret = -EPERM; 12839cc3c22bf017f33612748aeb466fdc3695fb1e1dAlan Cox goto out; 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid reset_vc(struct vc_data *vc) 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vc_mode = KD_TEXT; 12892e8ecb9db0bcc19e1cc8bb51e9252fe6a86a9863Bill Nottingham kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_mode.mode = VT_AUTO; 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_mode.waitv = 0; 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_mode.relsig = 0; 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_mode.acqsig = 0; 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_mode.frsig = 0; 12958b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman put_pid(vc->vt_pid); 12968b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman vc->vt_pid = NULL; 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc->vt_newvt = -1; 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_palette(vc); 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13028b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biedermanvoid vc_SAK(struct work_struct *work) 13038b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman{ 13048b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman struct vc *vc_con = 13058b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman container_of(work, struct vc, SAK_work); 13068b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman struct vc_data *vc; 13078b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman struct tty_struct *tty; 13088b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman 1309ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 13108b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman vc = vc_con->d; 13118b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman if (vc) { 13128ce73264b75be4d5ed480440ac32dfc1f25ff678Alan Cox tty = vc->port.tty; 13138b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman /* 13148b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman * SAK should also work in all raw modes and reset 13158b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman * them properly. 13168b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman */ 13178b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman if (tty) 13188b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman __do_SAK(tty); 13198b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman reset_vc(vc); 13208b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman } 1321ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 13228b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman} 13238b6312f4dcc1efe7975731b6c47dd134282bd9acEric W. Biederman 1324e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann#ifdef CONFIG_COMPAT 1325e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1326e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstruct compat_consolefontdesc { 1327e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann unsigned short charcount; /* characters in font (256 or 512) */ 1328e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann unsigned short charheight; /* scan lines per character (1-32) */ 1329e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann compat_caddr_t chardata; /* font data in expanded form */ 1330e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann}; 1331e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1332e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstatic inline int 1333e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmanncompat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd, 1334e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann int perm, struct console_font_op *op) 1335e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann{ 1336e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann struct compat_consolefontdesc cfdarg; 1337e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann int i; 1338e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1339e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc))) 1340e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EFAULT; 1341e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1342e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann switch (cmd) { 1343e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case PIO_FONTX: 1344e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (!perm) 1345e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EPERM; 1346e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->op = KD_FONT_OP_SET; 1347e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->flags = KD_FONT_FLAG_OLD; 1348e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->width = 8; 1349e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->height = cfdarg.charheight; 1350e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->charcount = cfdarg.charcount; 1351e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->data = compat_ptr(cfdarg.chardata); 1352e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return con_font_op(vc_cons[fg_console].d, op); 1353e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case GIO_FONTX: 1354e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->op = KD_FONT_OP_GET; 1355e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->flags = KD_FONT_FLAG_OLD; 1356e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->width = 8; 1357e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->height = cfdarg.charheight; 1358e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->charcount = cfdarg.charcount; 1359e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->data = compat_ptr(cfdarg.chardata); 1360e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann i = con_font_op(vc_cons[fg_console].d, op); 1361e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (i) 1362e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return i; 1363e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann cfdarg.charheight = op->height; 1364e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann cfdarg.charcount = op->charcount; 1365e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc))) 1366e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EFAULT; 1367e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return 0; 1368e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann } 1369e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EINVAL; 1370e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann} 1371e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1372e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstruct compat_console_font_op { 1373e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann compat_uint_t op; /* operation code KD_FONT_OP_* */ 1374e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann compat_uint_t flags; /* KD_FONT_FLAG_* */ 1375e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann compat_uint_t width, height; /* font size */ 1376e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann compat_uint_t charcount; 1377e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann compat_caddr_t data; /* font data with height fixed to 32 */ 1378e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann}; 1379e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1380e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstatic inline int 1381e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmanncompat_kdfontop_ioctl(struct compat_console_font_op __user *fontop, 1382e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann int perm, struct console_font_op *op, struct vc_data *vc) 1383e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann{ 1384e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann int i; 1385e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1386e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op))) 1387e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EFAULT; 1388e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (!perm && op->op != KD_FONT_OP_GET) 1389e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EPERM; 1390e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann op->data = compat_ptr(((struct compat_console_font_op *)op)->data); 1391e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann i = con_font_op(vc, op); 1392e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (i) 1393e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return i; 1394e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann ((struct compat_console_font_op *)op)->data = (unsigned long)op->data; 1395e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op))) 1396e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EFAULT; 1397e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return 0; 1398e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann} 1399e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1400e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstruct compat_unimapdesc { 1401e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann unsigned short entry_ct; 1402e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann compat_caddr_t entries; 1403e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann}; 1404e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1405e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannstatic inline int 1406e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmanncompat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud, 1407e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann int perm, struct vc_data *vc) 1408e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann{ 1409e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann struct compat_unimapdesc tmp; 1410e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann struct unipair __user *tmp_entries; 1411e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1412e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (copy_from_user(&tmp, user_ud, sizeof tmp)) 1413e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EFAULT; 1414e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann tmp_entries = compat_ptr(tmp.entries); 1415e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (tmp_entries) 1416e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (!access_ok(VERIFY_WRITE, tmp_entries, 1417e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann tmp.entry_ct*sizeof(struct unipair))) 1418e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EFAULT; 1419e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann switch (cmd) { 1420e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case PIO_UNIMAP: 1421e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (!perm) 1422e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EPERM; 1423e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return con_set_unimap(vc, tmp.entry_ct, tmp_entries); 1424e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case GIO_UNIMAP: 1425e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (!perm && fg_console != vc->vc_num) 1426e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return -EPERM; 1427e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries); 1428e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann } 1429e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return 0; 1430e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann} 1431e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 14326caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxlong vt_compat_ioctl(struct tty_struct *tty, 1433e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann unsigned int cmd, unsigned long arg) 1434e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann{ 1435e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann struct vc_data *vc = tty->driver_data; 1436e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann struct console_font_op op; /* used in multiple places here */ 1437e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann unsigned int console; 1438e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann void __user *up = (void __user *)arg; 1439e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann int perm; 1440e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann int ret = 0; 1441e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1442e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann console = vc->vc_num; 1443e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1444ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_lock(); 1445e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1446e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (!vc_cons_allocated(console)) { /* impossible? */ 1447e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann ret = -ENOIOCTLCMD; 1448e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann goto out; 1449e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann } 1450e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1451e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann /* 1452e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann * To have permissions to do most of the vt ioctls, we either have 1453e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. 1454e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann */ 1455e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann perm = 0; 1456e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) 1457e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann perm = 1; 1458e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1459e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann switch (cmd) { 1460e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann /* 1461e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann * these need special handlers for incompatible data structures 1462e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann */ 1463e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case PIO_FONTX: 1464e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case GIO_FONTX: 1465e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann ret = compat_fontx_ioctl(cmd, up, perm, &op); 1466e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann break; 1467e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1468e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDFONTOP: 1469e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann ret = compat_kdfontop_ioctl(up, perm, &op, vc); 1470e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann break; 1471e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1472e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case PIO_UNIMAP: 1473e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case GIO_UNIMAP: 14744b1fe7797270e866adc17fc603bddf8768bc187fAndreas Schwab ret = compat_unimap_ioctl(cmd, up, perm, vc); 1475e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann break; 1476e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1477e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann /* 1478e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann * all these treat 'arg' as an integer 1479e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann */ 1480e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KIOCSOUND: 1481e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDMKTONE: 1482e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann#ifdef CONFIG_X86 1483e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDADDIO: 1484e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDDELIO: 1485e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann#endif 1486e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDSETMODE: 1487e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDMAPDISP: 1488e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDUNMAPDISP: 1489e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDSKBMODE: 1490e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDSKBMETA: 1491e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDSKBLED: 1492e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDSETLED: 1493e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case KDSIGACCEPT: 1494e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case VT_ACTIVATE: 1495e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case VT_WAITACTIVE: 1496e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case VT_RELDISP: 1497e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case VT_DISALLOCATE: 1498e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case VT_RESIZE: 1499e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann case VT_RESIZEX: 1500e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann goto fallback; 1501e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1502e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann /* 1503e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann * the rest has a compatible data structure behind arg, 1504e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann * but we have to convert it to a proper 64 bit pointer. 1505e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann */ 1506e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann default: 1507e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann arg = (unsigned long)compat_ptr(arg); 1508e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann goto fallback; 1509e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann } 1510e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannout: 1511ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_unlock(); 1512e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann return ret; 1513e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1514e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmannfallback: 1515ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_unlock(); 15166caa76b7786891b42b66a0e61e2c2fff2c884620Alan Cox return vt_ioctl(tty, cmd, arg); 1517e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann} 1518e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1519e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1520e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann#endif /* CONFIG_COMPAT */ 1521e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 1522e92166517e3ca9bfb416f91e69cf0373b55b6edeArnd Bergmann 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1524d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox * Performs the back end of a vt switch. Called under the console 1525d3b5cffcf84a8bdc7073dce4745d67c72629af85Alan Cox * semaphore. 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void complete_change_console(struct vc_data *vc) 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char old_vc_mode; 15308b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox int old = fg_console; 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds last_console = fg_console; 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're switching, we could be going from KD_GRAPHICS to 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * KD_TEXT mode or vice versa, which means we need to blank or 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unblank the screen later. 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_vc_mode = vc_cons[fg_console].d->vc_mode; 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch_screen(vc); 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15433dfcaf16135150d0f025047a7525664a41bb2adfEric W. Biederman * This can't appear below a successful kill_pid(). If it did, 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then the *blank_screen operation could occur while X, having 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * received acqsig, is waking up on another processor. This 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * condition can lead to overlapping accesses to the VGA range 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and the framebuffer (causing system lockups). 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To account for this we duplicate this code below only if the 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controlling process is gone and we've called reset_vc. 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_vc_mode != vc->vc_mode) { 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vc->vc_mode == KD_TEXT) 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_unblank_screen(1); 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_blank_screen(1); 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If this new console is under process control, send it a signal 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * telling it that it has acquired. Also check if it has died and 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clean up (similar to logic employed in change_console()) 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 156487a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman if (vc->vt_mode.mode == VT_PROCESS) { 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15663dfcaf16135150d0f025047a7525664a41bb2adfEric W. Biederman * Send the signal as privileged - kill_pid() will 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tell us if the process has gone or something else 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is awry 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1570bde0d2c98bcfc9acc83ac79c33a6ac1335b95a92Eric W. Biederman if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The controlling process has died, so we revert back to 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * normal operation. In this case, we'll also change back 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to KD_TEXT mode. I'm not sure if this is strictly correct 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but it saves the agony when the X server dies and the screen 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * remains blanked due to KD_GRAPHICS! It would be nice to do 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this outside of VT_PROCESS but there is no single process 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to account for and tracking tty count may be undesirable. 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_vc(vc); 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_vc_mode != vc->vc_mode) { 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vc->vc_mode == KD_TEXT) 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_unblank_screen(1); 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_blank_screen(1); 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wake anyone waiting for their VT to activate 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15948b92e87d39bfd046e7581e1fe0f40eac40f88608Alan Cox vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num); 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Performs the front-end of a vt switch 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid change_console(struct vc_data *new_vc) 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct vc_data *vc; 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch) 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If this vt is in process mode, then we need to handshake with 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that process before switching. Essentially, we store where that 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vt wants to switch to and wait for it to tell us when it's done 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (via VT_RELDISP ioctl). 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We also check to see if the controlling process still exists. 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it doesn't, we reset this vt to auto mode and continue. 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is a cheap way to track process control. The worst thing 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that can happen is: we send a signal to a process, it dies, and 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the switch gets "lost" waiting for a response; hopefully, the 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * user will try again, we'll detect the process is gone (unless 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the user waits just the right amount of time :-) and revert the 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vt to auto control. 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vc = vc_cons[fg_console].d; 162487a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman if (vc->vt_mode.mode == VT_PROCESS) { 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16263dfcaf16135150d0f025047a7525664a41bb2adfEric W. Biederman * Send the signal as privileged - kill_pid() will 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tell us if the process has gone or something else 1628a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe * is awry. 1629a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe * 1630a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe * We need to set vt_newvt *before* sending the signal or we 1631a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe * have a race. 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1633a64314e62d89562b6fc77593648bec3acc35bf61Jan Lübbe vc->vt_newvt = new_vc->vc_num; 1634bde0d2c98bcfc9acc83ac79c33a6ac1335b95a92Eric W. Biederman if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 163687a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * It worked. Mark the vt to switch to and 163787a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * return. The process needs to send us a 163887a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * VT_RELDISP ioctl to complete the switch. 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 164087a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman return; 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 164487a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * The controlling process has died, so we revert back to 164587a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * normal operation. In this case, we'll also change back 164687a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * to KD_TEXT mode. I'm not sure if this is strictly correct 164787a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * but it saves the agony when the X server dies and the screen 164887a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * remains blanked due to KD_GRAPHICS! It would be nice to do 164987a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * this outside of VT_PROCESS but there is no single process 165087a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * to account for and tracking tty count may be undesirable. 165187a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman */ 165287a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman reset_vc(vc); 165387a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman 165487a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman /* 165587a6aca504d65f242589583e04df5e74b5eae1feGreg Kroah-Hartman * Fall through to normal (VT_AUTO) handling of the switch... 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ignore all switches in KD_GRAPHICS+VT_AUTO mode 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vc->vc_mode == KD_GRAPHICS) 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds complete_change_console(new_vc); 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16678d233558cd99a888571bb5a88a74970879e0aba4Alan Cox 16688d233558cd99a888571bb5a88a74970879e0aba4Alan Cox/* Perform a kernel triggered VT switch for suspend/resume */ 16698d233558cd99a888571bb5a88a74970879e0aba4Alan Cox 16708d233558cd99a888571bb5a88a74970879e0aba4Alan Coxstatic int disable_vt_switch; 16718d233558cd99a888571bb5a88a74970879e0aba4Alan Cox 16728d233558cd99a888571bb5a88a74970879e0aba4Alan Coxint vt_move_to_console(unsigned int vt, int alloc) 16738d233558cd99a888571bb5a88a74970879e0aba4Alan Cox{ 16748d233558cd99a888571bb5a88a74970879e0aba4Alan Cox int prev; 16758d233558cd99a888571bb5a88a74970879e0aba4Alan Cox 1676ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 16778d233558cd99a888571bb5a88a74970879e0aba4Alan Cox /* Graphics mode - up to X */ 16788d233558cd99a888571bb5a88a74970879e0aba4Alan Cox if (disable_vt_switch) { 1679ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 16808d233558cd99a888571bb5a88a74970879e0aba4Alan Cox return 0; 16818d233558cd99a888571bb5a88a74970879e0aba4Alan Cox } 16828d233558cd99a888571bb5a88a74970879e0aba4Alan Cox prev = fg_console; 16838d233558cd99a888571bb5a88a74970879e0aba4Alan Cox 16848d233558cd99a888571bb5a88a74970879e0aba4Alan Cox if (alloc && vc_allocate(vt)) { 16858d233558cd99a888571bb5a88a74970879e0aba4Alan Cox /* we can't have a free VC for now. Too bad, 16868d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * we don't want to mess the screen for now. */ 1687ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 16888d233558cd99a888571bb5a88a74970879e0aba4Alan Cox return -ENOSPC; 16898d233558cd99a888571bb5a88a74970879e0aba4Alan Cox } 16908d233558cd99a888571bb5a88a74970879e0aba4Alan Cox 16918d233558cd99a888571bb5a88a74970879e0aba4Alan Cox if (set_console(vt)) { 16928d233558cd99a888571bb5a88a74970879e0aba4Alan Cox /* 16938d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * We're unable to switch to the SUSPEND_CONSOLE. 16948d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * Let the calling function know so it can decide 16958d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * what to do. 16968d233558cd99a888571bb5a88a74970879e0aba4Alan Cox */ 1697ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 16988d233558cd99a888571bb5a88a74970879e0aba4Alan Cox return -EIO; 16998d233558cd99a888571bb5a88a74970879e0aba4Alan Cox } 1700ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 1701be1bc2889a4db4961ef69f47fb471ecae9f23adeArnd Bergmann tty_lock(); 1702797938b5e33991dadf4dd9228b932cc69c3e905aJiri Slaby if (vt_waitactive(vt + 1)) { 17038d233558cd99a888571bb5a88a74970879e0aba4Alan Cox pr_debug("Suspend: Can't switch VCs."); 1704be1bc2889a4db4961ef69f47fb471ecae9f23adeArnd Bergmann tty_unlock(); 17058d233558cd99a888571bb5a88a74970879e0aba4Alan Cox return -EINTR; 17068d233558cd99a888571bb5a88a74970879e0aba4Alan Cox } 1707be1bc2889a4db4961ef69f47fb471ecae9f23adeArnd Bergmann tty_unlock(); 17088d233558cd99a888571bb5a88a74970879e0aba4Alan Cox return prev; 17098d233558cd99a888571bb5a88a74970879e0aba4Alan Cox} 17108d233558cd99a888571bb5a88a74970879e0aba4Alan Cox 17118d233558cd99a888571bb5a88a74970879e0aba4Alan Cox/* 17128d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * Normally during a suspend, we allocate a new console and switch to it. 17138d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * When we resume, we switch back to the original console. This switch 17148d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * can be slow, so on systems where the framebuffer can handle restoration 17158d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * of video registers anyways, there's little point in doing the console 17168d233558cd99a888571bb5a88a74970879e0aba4Alan Cox * switch. This function allows you to disable it by passing it '0'. 17178d233558cd99a888571bb5a88a74970879e0aba4Alan Cox */ 17188d233558cd99a888571bb5a88a74970879e0aba4Alan Coxvoid pm_set_vt_switch(int do_switch) 17198d233558cd99a888571bb5a88a74970879e0aba4Alan Cox{ 1720ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 17218d233558cd99a888571bb5a88a74970879e0aba4Alan Cox disable_vt_switch = !do_switch; 1722ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 17238d233558cd99a888571bb5a88a74970879e0aba4Alan Cox} 17248d233558cd99a888571bb5a88a74970879e0aba4Alan CoxEXPORT_SYMBOL(pm_set_vt_switch); 1725