Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Provide access to virtual console memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * /dev/vcs: the screen as it is being viewed right now (possibly scrolled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *            [minor: N]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * /dev/vcsaN: idem, but including attributes, and prefixed with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *	the 4 bytes lines,columns,x,y (as screendump used to give).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *	Attribute/character pair is in native endianity.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *            [minor: N+128]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  * /dev/vcsuN: similar to /dev/vcsaN but using 4-byte unicode values
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  *	instead of 1-byte screen glyph values.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  *            [minor: N+64]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  * /dev/vcsuaN: same idea as /dev/vcsaN for unicode (not yet implemented).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  * This replaces screendump and part of selection, so that the system
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  * administrator can control access using file system permissions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  * aeb@cwi.nl - efter Friedas begravelse - 950211
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)  * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25)  *	 - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)  *	 - making it shorter - scr_readw are macros which expand in PRETTY long code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #include <linux/major.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) #include <linux/vt_kern.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) #include <linux/selection.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) #include <linux/kbd_kern.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) #include <linux/poll.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) #include <linux/signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) #include <linux/notifier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) #include <asm/byteorder.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) #define HEADER_SIZE	4u
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57)  * Our minor space:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59)  *   0 ... 63	glyph mode without attributes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60)  *  64 ... 127	unicode mode without attributes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61)  * 128 ... 191	glyph mode with attributes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62)  * 192 ... 255	unused (reserved for unicode with attributes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64)  * This relies on MAX_NR_CONSOLES being  <= 63, meaning 63 actual consoles
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65)  * with minors 0, 64, 128 and 192 being proxies for the foreground console.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) #if MAX_NR_CONSOLES > 63
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) #warning "/dev/vcs* devices may not accommodate more than 63 consoles"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) #define console(inode)		(iminor(inode) & 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) #define use_unicode(inode)	(iminor(inode) & 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) #define use_attributes(inode)	(iminor(inode) & 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) struct vcs_poll_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	struct notifier_block notifier;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	unsigned int cons_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	int event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	wait_queue_head_t waitq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	struct fasync_struct *fasync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	struct vt_notifier_param *param = _param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	struct vc_data *vc = param->vc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	struct vcs_poll_data *poll =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 		container_of(nb, struct vcs_poll_data, notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	int currcons = poll->cons_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	int fa_band;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	switch (code) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	case VT_UPDATE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 		fa_band = POLL_PRI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	case VT_DEALLOCATE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		fa_band = POLL_HUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 		return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	if (currcons == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		currcons = fg_console;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		currcons--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	if (currcons != vc->vc_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	poll->event = code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	wake_up_interruptible(&poll->waitq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	kill_fasync(&poll->fasync, SIGIO, fa_band);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) vcs_poll_data_free(struct vcs_poll_data *poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	unregister_vt_notifier(&poll->notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	kfree(poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static struct vcs_poll_data *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) vcs_poll_data_get(struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	struct vcs_poll_data *poll = file->private_data, *kill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	if (poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		return poll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	poll = kzalloc(sizeof(*poll), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	if (!poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	poll->cons_num = console(file_inode(file));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	init_waitqueue_head(&poll->waitq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	poll->notifier.notifier_call = vcs_notifier;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	 * In order not to lose any update event, we must pretend one might
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	 * have occurred before we have a chance to register our notifier.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	 * This is also how user space has come to detect which kernels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	 * support POLLPRI on /dev/vcs* devices i.e. using poll() with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	 * POLLPRI and a zero timeout.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	poll->event = VT_UPDATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	if (register_vt_notifier(&poll->notifier) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 		kfree(poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	 * This code may be called either through ->poll() or ->fasync().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	 * If we have two threads using the same file descriptor, they could
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	 * both enter this function, both notice that the structure hasn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	 * been allocated yet and go ahead allocating it in parallel, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	 * only one of them must survive and be shared otherwise we'd leak
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	 * memory with a dangling notifier callback.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	spin_lock(&file->f_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	if (!file->private_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		file->private_data = poll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		/* someone else raced ahead of us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		kill = poll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		poll = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	spin_unlock(&file->f_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	if (kill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		vcs_poll_data_free(kill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	return poll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)  * vcs_vc -- return VC for @inode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)  * @inode: inode for which to return a VC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)  * @viewed: returns whether this console is currently foreground (viewed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)  * Must be called with console_lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static struct vc_data *vcs_vc(struct inode *inode, bool *viewed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	unsigned int currcons = console(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	WARN_CONSOLE_UNLOCKED();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	if (currcons == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 		currcons = fg_console;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 		if (viewed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 			*viewed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		currcons--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 		if (viewed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 			*viewed = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	return vc_cons[currcons].d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)  * vcs_size -- return size for a VC in @vc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)  * @vc: which VC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)  * @attr: does it use attributes?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)  * @unicode: is it unicode?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)  * Must be called with console_lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static int vcs_size(const struct vc_data *vc, bool attr, bool unicode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	WARN_CONSOLE_UNLOCKED();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	size = vc->vc_rows * vc->vc_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	if (attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		if (unicode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 			return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 		size = 2 * size + HEADER_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	} else if (unicode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 		size *= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	struct inode *inode = file_inode(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	struct vc_data *vc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	vc = vcs_vc(inode, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	if (!vc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 		console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 		return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	size = vcs_size(vc, use_attributes(inode), use_unicode(inode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	if (size < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 		return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	return fixed_size_llseek(file, offset, orig, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static int vcs_read_buf_uni(struct vc_data *vc, char *con_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 		unsigned int pos, unsigned int count, bool viewed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	unsigned int nr, row, col, maxcol = vc->vc_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	ret = vc_uniscr_check(vc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	pos /= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	row = pos / maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	col = pos % maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	nr = maxcol - col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 		if (nr > count / 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 			nr = count / 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 		vc_uniscr_copy_line(vc, con_buf, viewed, row, col, nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 		con_buf += nr * 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 		count -= nr * 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 		row++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 		col = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 		nr = maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	} while (count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static void vcs_read_buf_noattr(const struct vc_data *vc, char *con_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 		unsigned int pos, unsigned int count, bool viewed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	u16 *org;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	unsigned int col, maxcol = vc->vc_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	org = screen_pos(vc, pos, viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	col = pos % maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	pos += maxcol - col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	while (count-- > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		*con_buf++ = (vcs_scr_readw(vc, org++) & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		if (++col == maxcol) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 			org = screen_pos(vc, pos, viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 			col = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 			pos += maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static unsigned int vcs_read_buf(const struct vc_data *vc, char *con_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 		unsigned int pos, unsigned int count, bool viewed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 		unsigned int *skip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	u16 *org, *con_buf16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	unsigned int col, maxcol = vc->vc_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	unsigned int filled = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	if (pos < HEADER_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 		/* clamp header values if they don't fit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 		con_buf[0] = min(vc->vc_rows, 0xFFu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 		con_buf[1] = min(vc->vc_cols, 0xFFu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 		getconsxy(vc, con_buf + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		*skip += pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		count += pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 		if (count > CON_BUF_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 			count = CON_BUF_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 			filled = count - pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 		/* Advance state pointers and move on. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 		count -= min(HEADER_SIZE, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 		pos = HEADER_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 		con_buf += HEADER_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 		/* If count >= 0, then pos is even... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 	} else if (pos & 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 		 * Skip first byte for output if start address is odd. Update
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 		 * region sizes up/down depending on free space in buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 		(*skip)++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 		if (count < CON_BUF_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 			filled--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	if (!count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 		return filled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	pos -= HEADER_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	pos /= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	col = pos % maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	org = screen_pos(vc, pos, viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	pos += maxcol - col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	 * Buffer has even length, so we can always copy character + attribute.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	 * We do not copy last byte to userspace if count is odd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	count = (count + 1) / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	con_buf16 = (u16 *)con_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	while (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 		*con_buf16++ = vcs_scr_readw(vc, org++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 		count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		if (++col == maxcol) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 			org = screen_pos(vc, pos, viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 			col = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 			pos += maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 	return filled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 	struct inode *inode = file_inode(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	struct vc_data *vc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 	struct vcs_poll_data *poll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 	unsigned int read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 	ssize_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 	char *con_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 	loff_t pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 	bool viewed, attr, uni_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 	con_buf = (char *) __get_free_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 	if (!con_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 	pos = *ppos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	/* Select the proper current console and verify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 	 * sanity of the situation under the console lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	uni_mode = use_unicode(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	attr = use_attributes(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 	ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 	vc = vcs_vc(inode, &viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	if (!vc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 		goto unlock_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	if (pos < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 		goto unlock_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	/* we enforce 32-bit alignment for pos and count in unicode mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 	if (uni_mode && (pos | count) & 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 		goto unlock_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	poll = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	if (count && poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 		poll->event = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 	read = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 	ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	while (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 		unsigned int this_round, skip = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 		int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 		/* Check whether we are above size each round,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 		 * as copy_to_user at the end of this loop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 		 * could sleep.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 		size = vcs_size(vc, attr, uni_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 		if (size < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 			if (read)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 			ret = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 			goto unlock_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 		if (pos >= size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 		if (count > size - pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 			count = size - pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 		this_round = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 		if (this_round > CON_BUF_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 			this_round = CON_BUF_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 		/* Perform the whole read into the local con_buf.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 		 * Then we can drop the console spinlock and safely
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 		 * attempt to move it to userspace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 		if (uni_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 			ret = vcs_read_buf_uni(vc, con_buf, pos, this_round,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 					viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 			if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 		} else if (!attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 			vcs_read_buf_noattr(vc, con_buf, pos, this_round,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 					viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 			this_round = vcs_read_buf(vc, con_buf, pos, this_round,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 					viewed, &skip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 		/* Finally, release the console semaphore while we push
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 		 * all the data to userspace from our temporary buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 		 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 		 * AKPM: Even though it's a semaphore, we should drop it because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 		 * the pagefault handling code may want to call printk().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 		console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 		ret = copy_to_user(buf, con_buf + skip, this_round);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 		console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 		if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 			read += this_round - ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 			ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 		buf += this_round;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 		pos += this_round;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 		read += this_round;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 		count -= this_round;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	*ppos += read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	if (read)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 		ret = read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) unlock_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 	free_page((unsigned long) con_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static u16 *vcs_write_buf_noattr(struct vc_data *vc, const char *con_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 		unsigned int pos, unsigned int count, bool viewed, u16 **org0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	u16 *org;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 	unsigned int col, maxcol = vc->vc_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 	*org0 = org = screen_pos(vc, pos, viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	col = pos % maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	pos += maxcol - col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 	while (count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 		unsigned char c = *con_buf++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 		count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 		vcs_scr_writew(vc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 			       (vcs_scr_readw(vc, org) & 0xff00) | c, org);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 		org++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 		if (++col == maxcol) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 			org = screen_pos(vc, pos, viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 			col = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 			pos += maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	return org;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)  * Compilers (gcc 10) are unable to optimize the swap in cpu_to_le16. So do it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)  * the poor man way.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) static inline u16 vc_compile_le16(u8 hi, u8 lo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) #ifdef __BIG_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 	return (lo << 8u) | hi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 	return (hi << 8u) | lo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) static u16 *vcs_write_buf(struct vc_data *vc, const char *con_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 		unsigned int pos, unsigned int count, bool viewed, u16 **org0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	u16 *org;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	unsigned int col, maxcol = vc->vc_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 	unsigned char c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 	/* header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 	if (pos < HEADER_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 		char header[HEADER_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 		getconsxy(vc, header + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 		while (pos < HEADER_SIZE && count > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 			count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 			header[pos++] = *con_buf++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 		if (!viewed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 			putconsxy(vc, header + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	if (!count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 	pos -= HEADER_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 	col = (pos/2) % maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 	*org0 = org = screen_pos(vc, pos/2, viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	/* odd pos -- the first single character */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	if (pos & 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 		count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 		c = *con_buf++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 		vcs_scr_writew(vc, vc_compile_le16(c, vcs_scr_readw(vc, org)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 				org);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 		org++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 		pos++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 		if (++col == maxcol) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 			org = screen_pos(vc, pos/2, viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 			col = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 	pos /= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 	pos += maxcol - col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 	/* even pos -- handle attr+character pairs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 	while (count > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 		unsigned short w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 		w = get_unaligned(((unsigned short *)con_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 		vcs_scr_writew(vc, w, org++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 		con_buf += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 		count -= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 		if (++col == maxcol) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 			org = screen_pos(vc, pos, viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 			col = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 			pos += maxcol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 	if (!count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 		return org;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 	/* odd pos -- the remaining character */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 	c = *con_buf++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 	vcs_scr_writew(vc, vc_compile_le16(vcs_scr_readw(vc, org) >> 8, c),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 				org);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 	return org;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 	struct inode *inode = file_inode(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 	struct vc_data *vc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 	char *con_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 	u16 *org0, *org;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 	unsigned int written;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 	int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 	ssize_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 	loff_t pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 	bool viewed, attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	if (use_unicode(inode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 		return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 	con_buf = (char *) __get_free_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 	if (!con_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 	pos = *ppos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 	/* Select the proper current console and verify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 	 * sanity of the situation under the console lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 	console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 	attr = use_attributes(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 	ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 	vc = vcs_vc(inode, &viewed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) 	if (!vc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 		goto unlock_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 	size = vcs_size(vc, attr, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 	if (size < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 		ret = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 		goto unlock_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 	ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) 	if (pos < 0 || pos > size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 		goto unlock_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 	if (count > size - pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) 		count = size - pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 	written = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) 	while (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 		unsigned int this_round = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) 		if (this_round > CON_BUF_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 			this_round = CON_BUF_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) 		/* Temporarily drop the console lock so that we can read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) 		 * in the write data from userspace safely.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) 		console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 		ret = copy_from_user(con_buf, buf, this_round);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 		console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 		if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) 			this_round -= ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 			if (!this_round) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 				/* Abort loop if no data were copied. Otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 				 * fail with -EFAULT.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 				 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 				if (written)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 					break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 				ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 				goto unlock_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 		/* The vcs_size might have changed while we slept to grab
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 		 * the user buffer, so recheck.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 		 * Return data written up to now on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 		size = vcs_size(vc, attr, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 		if (size < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 			if (written)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 			ret = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 			goto unlock_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 		if (pos >= size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 		if (this_round > size - pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 			this_round = size - pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 		/* OK, now actually push the write to the console
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 		 * under the lock using the local kernel buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 		if (attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 			org = vcs_write_buf(vc, con_buf, pos, this_round,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 					viewed, &org0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 			org = vcs_write_buf_noattr(vc, con_buf, pos, this_round,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 					viewed, &org0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 		count -= this_round;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 		written += this_round;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 		buf += this_round;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) 		pos += this_round;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 		if (org)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 			update_region(vc, (unsigned long)(org0), org - org0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 	*ppos += written;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 	ret = written;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 	if (written)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 		vcs_scr_updated(vc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) unlock_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 	console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 	free_page((unsigned long) con_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) static __poll_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) vcs_poll(struct file *file, poll_table *wait)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 	struct vcs_poll_data *poll = vcs_poll_data_get(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 	__poll_t ret = DEFAULT_POLLMASK|EPOLLERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 	if (poll) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 		poll_wait(file, &poll->waitq, wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) 		switch (poll->event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 		case VT_UPDATE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) 			ret = DEFAULT_POLLMASK|EPOLLPRI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) 		case VT_DEALLOCATE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) 			ret = DEFAULT_POLLMASK|EPOLLHUP|EPOLLERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 		case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 			ret = DEFAULT_POLLMASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) vcs_fasync(int fd, struct file *file, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 	struct vcs_poll_data *poll = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 	if (!poll) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 		/* don't allocate anything if all we want is disable fasync */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 		if (!on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 			return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 		poll = vcs_poll_data_get(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) 		if (!poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) 			return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) 	return fasync_helper(fd, file, on, &poll->fasync);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) vcs_open(struct inode *inode, struct file *filp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) 	unsigned int currcons = console(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) 	bool attr = use_attributes(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) 	bool uni_mode = use_unicode(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) 	/* we currently don't support attributes in unicode mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) 	if (attr && uni_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) 		return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) 	console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) 	if(currcons && !vc_cons_allocated(currcons-1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) 		ret = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) 	console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) static int vcs_release(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) 	struct vcs_poll_data *poll = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) 	if (poll)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) 		vcs_poll_data_free(poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) static const struct file_operations vcs_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) 	.llseek		= vcs_lseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) 	.read		= vcs_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) 	.write		= vcs_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) 	.poll		= vcs_poll,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) 	.fasync		= vcs_fasync,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) 	.open		= vcs_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) 	.release	= vcs_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) static struct class *vc_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) void vcs_make_sysfs(int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) 	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) 		      "vcs%u", index + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) 	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 65), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) 		      "vcsu%u", index + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) 	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) 		      "vcsa%u", index + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) void vcs_remove_sysfs(int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) 	device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) 	device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 65));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) 	device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) int __init vcs_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) 	if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) 		panic("unable to get major %d for vcs device", VCS_MAJOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) 	vc_class = class_create(THIS_MODULE, "vc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) 	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) 	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 64), NULL, "vcsu");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) 	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) 	for (i = 0; i < MIN_NR_CONSOLES; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) 		vcs_make_sysfs(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) }