^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) }