1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 1992 obz under the linux copyright
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
6*4882a593Smuzhiyun * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
7*4882a593Smuzhiyun * Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
8*4882a593Smuzhiyun * Some code moved for less code duplication - Andi Kleen - Mar 1997
9*4882a593Smuzhiyun * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/types.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/sched/signal.h>
15*4882a593Smuzhiyun #include <linux/tty.h>
16*4882a593Smuzhiyun #include <linux/timer.h>
17*4882a593Smuzhiyun #include <linux/kernel.h>
18*4882a593Smuzhiyun #include <linux/compat.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/kd.h>
21*4882a593Smuzhiyun #include <linux/vt.h>
22*4882a593Smuzhiyun #include <linux/string.h>
23*4882a593Smuzhiyun #include <linux/slab.h>
24*4882a593Smuzhiyun #include <linux/major.h>
25*4882a593Smuzhiyun #include <linux/fs.h>
26*4882a593Smuzhiyun #include <linux/console.h>
27*4882a593Smuzhiyun #include <linux/consolemap.h>
28*4882a593Smuzhiyun #include <linux/signal.h>
29*4882a593Smuzhiyun #include <linux/suspend.h>
30*4882a593Smuzhiyun #include <linux/timex.h>
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #include <asm/io.h>
33*4882a593Smuzhiyun #include <linux/uaccess.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include <linux/nospec.h>
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #include <linux/kbd_kern.h>
38*4882a593Smuzhiyun #include <linux/vt_kern.h>
39*4882a593Smuzhiyun #include <linux/kbd_diacr.h>
40*4882a593Smuzhiyun #include <linux/selection.h>
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun bool vt_dont_switch;
43*4882a593Smuzhiyun
vt_in_use(unsigned int i)44*4882a593Smuzhiyun static inline bool vt_in_use(unsigned int i)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun const struct vc_data *vc = vc_cons[i].d;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun /*
49*4882a593Smuzhiyun * console_lock must be held to prevent the vc from being deallocated
50*4882a593Smuzhiyun * while we're checking whether it's in-use.
51*4882a593Smuzhiyun */
52*4882a593Smuzhiyun WARN_CONSOLE_UNLOCKED();
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun return vc && kref_read(&vc->port.kref) > 1;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
vt_busy(int i)57*4882a593Smuzhiyun static inline bool vt_busy(int i)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun if (vt_in_use(i))
60*4882a593Smuzhiyun return true;
61*4882a593Smuzhiyun if (i == fg_console)
62*4882a593Smuzhiyun return true;
63*4882a593Smuzhiyun if (vc_is_sel(vc_cons[i].d))
64*4882a593Smuzhiyun return true;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun return false;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /*
70*4882a593Smuzhiyun * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
71*4882a593Smuzhiyun * experimentation and study of X386 SYSV handling.
72*4882a593Smuzhiyun *
73*4882a593Smuzhiyun * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
74*4882a593Smuzhiyun * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
75*4882a593Smuzhiyun * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
76*4882a593Smuzhiyun * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
77*4882a593Smuzhiyun * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
78*4882a593Smuzhiyun * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
79*4882a593Smuzhiyun * to the current console is done by the main ioctl code.
80*4882a593Smuzhiyun */
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun #ifdef CONFIG_X86
83*4882a593Smuzhiyun #include <asm/syscalls.h>
84*4882a593Smuzhiyun #endif
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun static void complete_change_console(struct vc_data *vc);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /*
89*4882a593Smuzhiyun * User space VT_EVENT handlers
90*4882a593Smuzhiyun */
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun struct vt_event_wait {
93*4882a593Smuzhiyun struct list_head list;
94*4882a593Smuzhiyun struct vt_event event;
95*4882a593Smuzhiyun int done;
96*4882a593Smuzhiyun };
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun static LIST_HEAD(vt_events);
99*4882a593Smuzhiyun static DEFINE_SPINLOCK(vt_event_lock);
100*4882a593Smuzhiyun static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /**
103*4882a593Smuzhiyun * vt_event_post
104*4882a593Smuzhiyun * @event: the event that occurred
105*4882a593Smuzhiyun * @old: old console
106*4882a593Smuzhiyun * @new: new console
107*4882a593Smuzhiyun *
108*4882a593Smuzhiyun * Post an VT event to interested VT handlers
109*4882a593Smuzhiyun */
110*4882a593Smuzhiyun
vt_event_post(unsigned int event,unsigned int old,unsigned int new)111*4882a593Smuzhiyun void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun struct list_head *pos, *head;
114*4882a593Smuzhiyun unsigned long flags;
115*4882a593Smuzhiyun int wake = 0;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun spin_lock_irqsave(&vt_event_lock, flags);
118*4882a593Smuzhiyun head = &vt_events;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun list_for_each(pos, head) {
121*4882a593Smuzhiyun struct vt_event_wait *ve = list_entry(pos,
122*4882a593Smuzhiyun struct vt_event_wait, list);
123*4882a593Smuzhiyun if (!(ve->event.event & event))
124*4882a593Smuzhiyun continue;
125*4882a593Smuzhiyun ve->event.event = event;
126*4882a593Smuzhiyun /* kernel view is consoles 0..n-1, user space view is
127*4882a593Smuzhiyun console 1..n with 0 meaning current, so we must bias */
128*4882a593Smuzhiyun ve->event.oldev = old + 1;
129*4882a593Smuzhiyun ve->event.newev = new + 1;
130*4882a593Smuzhiyun wake = 1;
131*4882a593Smuzhiyun ve->done = 1;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun spin_unlock_irqrestore(&vt_event_lock, flags);
134*4882a593Smuzhiyun if (wake)
135*4882a593Smuzhiyun wake_up_interruptible(&vt_event_waitqueue);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
__vt_event_queue(struct vt_event_wait * vw)138*4882a593Smuzhiyun static void __vt_event_queue(struct vt_event_wait *vw)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun unsigned long flags;
141*4882a593Smuzhiyun /* Prepare the event */
142*4882a593Smuzhiyun INIT_LIST_HEAD(&vw->list);
143*4882a593Smuzhiyun vw->done = 0;
144*4882a593Smuzhiyun /* Queue our event */
145*4882a593Smuzhiyun spin_lock_irqsave(&vt_event_lock, flags);
146*4882a593Smuzhiyun list_add(&vw->list, &vt_events);
147*4882a593Smuzhiyun spin_unlock_irqrestore(&vt_event_lock, flags);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
__vt_event_wait(struct vt_event_wait * vw)150*4882a593Smuzhiyun static void __vt_event_wait(struct vt_event_wait *vw)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun /* Wait for it to pass */
153*4882a593Smuzhiyun wait_event_interruptible(vt_event_waitqueue, vw->done);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
__vt_event_dequeue(struct vt_event_wait * vw)156*4882a593Smuzhiyun static void __vt_event_dequeue(struct vt_event_wait *vw)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun unsigned long flags;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* Dequeue it */
161*4882a593Smuzhiyun spin_lock_irqsave(&vt_event_lock, flags);
162*4882a593Smuzhiyun list_del(&vw->list);
163*4882a593Smuzhiyun spin_unlock_irqrestore(&vt_event_lock, flags);
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /**
167*4882a593Smuzhiyun * vt_event_wait - wait for an event
168*4882a593Smuzhiyun * @vw: our event
169*4882a593Smuzhiyun *
170*4882a593Smuzhiyun * Waits for an event to occur which completes our vt_event_wait
171*4882a593Smuzhiyun * structure. On return the structure has wv->done set to 1 for success
172*4882a593Smuzhiyun * or 0 if some event such as a signal ended the wait.
173*4882a593Smuzhiyun */
174*4882a593Smuzhiyun
vt_event_wait(struct vt_event_wait * vw)175*4882a593Smuzhiyun static void vt_event_wait(struct vt_event_wait *vw)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun __vt_event_queue(vw);
178*4882a593Smuzhiyun __vt_event_wait(vw);
179*4882a593Smuzhiyun __vt_event_dequeue(vw);
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /**
183*4882a593Smuzhiyun * vt_event_wait_ioctl - event ioctl handler
184*4882a593Smuzhiyun * @event: argument to ioctl (the event)
185*4882a593Smuzhiyun *
186*4882a593Smuzhiyun * Implement the VT_WAITEVENT ioctl using the VT event interface
187*4882a593Smuzhiyun */
188*4882a593Smuzhiyun
vt_event_wait_ioctl(struct vt_event __user * event)189*4882a593Smuzhiyun static int vt_event_wait_ioctl(struct vt_event __user *event)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun struct vt_event_wait vw;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun if (copy_from_user(&vw.event, event, sizeof(struct vt_event)))
194*4882a593Smuzhiyun return -EFAULT;
195*4882a593Smuzhiyun /* Highest supported event for now */
196*4882a593Smuzhiyun if (vw.event.event & ~VT_MAX_EVENT)
197*4882a593Smuzhiyun return -EINVAL;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun vt_event_wait(&vw);
200*4882a593Smuzhiyun /* If it occurred report it */
201*4882a593Smuzhiyun if (vw.done) {
202*4882a593Smuzhiyun if (copy_to_user(event, &vw.event, sizeof(struct vt_event)))
203*4882a593Smuzhiyun return -EFAULT;
204*4882a593Smuzhiyun return 0;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun return -EINTR;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun /**
210*4882a593Smuzhiyun * vt_waitactive - active console wait
211*4882a593Smuzhiyun * @n: new console
212*4882a593Smuzhiyun *
213*4882a593Smuzhiyun * Helper for event waits. Used to implement the legacy
214*4882a593Smuzhiyun * event waiting ioctls in terms of events
215*4882a593Smuzhiyun */
216*4882a593Smuzhiyun
vt_waitactive(int n)217*4882a593Smuzhiyun int vt_waitactive(int n)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun struct vt_event_wait vw;
220*4882a593Smuzhiyun do {
221*4882a593Smuzhiyun vw.event.event = VT_EVENT_SWITCH;
222*4882a593Smuzhiyun __vt_event_queue(&vw);
223*4882a593Smuzhiyun if (n == fg_console + 1) {
224*4882a593Smuzhiyun __vt_event_dequeue(&vw);
225*4882a593Smuzhiyun break;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun __vt_event_wait(&vw);
228*4882a593Smuzhiyun __vt_event_dequeue(&vw);
229*4882a593Smuzhiyun if (vw.done == 0)
230*4882a593Smuzhiyun return -EINTR;
231*4882a593Smuzhiyun } while (vw.event.newev != n);
232*4882a593Smuzhiyun return 0;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun /*
236*4882a593Smuzhiyun * these are the valid i/o ports we're allowed to change. they map all the
237*4882a593Smuzhiyun * video ports
238*4882a593Smuzhiyun */
239*4882a593Smuzhiyun #define GPFIRST 0x3b4
240*4882a593Smuzhiyun #define GPLAST 0x3df
241*4882a593Smuzhiyun #define GPNUM (GPLAST - GPFIRST + 1)
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /*
244*4882a593Smuzhiyun * currently, setting the mode from KD_TEXT to KD_GRAPHICS doesn't do a whole
245*4882a593Smuzhiyun * lot. i'm not sure if it should do any restoration of modes or what...
246*4882a593Smuzhiyun *
247*4882a593Smuzhiyun * XXX It should at least call into the driver, fbdev's definitely need to
248*4882a593Smuzhiyun * restore their engine state. --BenH
249*4882a593Smuzhiyun *
250*4882a593Smuzhiyun * Called with the console lock held.
251*4882a593Smuzhiyun */
vt_kdsetmode(struct vc_data * vc,unsigned long mode)252*4882a593Smuzhiyun static int vt_kdsetmode(struct vc_data *vc, unsigned long mode)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun switch (mode) {
255*4882a593Smuzhiyun case KD_GRAPHICS:
256*4882a593Smuzhiyun break;
257*4882a593Smuzhiyun case KD_TEXT0:
258*4882a593Smuzhiyun case KD_TEXT1:
259*4882a593Smuzhiyun mode = KD_TEXT;
260*4882a593Smuzhiyun fallthrough;
261*4882a593Smuzhiyun case KD_TEXT:
262*4882a593Smuzhiyun break;
263*4882a593Smuzhiyun default:
264*4882a593Smuzhiyun return -EINVAL;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun if (vc->vc_mode == mode)
268*4882a593Smuzhiyun return 0;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun vc->vc_mode = mode;
271*4882a593Smuzhiyun if (vc->vc_num != fg_console)
272*4882a593Smuzhiyun return 0;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /* explicitly blank/unblank the screen if switching modes */
275*4882a593Smuzhiyun if (mode == KD_TEXT)
276*4882a593Smuzhiyun do_unblank_screen(1);
277*4882a593Smuzhiyun else
278*4882a593Smuzhiyun do_blank_screen(1);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun return 0;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
vt_k_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg,bool perm)283*4882a593Smuzhiyun static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd,
284*4882a593Smuzhiyun unsigned long arg, bool perm)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun struct vc_data *vc = tty->driver_data;
287*4882a593Smuzhiyun void __user *up = (void __user *)arg;
288*4882a593Smuzhiyun unsigned int console = vc->vc_num;
289*4882a593Smuzhiyun int ret;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun switch (cmd) {
292*4882a593Smuzhiyun case KIOCSOUND:
293*4882a593Smuzhiyun if (!perm)
294*4882a593Smuzhiyun return -EPERM;
295*4882a593Smuzhiyun /*
296*4882a593Smuzhiyun * The use of PIT_TICK_RATE is historic, it used to be
297*4882a593Smuzhiyun * the platform-dependent CLOCK_TICK_RATE between 2.6.12
298*4882a593Smuzhiyun * and 2.6.36, which was a minor but unfortunate ABI
299*4882a593Smuzhiyun * change. kd_mksound is locked by the input layer.
300*4882a593Smuzhiyun */
301*4882a593Smuzhiyun if (arg)
302*4882a593Smuzhiyun arg = PIT_TICK_RATE / arg;
303*4882a593Smuzhiyun kd_mksound(arg, 0);
304*4882a593Smuzhiyun break;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun case KDMKTONE:
307*4882a593Smuzhiyun if (!perm)
308*4882a593Smuzhiyun return -EPERM;
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun unsigned int ticks, count;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun /*
313*4882a593Smuzhiyun * Generate the tone for the appropriate number of ticks.
314*4882a593Smuzhiyun * If the time is zero, turn off sound ourselves.
315*4882a593Smuzhiyun */
316*4882a593Smuzhiyun ticks = msecs_to_jiffies((arg >> 16) & 0xffff);
317*4882a593Smuzhiyun count = ticks ? (arg & 0xffff) : 0;
318*4882a593Smuzhiyun if (count)
319*4882a593Smuzhiyun count = PIT_TICK_RATE / count;
320*4882a593Smuzhiyun kd_mksound(count, ticks);
321*4882a593Smuzhiyun break;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun case KDGKBTYPE:
325*4882a593Smuzhiyun /*
326*4882a593Smuzhiyun * this is naïve.
327*4882a593Smuzhiyun */
328*4882a593Smuzhiyun return put_user(KB_101, (char __user *)arg);
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun /*
331*4882a593Smuzhiyun * These cannot be implemented on any machine that implements
332*4882a593Smuzhiyun * ioperm() in user level (such as Alpha PCs) or not at all.
333*4882a593Smuzhiyun *
334*4882a593Smuzhiyun * XXX: you should never use these, just call ioperm directly..
335*4882a593Smuzhiyun */
336*4882a593Smuzhiyun #ifdef CONFIG_X86
337*4882a593Smuzhiyun case KDADDIO:
338*4882a593Smuzhiyun case KDDELIO:
339*4882a593Smuzhiyun /*
340*4882a593Smuzhiyun * KDADDIO and KDDELIO may be able to add ports beyond what
341*4882a593Smuzhiyun * we reject here, but to be safe...
342*4882a593Smuzhiyun *
343*4882a593Smuzhiyun * These are locked internally via sys_ioperm
344*4882a593Smuzhiyun */
345*4882a593Smuzhiyun if (arg < GPFIRST || arg > GPLAST)
346*4882a593Smuzhiyun return -EINVAL;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun return ksys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun case KDENABIO:
351*4882a593Smuzhiyun case KDDISABIO:
352*4882a593Smuzhiyun return ksys_ioperm(GPFIRST, GPNUM,
353*4882a593Smuzhiyun (cmd == KDENABIO)) ? -ENXIO : 0;
354*4882a593Smuzhiyun #endif
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun case KDKBDREP:
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun struct kbd_repeat kbrep;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun if (!capable(CAP_SYS_TTY_CONFIG))
363*4882a593Smuzhiyun return -EPERM;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat)))
366*4882a593Smuzhiyun return -EFAULT;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun ret = kbd_rate(&kbrep);
369*4882a593Smuzhiyun if (ret)
370*4882a593Smuzhiyun return ret;
371*4882a593Smuzhiyun if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
372*4882a593Smuzhiyun return -EFAULT;
373*4882a593Smuzhiyun break;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun case KDSETMODE:
377*4882a593Smuzhiyun if (!perm)
378*4882a593Smuzhiyun return -EPERM;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun console_lock();
381*4882a593Smuzhiyun ret = vt_kdsetmode(vc, arg);
382*4882a593Smuzhiyun console_unlock();
383*4882a593Smuzhiyun return ret;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun case KDGETMODE:
386*4882a593Smuzhiyun return put_user(vc->vc_mode, (int __user *)arg);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun case KDMAPDISP:
389*4882a593Smuzhiyun case KDUNMAPDISP:
390*4882a593Smuzhiyun /*
391*4882a593Smuzhiyun * these work like a combination of mmap and KDENABIO.
392*4882a593Smuzhiyun * this could be easily finished.
393*4882a593Smuzhiyun */
394*4882a593Smuzhiyun return -EINVAL;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun case KDSKBMODE:
397*4882a593Smuzhiyun if (!perm)
398*4882a593Smuzhiyun return -EPERM;
399*4882a593Smuzhiyun ret = vt_do_kdskbmode(console, arg);
400*4882a593Smuzhiyun if (ret)
401*4882a593Smuzhiyun return ret;
402*4882a593Smuzhiyun tty_ldisc_flush(tty);
403*4882a593Smuzhiyun break;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun case KDGKBMODE:
406*4882a593Smuzhiyun return put_user(vt_do_kdgkbmode(console), (int __user *)arg);
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun /* this could be folded into KDSKBMODE, but for compatibility
409*4882a593Smuzhiyun reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
410*4882a593Smuzhiyun case KDSKBMETA:
411*4882a593Smuzhiyun return vt_do_kdskbmeta(console, arg);
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun case KDGKBMETA:
414*4882a593Smuzhiyun /* FIXME: should review whether this is worth locking */
415*4882a593Smuzhiyun return put_user(vt_do_kdgkbmeta(console), (int __user *)arg);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun case KDGETKEYCODE:
418*4882a593Smuzhiyun case KDSETKEYCODE:
419*4882a593Smuzhiyun if(!capable(CAP_SYS_TTY_CONFIG))
420*4882a593Smuzhiyun perm = 0;
421*4882a593Smuzhiyun return vt_do_kbkeycode_ioctl(cmd, up, perm);
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun case KDGKBENT:
424*4882a593Smuzhiyun case KDSKBENT:
425*4882a593Smuzhiyun return vt_do_kdsk_ioctl(cmd, up, perm, console);
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun case KDGKBSENT:
428*4882a593Smuzhiyun case KDSKBSENT:
429*4882a593Smuzhiyun return vt_do_kdgkb_ioctl(cmd, up, perm);
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun /* Diacritical processing. Handled in keyboard.c as it has
432*4882a593Smuzhiyun to operate on the keyboard locks and structures */
433*4882a593Smuzhiyun case KDGKBDIACR:
434*4882a593Smuzhiyun case KDGKBDIACRUC:
435*4882a593Smuzhiyun case KDSKBDIACR:
436*4882a593Smuzhiyun case KDSKBDIACRUC:
437*4882a593Smuzhiyun return vt_do_diacrit(cmd, up, perm);
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun /* the ioctls below read/set the flags usually shown in the leds */
440*4882a593Smuzhiyun /* don't use them - they will go away without warning */
441*4882a593Smuzhiyun case KDGKBLED:
442*4882a593Smuzhiyun case KDSKBLED:
443*4882a593Smuzhiyun case KDGETLED:
444*4882a593Smuzhiyun case KDSETLED:
445*4882a593Smuzhiyun return vt_do_kdskled(console, cmd, arg, perm);
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun /*
448*4882a593Smuzhiyun * A process can indicate its willingness to accept signals
449*4882a593Smuzhiyun * generated by pressing an appropriate key combination.
450*4882a593Smuzhiyun * Thus, one can have a daemon that e.g. spawns a new console
451*4882a593Smuzhiyun * upon a keypress and then changes to it.
452*4882a593Smuzhiyun * See also the kbrequest field of inittab(5).
453*4882a593Smuzhiyun */
454*4882a593Smuzhiyun case KDSIGACCEPT:
455*4882a593Smuzhiyun if (!perm || !capable(CAP_KILL))
456*4882a593Smuzhiyun return -EPERM;
457*4882a593Smuzhiyun if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
458*4882a593Smuzhiyun return -EINVAL;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun spin_lock_irq(&vt_spawn_con.lock);
461*4882a593Smuzhiyun put_pid(vt_spawn_con.pid);
462*4882a593Smuzhiyun vt_spawn_con.pid = get_pid(task_pid(current));
463*4882a593Smuzhiyun vt_spawn_con.sig = arg;
464*4882a593Smuzhiyun spin_unlock_irq(&vt_spawn_con.lock);
465*4882a593Smuzhiyun break;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun case KDFONTOP: {
468*4882a593Smuzhiyun struct console_font_op op;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (copy_from_user(&op, up, sizeof(op)))
471*4882a593Smuzhiyun return -EFAULT;
472*4882a593Smuzhiyun if (!perm && op.op != KD_FONT_OP_GET)
473*4882a593Smuzhiyun return -EPERM;
474*4882a593Smuzhiyun ret = con_font_op(vc, &op);
475*4882a593Smuzhiyun if (ret)
476*4882a593Smuzhiyun return ret;
477*4882a593Smuzhiyun if (copy_to_user(up, &op, sizeof(op)))
478*4882a593Smuzhiyun return -EFAULT;
479*4882a593Smuzhiyun break;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun default:
483*4882a593Smuzhiyun return -ENOIOCTLCMD;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun return 0;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
do_unimap_ioctl(int cmd,struct unimapdesc __user * user_ud,bool perm,struct vc_data * vc)489*4882a593Smuzhiyun static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud,
490*4882a593Smuzhiyun bool perm, struct vc_data *vc)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun struct unimapdesc tmp;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun if (copy_from_user(&tmp, user_ud, sizeof tmp))
495*4882a593Smuzhiyun return -EFAULT;
496*4882a593Smuzhiyun switch (cmd) {
497*4882a593Smuzhiyun case PIO_UNIMAP:
498*4882a593Smuzhiyun if (!perm)
499*4882a593Smuzhiyun return -EPERM;
500*4882a593Smuzhiyun return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
501*4882a593Smuzhiyun case GIO_UNIMAP:
502*4882a593Smuzhiyun if (!perm && fg_console != vc->vc_num)
503*4882a593Smuzhiyun return -EPERM;
504*4882a593Smuzhiyun return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct),
505*4882a593Smuzhiyun tmp.entries);
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun return 0;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
vt_io_ioctl(struct vc_data * vc,unsigned int cmd,void __user * up,bool perm)510*4882a593Smuzhiyun static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up,
511*4882a593Smuzhiyun bool perm)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun switch (cmd) {
514*4882a593Smuzhiyun case PIO_CMAP:
515*4882a593Smuzhiyun if (!perm)
516*4882a593Smuzhiyun return -EPERM;
517*4882a593Smuzhiyun return con_set_cmap(up);
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun case GIO_CMAP:
520*4882a593Smuzhiyun return con_get_cmap(up);
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun case PIO_SCRNMAP:
523*4882a593Smuzhiyun if (!perm)
524*4882a593Smuzhiyun return -EPERM;
525*4882a593Smuzhiyun return con_set_trans_old(up);
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun case GIO_SCRNMAP:
528*4882a593Smuzhiyun return con_get_trans_old(up);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun case PIO_UNISCRNMAP:
531*4882a593Smuzhiyun if (!perm)
532*4882a593Smuzhiyun return -EPERM;
533*4882a593Smuzhiyun return con_set_trans_new(up);
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun case GIO_UNISCRNMAP:
536*4882a593Smuzhiyun return con_get_trans_new(up);
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun case PIO_UNIMAPCLR:
539*4882a593Smuzhiyun if (!perm)
540*4882a593Smuzhiyun return -EPERM;
541*4882a593Smuzhiyun con_clear_unimap(vc);
542*4882a593Smuzhiyun break;
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun case PIO_UNIMAP:
545*4882a593Smuzhiyun case GIO_UNIMAP:
546*4882a593Smuzhiyun return do_unimap_ioctl(cmd, up, perm, vc);
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun default:
549*4882a593Smuzhiyun return -ENOIOCTLCMD;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun return 0;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
vt_reldisp(struct vc_data * vc,unsigned int swtch)555*4882a593Smuzhiyun static int vt_reldisp(struct vc_data *vc, unsigned int swtch)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun int newvt, ret;
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun if (vc->vt_mode.mode != VT_PROCESS)
560*4882a593Smuzhiyun return -EINVAL;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun /* Switched-to response */
563*4882a593Smuzhiyun if (vc->vt_newvt < 0) {
564*4882a593Smuzhiyun /* If it's just an ACK, ignore it */
565*4882a593Smuzhiyun return swtch == VT_ACKACQ ? 0 : -EINVAL;
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun /* Switching-from response */
569*4882a593Smuzhiyun if (swtch == 0) {
570*4882a593Smuzhiyun /* Switch disallowed, so forget we were trying to do it. */
571*4882a593Smuzhiyun vc->vt_newvt = -1;
572*4882a593Smuzhiyun return 0;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /* The current vt has been released, so complete the switch. */
576*4882a593Smuzhiyun newvt = vc->vt_newvt;
577*4882a593Smuzhiyun vc->vt_newvt = -1;
578*4882a593Smuzhiyun ret = vc_allocate(newvt);
579*4882a593Smuzhiyun if (ret)
580*4882a593Smuzhiyun return ret;
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /*
583*4882a593Smuzhiyun * When we actually do the console switch, make sure we are atomic with
584*4882a593Smuzhiyun * respect to other console switches..
585*4882a593Smuzhiyun */
586*4882a593Smuzhiyun complete_change_console(vc_cons[newvt].d);
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun return 0;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun
vt_setactivate(struct vt_setactivate __user * sa)591*4882a593Smuzhiyun static int vt_setactivate(struct vt_setactivate __user *sa)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun struct vt_setactivate vsa;
594*4882a593Smuzhiyun struct vc_data *nvc;
595*4882a593Smuzhiyun int ret;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun if (copy_from_user(&vsa, sa, sizeof(vsa)))
598*4882a593Smuzhiyun return -EFAULT;
599*4882a593Smuzhiyun if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
600*4882a593Smuzhiyun return -ENXIO;
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun vsa.console--;
603*4882a593Smuzhiyun vsa.console = array_index_nospec(vsa.console, MAX_NR_CONSOLES);
604*4882a593Smuzhiyun console_lock();
605*4882a593Smuzhiyun ret = vc_allocate(vsa.console);
606*4882a593Smuzhiyun if (ret) {
607*4882a593Smuzhiyun console_unlock();
608*4882a593Smuzhiyun return ret;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun /*
612*4882a593Smuzhiyun * This is safe providing we don't drop the console sem between
613*4882a593Smuzhiyun * vc_allocate and finishing referencing nvc.
614*4882a593Smuzhiyun */
615*4882a593Smuzhiyun nvc = vc_cons[vsa.console].d;
616*4882a593Smuzhiyun nvc->vt_mode = vsa.mode;
617*4882a593Smuzhiyun nvc->vt_mode.frsig = 0;
618*4882a593Smuzhiyun put_pid(nvc->vt_pid);
619*4882a593Smuzhiyun nvc->vt_pid = get_pid(task_pid(current));
620*4882a593Smuzhiyun console_unlock();
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun /* Commence switch and lock */
623*4882a593Smuzhiyun /* Review set_console locks */
624*4882a593Smuzhiyun set_console(vsa.console);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun return 0;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun /* deallocate a single console, if possible (leave 0) */
vt_disallocate(unsigned int vc_num)630*4882a593Smuzhiyun static int vt_disallocate(unsigned int vc_num)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun struct vc_data *vc = NULL;
633*4882a593Smuzhiyun int ret = 0;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun console_lock();
636*4882a593Smuzhiyun if (vt_busy(vc_num))
637*4882a593Smuzhiyun ret = -EBUSY;
638*4882a593Smuzhiyun else if (vc_num)
639*4882a593Smuzhiyun vc = vc_deallocate(vc_num);
640*4882a593Smuzhiyun console_unlock();
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun if (vc && vc_num >= MIN_NR_CONSOLES)
643*4882a593Smuzhiyun tty_port_put(&vc->port);
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun return ret;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun /* deallocate all unused consoles, but leave 0 */
vt_disallocate_all(void)649*4882a593Smuzhiyun static void vt_disallocate_all(void)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun struct vc_data *vc[MAX_NR_CONSOLES];
652*4882a593Smuzhiyun int i;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun console_lock();
655*4882a593Smuzhiyun for (i = 1; i < MAX_NR_CONSOLES; i++)
656*4882a593Smuzhiyun if (!vt_busy(i))
657*4882a593Smuzhiyun vc[i] = vc_deallocate(i);
658*4882a593Smuzhiyun else
659*4882a593Smuzhiyun vc[i] = NULL;
660*4882a593Smuzhiyun console_unlock();
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun for (i = 1; i < MAX_NR_CONSOLES; i++) {
663*4882a593Smuzhiyun if (vc[i] && i >= MIN_NR_CONSOLES)
664*4882a593Smuzhiyun tty_port_put(&vc[i]->port);
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
vt_resizex(struct vc_data * vc,struct vt_consize __user * cs)668*4882a593Smuzhiyun static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun struct vt_consize v;
671*4882a593Smuzhiyun int i;
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun if (copy_from_user(&v, cs, sizeof(struct vt_consize)))
674*4882a593Smuzhiyun return -EFAULT;
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun /* FIXME: Should check the copies properly */
677*4882a593Smuzhiyun if (!v.v_vlin)
678*4882a593Smuzhiyun v.v_vlin = vc->vc_scan_lines;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun if (v.v_clin) {
681*4882a593Smuzhiyun int rows = v.v_vlin / v.v_clin;
682*4882a593Smuzhiyun if (v.v_rows != rows) {
683*4882a593Smuzhiyun if (v.v_rows) /* Parameters don't add up */
684*4882a593Smuzhiyun return -EINVAL;
685*4882a593Smuzhiyun v.v_rows = rows;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun if (v.v_vcol && v.v_ccol) {
690*4882a593Smuzhiyun int cols = v.v_vcol / v.v_ccol;
691*4882a593Smuzhiyun if (v.v_cols != cols) {
692*4882a593Smuzhiyun if (v.v_cols)
693*4882a593Smuzhiyun return -EINVAL;
694*4882a593Smuzhiyun v.v_cols = cols;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun if (v.v_clin > 32)
699*4882a593Smuzhiyun return -EINVAL;
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun for (i = 0; i < MAX_NR_CONSOLES; i++) {
702*4882a593Smuzhiyun struct vc_data *vcp;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun if (!vc_cons[i].d)
705*4882a593Smuzhiyun continue;
706*4882a593Smuzhiyun console_lock();
707*4882a593Smuzhiyun vcp = vc_cons[i].d;
708*4882a593Smuzhiyun if (vcp) {
709*4882a593Smuzhiyun int ret;
710*4882a593Smuzhiyun int save_scan_lines = vcp->vc_scan_lines;
711*4882a593Smuzhiyun int save_cell_height = vcp->vc_cell_height;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun if (v.v_vlin)
714*4882a593Smuzhiyun vcp->vc_scan_lines = v.v_vlin;
715*4882a593Smuzhiyun if (v.v_clin)
716*4882a593Smuzhiyun vcp->vc_cell_height = v.v_clin;
717*4882a593Smuzhiyun vcp->vc_resize_user = 1;
718*4882a593Smuzhiyun ret = vc_resize(vcp, v.v_cols, v.v_rows);
719*4882a593Smuzhiyun if (ret) {
720*4882a593Smuzhiyun vcp->vc_scan_lines = save_scan_lines;
721*4882a593Smuzhiyun vcp->vc_cell_height = save_cell_height;
722*4882a593Smuzhiyun console_unlock();
723*4882a593Smuzhiyun return ret;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun }
726*4882a593Smuzhiyun console_unlock();
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun return 0;
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun /*
733*4882a593Smuzhiyun * We handle the console-specific ioctl's here. We allow the
734*4882a593Smuzhiyun * capability to modify any console, not just the fg_console.
735*4882a593Smuzhiyun */
vt_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg)736*4882a593Smuzhiyun int vt_ioctl(struct tty_struct *tty,
737*4882a593Smuzhiyun unsigned int cmd, unsigned long arg)
738*4882a593Smuzhiyun {
739*4882a593Smuzhiyun struct vc_data *vc = tty->driver_data;
740*4882a593Smuzhiyun void __user *up = (void __user *)arg;
741*4882a593Smuzhiyun int i, perm;
742*4882a593Smuzhiyun int ret;
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun /*
745*4882a593Smuzhiyun * To have permissions to do most of the vt ioctls, we either have
746*4882a593Smuzhiyun * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
747*4882a593Smuzhiyun */
748*4882a593Smuzhiyun perm = 0;
749*4882a593Smuzhiyun if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
750*4882a593Smuzhiyun perm = 1;
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun ret = vt_k_ioctl(tty, cmd, arg, perm);
753*4882a593Smuzhiyun if (ret != -ENOIOCTLCMD)
754*4882a593Smuzhiyun return ret;
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun ret = vt_io_ioctl(vc, cmd, up, perm);
757*4882a593Smuzhiyun if (ret != -ENOIOCTLCMD)
758*4882a593Smuzhiyun return ret;
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun switch (cmd) {
761*4882a593Smuzhiyun case TIOCLINUX:
762*4882a593Smuzhiyun return tioclinux(tty, arg);
763*4882a593Smuzhiyun case VT_SETMODE:
764*4882a593Smuzhiyun {
765*4882a593Smuzhiyun struct vt_mode tmp;
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun if (!perm)
768*4882a593Smuzhiyun return -EPERM;
769*4882a593Smuzhiyun if (copy_from_user(&tmp, up, sizeof(struct vt_mode)))
770*4882a593Smuzhiyun return -EFAULT;
771*4882a593Smuzhiyun if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS)
772*4882a593Smuzhiyun return -EINVAL;
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun console_lock();
775*4882a593Smuzhiyun vc->vt_mode = tmp;
776*4882a593Smuzhiyun /* the frsig is ignored, so we set it to 0 */
777*4882a593Smuzhiyun vc->vt_mode.frsig = 0;
778*4882a593Smuzhiyun put_pid(vc->vt_pid);
779*4882a593Smuzhiyun vc->vt_pid = get_pid(task_pid(current));
780*4882a593Smuzhiyun /* no switch is required -- saw@shade.msu.ru */
781*4882a593Smuzhiyun vc->vt_newvt = -1;
782*4882a593Smuzhiyun console_unlock();
783*4882a593Smuzhiyun break;
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun case VT_GETMODE:
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun struct vt_mode tmp;
789*4882a593Smuzhiyun int rc;
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun console_lock();
792*4882a593Smuzhiyun memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
793*4882a593Smuzhiyun console_unlock();
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
796*4882a593Smuzhiyun if (rc)
797*4882a593Smuzhiyun return -EFAULT;
798*4882a593Smuzhiyun break;
799*4882a593Smuzhiyun }
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun /*
802*4882a593Smuzhiyun * Returns global vt state. Note that VT 0 is always open, since
803*4882a593Smuzhiyun * it's an alias for the current VT, and people can't use it here.
804*4882a593Smuzhiyun * We cannot return state for more than 16 VTs, since v_state is short.
805*4882a593Smuzhiyun */
806*4882a593Smuzhiyun case VT_GETSTATE:
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun struct vt_stat __user *vtstat = up;
809*4882a593Smuzhiyun unsigned short state, mask;
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun if (put_user(fg_console + 1, &vtstat->v_active))
812*4882a593Smuzhiyun return -EFAULT;
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun state = 1; /* /dev/tty0 is always open */
815*4882a593Smuzhiyun console_lock(); /* required by vt_in_use() */
816*4882a593Smuzhiyun for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
817*4882a593Smuzhiyun ++i, mask <<= 1)
818*4882a593Smuzhiyun if (vt_in_use(i))
819*4882a593Smuzhiyun state |= mask;
820*4882a593Smuzhiyun console_unlock();
821*4882a593Smuzhiyun return put_user(state, &vtstat->v_state);
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun /*
825*4882a593Smuzhiyun * Returns the first available (non-opened) console.
826*4882a593Smuzhiyun */
827*4882a593Smuzhiyun case VT_OPENQRY:
828*4882a593Smuzhiyun console_lock(); /* required by vt_in_use() */
829*4882a593Smuzhiyun for (i = 0; i < MAX_NR_CONSOLES; ++i)
830*4882a593Smuzhiyun if (!vt_in_use(i))
831*4882a593Smuzhiyun break;
832*4882a593Smuzhiyun console_unlock();
833*4882a593Smuzhiyun i = i < MAX_NR_CONSOLES ? (i+1) : -1;
834*4882a593Smuzhiyun return put_user(i, (int __user *)arg);
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun /*
837*4882a593Smuzhiyun * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
838*4882a593Smuzhiyun * with num >= 1 (switches to vt 0, our console, are not allowed, just
839*4882a593Smuzhiyun * to preserve sanity).
840*4882a593Smuzhiyun */
841*4882a593Smuzhiyun case VT_ACTIVATE:
842*4882a593Smuzhiyun if (!perm)
843*4882a593Smuzhiyun return -EPERM;
844*4882a593Smuzhiyun if (arg == 0 || arg > MAX_NR_CONSOLES)
845*4882a593Smuzhiyun return -ENXIO;
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun arg--;
848*4882a593Smuzhiyun arg = array_index_nospec(arg, MAX_NR_CONSOLES);
849*4882a593Smuzhiyun console_lock();
850*4882a593Smuzhiyun ret = vc_allocate(arg);
851*4882a593Smuzhiyun console_unlock();
852*4882a593Smuzhiyun if (ret)
853*4882a593Smuzhiyun return ret;
854*4882a593Smuzhiyun set_console(arg);
855*4882a593Smuzhiyun break;
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun case VT_SETACTIVATE:
858*4882a593Smuzhiyun if (!perm)
859*4882a593Smuzhiyun return -EPERM;
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun return vt_setactivate(up);
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun /*
864*4882a593Smuzhiyun * wait until the specified VT has been activated
865*4882a593Smuzhiyun */
866*4882a593Smuzhiyun case VT_WAITACTIVE:
867*4882a593Smuzhiyun if (!perm)
868*4882a593Smuzhiyun return -EPERM;
869*4882a593Smuzhiyun if (arg == 0 || arg > MAX_NR_CONSOLES)
870*4882a593Smuzhiyun return -ENXIO;
871*4882a593Smuzhiyun return vt_waitactive(arg);
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun /*
874*4882a593Smuzhiyun * If a vt is under process control, the kernel will not switch to it
875*4882a593Smuzhiyun * immediately, but postpone the operation until the process calls this
876*4882a593Smuzhiyun * ioctl, allowing the switch to complete.
877*4882a593Smuzhiyun *
878*4882a593Smuzhiyun * According to the X sources this is the behavior:
879*4882a593Smuzhiyun * 0: pending switch-from not OK
880*4882a593Smuzhiyun * 1: pending switch-from OK
881*4882a593Smuzhiyun * 2: completed switch-to OK
882*4882a593Smuzhiyun */
883*4882a593Smuzhiyun case VT_RELDISP:
884*4882a593Smuzhiyun if (!perm)
885*4882a593Smuzhiyun return -EPERM;
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun console_lock();
888*4882a593Smuzhiyun ret = vt_reldisp(vc, arg);
889*4882a593Smuzhiyun console_unlock();
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun return ret;
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun /*
895*4882a593Smuzhiyun * Disallocate memory associated to VT (but leave VT1)
896*4882a593Smuzhiyun */
897*4882a593Smuzhiyun case VT_DISALLOCATE:
898*4882a593Smuzhiyun if (arg > MAX_NR_CONSOLES)
899*4882a593Smuzhiyun return -ENXIO;
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun if (arg == 0)
902*4882a593Smuzhiyun vt_disallocate_all();
903*4882a593Smuzhiyun else
904*4882a593Smuzhiyun return vt_disallocate(--arg);
905*4882a593Smuzhiyun break;
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun case VT_RESIZE:
908*4882a593Smuzhiyun {
909*4882a593Smuzhiyun struct vt_sizes __user *vtsizes = up;
910*4882a593Smuzhiyun struct vc_data *vc;
911*4882a593Smuzhiyun ushort ll,cc;
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun if (!perm)
914*4882a593Smuzhiyun return -EPERM;
915*4882a593Smuzhiyun if (get_user(ll, &vtsizes->v_rows) ||
916*4882a593Smuzhiyun get_user(cc, &vtsizes->v_cols))
917*4882a593Smuzhiyun return -EFAULT;
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun console_lock();
920*4882a593Smuzhiyun for (i = 0; i < MAX_NR_CONSOLES; i++) {
921*4882a593Smuzhiyun vc = vc_cons[i].d;
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun if (vc) {
924*4882a593Smuzhiyun vc->vc_resize_user = 1;
925*4882a593Smuzhiyun /* FIXME: review v tty lock */
926*4882a593Smuzhiyun vc_resize(vc_cons[i].d, cc, ll);
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun }
929*4882a593Smuzhiyun console_unlock();
930*4882a593Smuzhiyun break;
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun case VT_RESIZEX:
934*4882a593Smuzhiyun if (!perm)
935*4882a593Smuzhiyun return -EPERM;
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun return vt_resizex(vc, up);
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun case VT_LOCKSWITCH:
940*4882a593Smuzhiyun if (!capable(CAP_SYS_TTY_CONFIG))
941*4882a593Smuzhiyun return -EPERM;
942*4882a593Smuzhiyun vt_dont_switch = true;
943*4882a593Smuzhiyun break;
944*4882a593Smuzhiyun case VT_UNLOCKSWITCH:
945*4882a593Smuzhiyun if (!capable(CAP_SYS_TTY_CONFIG))
946*4882a593Smuzhiyun return -EPERM;
947*4882a593Smuzhiyun vt_dont_switch = false;
948*4882a593Smuzhiyun break;
949*4882a593Smuzhiyun case VT_GETHIFONTMASK:
950*4882a593Smuzhiyun return put_user(vc->vc_hi_font_mask,
951*4882a593Smuzhiyun (unsigned short __user *)arg);
952*4882a593Smuzhiyun case VT_WAITEVENT:
953*4882a593Smuzhiyun return vt_event_wait_ioctl((struct vt_event __user *)arg);
954*4882a593Smuzhiyun default:
955*4882a593Smuzhiyun return -ENOIOCTLCMD;
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun return 0;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun
reset_vc(struct vc_data * vc)961*4882a593Smuzhiyun void reset_vc(struct vc_data *vc)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun vc->vc_mode = KD_TEXT;
964*4882a593Smuzhiyun vt_reset_unicode(vc->vc_num);
965*4882a593Smuzhiyun vc->vt_mode.mode = VT_AUTO;
966*4882a593Smuzhiyun vc->vt_mode.waitv = 0;
967*4882a593Smuzhiyun vc->vt_mode.relsig = 0;
968*4882a593Smuzhiyun vc->vt_mode.acqsig = 0;
969*4882a593Smuzhiyun vc->vt_mode.frsig = 0;
970*4882a593Smuzhiyun put_pid(vc->vt_pid);
971*4882a593Smuzhiyun vc->vt_pid = NULL;
972*4882a593Smuzhiyun vc->vt_newvt = -1;
973*4882a593Smuzhiyun if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */
974*4882a593Smuzhiyun reset_palette(vc);
975*4882a593Smuzhiyun }
976*4882a593Smuzhiyun
vc_SAK(struct work_struct * work)977*4882a593Smuzhiyun void vc_SAK(struct work_struct *work)
978*4882a593Smuzhiyun {
979*4882a593Smuzhiyun struct vc *vc_con =
980*4882a593Smuzhiyun container_of(work, struct vc, SAK_work);
981*4882a593Smuzhiyun struct vc_data *vc;
982*4882a593Smuzhiyun struct tty_struct *tty;
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun console_lock();
985*4882a593Smuzhiyun vc = vc_con->d;
986*4882a593Smuzhiyun if (vc) {
987*4882a593Smuzhiyun /* FIXME: review tty ref counting */
988*4882a593Smuzhiyun tty = vc->port.tty;
989*4882a593Smuzhiyun /*
990*4882a593Smuzhiyun * SAK should also work in all raw modes and reset
991*4882a593Smuzhiyun * them properly.
992*4882a593Smuzhiyun */
993*4882a593Smuzhiyun if (tty)
994*4882a593Smuzhiyun __do_SAK(tty);
995*4882a593Smuzhiyun reset_vc(vc);
996*4882a593Smuzhiyun }
997*4882a593Smuzhiyun console_unlock();
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun struct compat_console_font_op {
1003*4882a593Smuzhiyun compat_uint_t op; /* operation code KD_FONT_OP_* */
1004*4882a593Smuzhiyun compat_uint_t flags; /* KD_FONT_FLAG_* */
1005*4882a593Smuzhiyun compat_uint_t width, height; /* font size */
1006*4882a593Smuzhiyun compat_uint_t charcount;
1007*4882a593Smuzhiyun compat_caddr_t data; /* font data with height fixed to 32 */
1008*4882a593Smuzhiyun };
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun static inline int
compat_kdfontop_ioctl(struct compat_console_font_op __user * fontop,int perm,struct console_font_op * op,struct vc_data * vc)1011*4882a593Smuzhiyun compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
1012*4882a593Smuzhiyun int perm, struct console_font_op *op, struct vc_data *vc)
1013*4882a593Smuzhiyun {
1014*4882a593Smuzhiyun int i;
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
1017*4882a593Smuzhiyun return -EFAULT;
1018*4882a593Smuzhiyun if (!perm && op->op != KD_FONT_OP_GET)
1019*4882a593Smuzhiyun return -EPERM;
1020*4882a593Smuzhiyun op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
1021*4882a593Smuzhiyun i = con_font_op(vc, op);
1022*4882a593Smuzhiyun if (i)
1023*4882a593Smuzhiyun return i;
1024*4882a593Smuzhiyun ((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
1025*4882a593Smuzhiyun if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
1026*4882a593Smuzhiyun return -EFAULT;
1027*4882a593Smuzhiyun return 0;
1028*4882a593Smuzhiyun }
1029*4882a593Smuzhiyun
1030*4882a593Smuzhiyun struct compat_unimapdesc {
1031*4882a593Smuzhiyun unsigned short entry_ct;
1032*4882a593Smuzhiyun compat_caddr_t entries;
1033*4882a593Smuzhiyun };
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun static inline int
compat_unimap_ioctl(unsigned int cmd,struct compat_unimapdesc __user * user_ud,int perm,struct vc_data * vc)1036*4882a593Smuzhiyun compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
1037*4882a593Smuzhiyun int perm, struct vc_data *vc)
1038*4882a593Smuzhiyun {
1039*4882a593Smuzhiyun struct compat_unimapdesc tmp;
1040*4882a593Smuzhiyun struct unipair __user *tmp_entries;
1041*4882a593Smuzhiyun
1042*4882a593Smuzhiyun if (copy_from_user(&tmp, user_ud, sizeof tmp))
1043*4882a593Smuzhiyun return -EFAULT;
1044*4882a593Smuzhiyun tmp_entries = compat_ptr(tmp.entries);
1045*4882a593Smuzhiyun switch (cmd) {
1046*4882a593Smuzhiyun case PIO_UNIMAP:
1047*4882a593Smuzhiyun if (!perm)
1048*4882a593Smuzhiyun return -EPERM;
1049*4882a593Smuzhiyun return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
1050*4882a593Smuzhiyun case GIO_UNIMAP:
1051*4882a593Smuzhiyun if (!perm && fg_console != vc->vc_num)
1052*4882a593Smuzhiyun return -EPERM;
1053*4882a593Smuzhiyun return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
1054*4882a593Smuzhiyun }
1055*4882a593Smuzhiyun return 0;
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun
vt_compat_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg)1058*4882a593Smuzhiyun long vt_compat_ioctl(struct tty_struct *tty,
1059*4882a593Smuzhiyun unsigned int cmd, unsigned long arg)
1060*4882a593Smuzhiyun {
1061*4882a593Smuzhiyun struct vc_data *vc = tty->driver_data;
1062*4882a593Smuzhiyun struct console_font_op op; /* used in multiple places here */
1063*4882a593Smuzhiyun void __user *up = compat_ptr(arg);
1064*4882a593Smuzhiyun int perm;
1065*4882a593Smuzhiyun
1066*4882a593Smuzhiyun /*
1067*4882a593Smuzhiyun * To have permissions to do most of the vt ioctls, we either have
1068*4882a593Smuzhiyun * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
1069*4882a593Smuzhiyun */
1070*4882a593Smuzhiyun perm = 0;
1071*4882a593Smuzhiyun if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
1072*4882a593Smuzhiyun perm = 1;
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun switch (cmd) {
1075*4882a593Smuzhiyun /*
1076*4882a593Smuzhiyun * these need special handlers for incompatible data structures
1077*4882a593Smuzhiyun */
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun case KDFONTOP:
1080*4882a593Smuzhiyun return compat_kdfontop_ioctl(up, perm, &op, vc);
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun case PIO_UNIMAP:
1083*4882a593Smuzhiyun case GIO_UNIMAP:
1084*4882a593Smuzhiyun return compat_unimap_ioctl(cmd, up, perm, vc);
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun /*
1087*4882a593Smuzhiyun * all these treat 'arg' as an integer
1088*4882a593Smuzhiyun */
1089*4882a593Smuzhiyun case KIOCSOUND:
1090*4882a593Smuzhiyun case KDMKTONE:
1091*4882a593Smuzhiyun #ifdef CONFIG_X86
1092*4882a593Smuzhiyun case KDADDIO:
1093*4882a593Smuzhiyun case KDDELIO:
1094*4882a593Smuzhiyun #endif
1095*4882a593Smuzhiyun case KDSETMODE:
1096*4882a593Smuzhiyun case KDMAPDISP:
1097*4882a593Smuzhiyun case KDUNMAPDISP:
1098*4882a593Smuzhiyun case KDSKBMODE:
1099*4882a593Smuzhiyun case KDSKBMETA:
1100*4882a593Smuzhiyun case KDSKBLED:
1101*4882a593Smuzhiyun case KDSETLED:
1102*4882a593Smuzhiyun case KDSIGACCEPT:
1103*4882a593Smuzhiyun case VT_ACTIVATE:
1104*4882a593Smuzhiyun case VT_WAITACTIVE:
1105*4882a593Smuzhiyun case VT_RELDISP:
1106*4882a593Smuzhiyun case VT_DISALLOCATE:
1107*4882a593Smuzhiyun case VT_RESIZE:
1108*4882a593Smuzhiyun case VT_RESIZEX:
1109*4882a593Smuzhiyun return vt_ioctl(tty, cmd, arg);
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun /*
1112*4882a593Smuzhiyun * the rest has a compatible data structure behind arg,
1113*4882a593Smuzhiyun * but we have to convert it to a proper 64 bit pointer.
1114*4882a593Smuzhiyun */
1115*4882a593Smuzhiyun default:
1116*4882a593Smuzhiyun return vt_ioctl(tty, cmd, (unsigned long)up);
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun #endif /* CONFIG_COMPAT */
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun /*
1125*4882a593Smuzhiyun * Performs the back end of a vt switch. Called under the console
1126*4882a593Smuzhiyun * semaphore.
1127*4882a593Smuzhiyun */
complete_change_console(struct vc_data * vc)1128*4882a593Smuzhiyun static void complete_change_console(struct vc_data *vc)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun unsigned char old_vc_mode;
1131*4882a593Smuzhiyun int old = fg_console;
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun last_console = fg_console;
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun /*
1136*4882a593Smuzhiyun * If we're switching, we could be going from KD_GRAPHICS to
1137*4882a593Smuzhiyun * KD_TEXT mode or vice versa, which means we need to blank or
1138*4882a593Smuzhiyun * unblank the screen later.
1139*4882a593Smuzhiyun */
1140*4882a593Smuzhiyun old_vc_mode = vc_cons[fg_console].d->vc_mode;
1141*4882a593Smuzhiyun switch_screen(vc);
1142*4882a593Smuzhiyun
1143*4882a593Smuzhiyun /*
1144*4882a593Smuzhiyun * This can't appear below a successful kill_pid(). If it did,
1145*4882a593Smuzhiyun * then the *blank_screen operation could occur while X, having
1146*4882a593Smuzhiyun * received acqsig, is waking up on another processor. This
1147*4882a593Smuzhiyun * condition can lead to overlapping accesses to the VGA range
1148*4882a593Smuzhiyun * and the framebuffer (causing system lockups).
1149*4882a593Smuzhiyun *
1150*4882a593Smuzhiyun * To account for this we duplicate this code below only if the
1151*4882a593Smuzhiyun * controlling process is gone and we've called reset_vc.
1152*4882a593Smuzhiyun */
1153*4882a593Smuzhiyun if (old_vc_mode != vc->vc_mode) {
1154*4882a593Smuzhiyun if (vc->vc_mode == KD_TEXT)
1155*4882a593Smuzhiyun do_unblank_screen(1);
1156*4882a593Smuzhiyun else
1157*4882a593Smuzhiyun do_blank_screen(1);
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun
1160*4882a593Smuzhiyun /*
1161*4882a593Smuzhiyun * If this new console is under process control, send it a signal
1162*4882a593Smuzhiyun * telling it that it has acquired. Also check if it has died and
1163*4882a593Smuzhiyun * clean up (similar to logic employed in change_console())
1164*4882a593Smuzhiyun */
1165*4882a593Smuzhiyun if (vc->vt_mode.mode == VT_PROCESS) {
1166*4882a593Smuzhiyun /*
1167*4882a593Smuzhiyun * Send the signal as privileged - kill_pid() will
1168*4882a593Smuzhiyun * tell us if the process has gone or something else
1169*4882a593Smuzhiyun * is awry
1170*4882a593Smuzhiyun */
1171*4882a593Smuzhiyun if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
1172*4882a593Smuzhiyun /*
1173*4882a593Smuzhiyun * The controlling process has died, so we revert back to
1174*4882a593Smuzhiyun * normal operation. In this case, we'll also change back
1175*4882a593Smuzhiyun * to KD_TEXT mode. I'm not sure if this is strictly correct
1176*4882a593Smuzhiyun * but it saves the agony when the X server dies and the screen
1177*4882a593Smuzhiyun * remains blanked due to KD_GRAPHICS! It would be nice to do
1178*4882a593Smuzhiyun * this outside of VT_PROCESS but there is no single process
1179*4882a593Smuzhiyun * to account for and tracking tty count may be undesirable.
1180*4882a593Smuzhiyun */
1181*4882a593Smuzhiyun reset_vc(vc);
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun if (old_vc_mode != vc->vc_mode) {
1184*4882a593Smuzhiyun if (vc->vc_mode == KD_TEXT)
1185*4882a593Smuzhiyun do_unblank_screen(1);
1186*4882a593Smuzhiyun else
1187*4882a593Smuzhiyun do_blank_screen(1);
1188*4882a593Smuzhiyun }
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun }
1191*4882a593Smuzhiyun
1192*4882a593Smuzhiyun /*
1193*4882a593Smuzhiyun * Wake anyone waiting for their VT to activate
1194*4882a593Smuzhiyun */
1195*4882a593Smuzhiyun vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
1196*4882a593Smuzhiyun return;
1197*4882a593Smuzhiyun }
1198*4882a593Smuzhiyun
1199*4882a593Smuzhiyun /*
1200*4882a593Smuzhiyun * Performs the front-end of a vt switch
1201*4882a593Smuzhiyun */
change_console(struct vc_data * new_vc)1202*4882a593Smuzhiyun void change_console(struct vc_data *new_vc)
1203*4882a593Smuzhiyun {
1204*4882a593Smuzhiyun struct vc_data *vc;
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
1207*4882a593Smuzhiyun return;
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun /*
1210*4882a593Smuzhiyun * If this vt is in process mode, then we need to handshake with
1211*4882a593Smuzhiyun * that process before switching. Essentially, we store where that
1212*4882a593Smuzhiyun * vt wants to switch to and wait for it to tell us when it's done
1213*4882a593Smuzhiyun * (via VT_RELDISP ioctl).
1214*4882a593Smuzhiyun *
1215*4882a593Smuzhiyun * We also check to see if the controlling process still exists.
1216*4882a593Smuzhiyun * If it doesn't, we reset this vt to auto mode and continue.
1217*4882a593Smuzhiyun * This is a cheap way to track process control. The worst thing
1218*4882a593Smuzhiyun * that can happen is: we send a signal to a process, it dies, and
1219*4882a593Smuzhiyun * the switch gets "lost" waiting for a response; hopefully, the
1220*4882a593Smuzhiyun * user will try again, we'll detect the process is gone (unless
1221*4882a593Smuzhiyun * the user waits just the right amount of time :-) and revert the
1222*4882a593Smuzhiyun * vt to auto control.
1223*4882a593Smuzhiyun */
1224*4882a593Smuzhiyun vc = vc_cons[fg_console].d;
1225*4882a593Smuzhiyun if (vc->vt_mode.mode == VT_PROCESS) {
1226*4882a593Smuzhiyun /*
1227*4882a593Smuzhiyun * Send the signal as privileged - kill_pid() will
1228*4882a593Smuzhiyun * tell us if the process has gone or something else
1229*4882a593Smuzhiyun * is awry.
1230*4882a593Smuzhiyun *
1231*4882a593Smuzhiyun * We need to set vt_newvt *before* sending the signal or we
1232*4882a593Smuzhiyun * have a race.
1233*4882a593Smuzhiyun */
1234*4882a593Smuzhiyun vc->vt_newvt = new_vc->vc_num;
1235*4882a593Smuzhiyun if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
1236*4882a593Smuzhiyun /*
1237*4882a593Smuzhiyun * It worked. Mark the vt to switch to and
1238*4882a593Smuzhiyun * return. The process needs to send us a
1239*4882a593Smuzhiyun * VT_RELDISP ioctl to complete the switch.
1240*4882a593Smuzhiyun */
1241*4882a593Smuzhiyun return;
1242*4882a593Smuzhiyun }
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun /*
1245*4882a593Smuzhiyun * The controlling process has died, so we revert back to
1246*4882a593Smuzhiyun * normal operation. In this case, we'll also change back
1247*4882a593Smuzhiyun * to KD_TEXT mode. I'm not sure if this is strictly correct
1248*4882a593Smuzhiyun * but it saves the agony when the X server dies and the screen
1249*4882a593Smuzhiyun * remains blanked due to KD_GRAPHICS! It would be nice to do
1250*4882a593Smuzhiyun * this outside of VT_PROCESS but there is no single process
1251*4882a593Smuzhiyun * to account for and tracking tty count may be undesirable.
1252*4882a593Smuzhiyun */
1253*4882a593Smuzhiyun reset_vc(vc);
1254*4882a593Smuzhiyun
1255*4882a593Smuzhiyun /*
1256*4882a593Smuzhiyun * Fall through to normal (VT_AUTO) handling of the switch...
1257*4882a593Smuzhiyun */
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun
1260*4882a593Smuzhiyun /*
1261*4882a593Smuzhiyun * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
1262*4882a593Smuzhiyun */
1263*4882a593Smuzhiyun if (vc->vc_mode == KD_GRAPHICS)
1264*4882a593Smuzhiyun return;
1265*4882a593Smuzhiyun
1266*4882a593Smuzhiyun complete_change_console(new_vc);
1267*4882a593Smuzhiyun }
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun /* Perform a kernel triggered VT switch for suspend/resume */
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun static int disable_vt_switch;
1272*4882a593Smuzhiyun
vt_move_to_console(unsigned int vt,int alloc)1273*4882a593Smuzhiyun int vt_move_to_console(unsigned int vt, int alloc)
1274*4882a593Smuzhiyun {
1275*4882a593Smuzhiyun int prev;
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun console_lock();
1278*4882a593Smuzhiyun /* Graphics mode - up to X */
1279*4882a593Smuzhiyun if (disable_vt_switch) {
1280*4882a593Smuzhiyun console_unlock();
1281*4882a593Smuzhiyun return 0;
1282*4882a593Smuzhiyun }
1283*4882a593Smuzhiyun prev = fg_console;
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun if (alloc && vc_allocate(vt)) {
1286*4882a593Smuzhiyun /* we can't have a free VC for now. Too bad,
1287*4882a593Smuzhiyun * we don't want to mess the screen for now. */
1288*4882a593Smuzhiyun console_unlock();
1289*4882a593Smuzhiyun return -ENOSPC;
1290*4882a593Smuzhiyun }
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun if (set_console(vt)) {
1293*4882a593Smuzhiyun /*
1294*4882a593Smuzhiyun * We're unable to switch to the SUSPEND_CONSOLE.
1295*4882a593Smuzhiyun * Let the calling function know so it can decide
1296*4882a593Smuzhiyun * what to do.
1297*4882a593Smuzhiyun */
1298*4882a593Smuzhiyun console_unlock();
1299*4882a593Smuzhiyun return -EIO;
1300*4882a593Smuzhiyun }
1301*4882a593Smuzhiyun console_unlock();
1302*4882a593Smuzhiyun if (vt_waitactive(vt + 1)) {
1303*4882a593Smuzhiyun pr_debug("Suspend: Can't switch VCs.");
1304*4882a593Smuzhiyun return -EINTR;
1305*4882a593Smuzhiyun }
1306*4882a593Smuzhiyun return prev;
1307*4882a593Smuzhiyun }
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun /*
1310*4882a593Smuzhiyun * Normally during a suspend, we allocate a new console and switch to it.
1311*4882a593Smuzhiyun * When we resume, we switch back to the original console. This switch
1312*4882a593Smuzhiyun * can be slow, so on systems where the framebuffer can handle restoration
1313*4882a593Smuzhiyun * of video registers anyways, there's little point in doing the console
1314*4882a593Smuzhiyun * switch. This function allows you to disable it by passing it '0'.
1315*4882a593Smuzhiyun */
pm_set_vt_switch(int do_switch)1316*4882a593Smuzhiyun void pm_set_vt_switch(int do_switch)
1317*4882a593Smuzhiyun {
1318*4882a593Smuzhiyun console_lock();
1319*4882a593Smuzhiyun disable_vt_switch = !do_switch;
1320*4882a593Smuzhiyun console_unlock();
1321*4882a593Smuzhiyun }
1322*4882a593Smuzhiyun EXPORT_SYMBOL(pm_set_vt_switch);
1323