1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
260d4ae8dSGreg Kroah-Hartman /*
360d4ae8dSGreg Kroah-Hartman * This module exports the functions:
460d4ae8dSGreg Kroah-Hartman *
5496124e5SOkash Khawaja * 'int set_selection_user(struct tiocl_selection __user *,
6496124e5SOkash Khawaja * struct tty_struct *)'
7496124e5SOkash Khawaja * 'int set_selection_kernel(struct tiocl_selection *, struct tty_struct *)'
860d4ae8dSGreg Kroah-Hartman * 'void clear_selection(void)'
960d4ae8dSGreg Kroah-Hartman * 'int paste_selection(struct tty_struct *)'
1060d4ae8dSGreg Kroah-Hartman * 'int sel_loadlut(char __user *)'
1160d4ae8dSGreg Kroah-Hartman *
1260d4ae8dSGreg Kroah-Hartman * Now that /dev/vcs exists, most of this can disappear again.
1360d4ae8dSGreg Kroah-Hartman */
1460d4ae8dSGreg Kroah-Hartman
1560d4ae8dSGreg Kroah-Hartman #include <linux/module.h>
1660d4ae8dSGreg Kroah-Hartman #include <linux/tty.h>
1760d4ae8dSGreg Kroah-Hartman #include <linux/sched.h>
1860d4ae8dSGreg Kroah-Hartman #include <linux/mm.h>
1907e6124aSJiri Slaby #include <linux/mutex.h>
2060d4ae8dSGreg Kroah-Hartman #include <linux/slab.h>
2160d4ae8dSGreg Kroah-Hartman #include <linux/types.h>
2260d4ae8dSGreg Kroah-Hartman
237c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
2460d4ae8dSGreg Kroah-Hartman
2560d4ae8dSGreg Kroah-Hartman #include <linux/kbd_kern.h>
2660d4ae8dSGreg Kroah-Hartman #include <linux/vt_kern.h>
2760d4ae8dSGreg Kroah-Hartman #include <linux/consolemap.h>
2860d4ae8dSGreg Kroah-Hartman #include <linux/selection.h>
2960d4ae8dSGreg Kroah-Hartman #include <linux/tiocl.h>
3060d4ae8dSGreg Kroah-Hartman #include <linux/console.h>
31a7c8d58cSPeter Hurley #include <linux/tty_flip.h>
3260d4ae8dSGreg Kroah-Hartman
33687bff0cSJiri Slaby #include <linux/sched/signal.h>
34687bff0cSJiri Slaby
3560d4ae8dSGreg Kroah-Hartman /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
367985723dSAndy Shevchenko #define is_space_on_vt(c) ((c) == ' ')
3760d4ae8dSGreg Kroah-Hartman
38079c9534SAlan Cox /* FIXME: all this needs locking */
399256d09fSJiri Slaby static struct vc_selection {
409256d09fSJiri Slaby struct mutex lock;
419256d09fSJiri Slaby struct vc_data *cons; /* must not be deallocated */
429256d09fSJiri Slaby char *buffer;
439256d09fSJiri Slaby unsigned int buf_len;
449256d09fSJiri Slaby volatile int start; /* cleared by clear_selection */
459256d09fSJiri Slaby int end;
469256d09fSJiri Slaby } vc_sel = {
479256d09fSJiri Slaby .lock = __MUTEX_INITIALIZER(vc_sel.lock),
489256d09fSJiri Slaby .start = -1,
499256d09fSJiri Slaby };
5060d4ae8dSGreg Kroah-Hartman
5160d4ae8dSGreg Kroah-Hartman /* clear_selection, highlight and highlight_pointer can be called
5260d4ae8dSGreg Kroah-Hartman from interrupt (via scrollback/front) */
5360d4ae8dSGreg Kroah-Hartman
5460d4ae8dSGreg Kroah-Hartman /* set reverse video on characters s-e of console with selection. */
highlight(const int s,const int e)5560d4ae8dSGreg Kroah-Hartman static inline void highlight(const int s, const int e)
5660d4ae8dSGreg Kroah-Hartman {
57b8209f69SJiri Slaby invert_screen(vc_sel.cons, s, e-s+2, true);
5860d4ae8dSGreg Kroah-Hartman }
5960d4ae8dSGreg Kroah-Hartman
6060d4ae8dSGreg Kroah-Hartman /* use complementary color to show the pointer */
highlight_pointer(const int where)6160d4ae8dSGreg Kroah-Hartman static inline void highlight_pointer(const int where)
6260d4ae8dSGreg Kroah-Hartman {
639256d09fSJiri Slaby complement_pos(vc_sel.cons, where);
6460d4ae8dSGreg Kroah-Hartman }
6560d4ae8dSGreg Kroah-Hartman
669bfdc261SAdam Borowski static u32
sel_pos(int n,bool unicode)67555b4ef7SJiri Slaby sel_pos(int n, bool unicode)
6860d4ae8dSGreg Kroah-Hartman {
69555b4ef7SJiri Slaby if (unicode)
709256d09fSJiri Slaby return screen_glyph_unicode(vc_sel.cons, n / 2);
71d9ebb906SJiri Slaby return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n),
72d9ebb906SJiri Slaby false);
7360d4ae8dSGreg Kroah-Hartman }
7460d4ae8dSGreg Kroah-Hartman
755289475dSAlan Cox /**
765289475dSAlan Cox * clear_selection - remove current selection
775289475dSAlan Cox *
785289475dSAlan Cox * Remove the current selection highlight, if any from the console
795289475dSAlan Cox * holding the selection. The caller must hold the console lock.
805289475dSAlan Cox */
clear_selection(void)815289475dSAlan Cox void clear_selection(void)
825289475dSAlan Cox {
8360d4ae8dSGreg Kroah-Hartman highlight_pointer(-1); /* hide the pointer */
849256d09fSJiri Slaby if (vc_sel.start != -1) {
859256d09fSJiri Slaby highlight(vc_sel.start, vc_sel.end);
869256d09fSJiri Slaby vc_sel.start = -1;
8760d4ae8dSGreg Kroah-Hartman }
8860d4ae8dSGreg Kroah-Hartman }
89496124e5SOkash Khawaja EXPORT_SYMBOL_GPL(clear_selection);
9060d4ae8dSGreg Kroah-Hartman
vc_is_sel(struct vc_data * vc)91dce05aa6SJiri Slaby bool vc_is_sel(struct vc_data *vc)
92dce05aa6SJiri Slaby {
939256d09fSJiri Slaby return vc == vc_sel.cons;
94dce05aa6SJiri Slaby }
95dce05aa6SJiri Slaby
9660d4ae8dSGreg Kroah-Hartman /*
9760d4ae8dSGreg Kroah-Hartman * User settable table: what characters are to be considered alphabetic?
987f1534e1SAdam Borowski * 128 bits. Locked by the console lock.
9960d4ae8dSGreg Kroah-Hartman */
1007f1534e1SAdam Borowski static u32 inwordLut[]={
10160d4ae8dSGreg Kroah-Hartman 0x00000000, /* control chars */
1027d6d44aeSAdam Borowski 0x03FFE000, /* digits and "-./" */
10360d4ae8dSGreg Kroah-Hartman 0x87FFFFFE, /* uppercase and '_' */
10460d4ae8dSGreg Kroah-Hartman 0x07FFFFFE, /* lowercase */
10560d4ae8dSGreg Kroah-Hartman };
10660d4ae8dSGreg Kroah-Hartman
inword(const u32 c)1079bfdc261SAdam Borowski static inline int inword(const u32 c)
1089bfdc261SAdam Borowski {
1097f1534e1SAdam Borowski return c > 0x7f || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
11060d4ae8dSGreg Kroah-Hartman }
11160d4ae8dSGreg Kroah-Hartman
1125289475dSAlan Cox /**
113816cea10SLee Jones * sel_loadlut() - load the LUT table
1145289475dSAlan Cox * @p: user table
1155289475dSAlan Cox *
1165289475dSAlan Cox * Load the LUT table from user space. The caller must hold the console
1175289475dSAlan Cox * lock. Make a temporary copy so a partial update doesn't make a mess.
1185289475dSAlan Cox */
sel_loadlut(char __user * p)11960d4ae8dSGreg Kroah-Hartman int sel_loadlut(char __user *p)
12060d4ae8dSGreg Kroah-Hartman {
1217f1534e1SAdam Borowski u32 tmplut[ARRAY_SIZE(inwordLut)];
1227f1534e1SAdam Borowski if (copy_from_user(tmplut, (u32 __user *)(p+4), sizeof(inwordLut)))
1235289475dSAlan Cox return -EFAULT;
1247f1534e1SAdam Borowski memcpy(inwordLut, tmplut, sizeof(inwordLut));
1255289475dSAlan Cox return 0;
12660d4ae8dSGreg Kroah-Hartman }
12760d4ae8dSGreg Kroah-Hartman
12860d4ae8dSGreg Kroah-Hartman /* does screen address p correspond to character at LH/RH edge of screen? */
atedge(const int p,int size_row)12960d4ae8dSGreg Kroah-Hartman static inline int atedge(const int p, int size_row)
13060d4ae8dSGreg Kroah-Hartman {
13160d4ae8dSGreg Kroah-Hartman return (!(p % size_row) || !((p + 2) % size_row));
13260d4ae8dSGreg Kroah-Hartman }
13360d4ae8dSGreg Kroah-Hartman
134df155d2dSAdam Borowski /* stores the char in UTF8 and returns the number of bytes used (1-4) */
store_utf8(u32 c,char * p)135df155d2dSAdam Borowski static int store_utf8(u32 c, char *p)
13660d4ae8dSGreg Kroah-Hartman {
13760d4ae8dSGreg Kroah-Hartman if (c < 0x80) {
13860d4ae8dSGreg Kroah-Hartman /* 0******* */
13960d4ae8dSGreg Kroah-Hartman p[0] = c;
14060d4ae8dSGreg Kroah-Hartman return 1;
14160d4ae8dSGreg Kroah-Hartman } else if (c < 0x800) {
14260d4ae8dSGreg Kroah-Hartman /* 110***** 10****** */
14360d4ae8dSGreg Kroah-Hartman p[0] = 0xc0 | (c >> 6);
14460d4ae8dSGreg Kroah-Hartman p[1] = 0x80 | (c & 0x3f);
14560d4ae8dSGreg Kroah-Hartman return 2;
146df155d2dSAdam Borowski } else if (c < 0x10000) {
14760d4ae8dSGreg Kroah-Hartman /* 1110**** 10****** 10****** */
14860d4ae8dSGreg Kroah-Hartman p[0] = 0xe0 | (c >> 12);
14960d4ae8dSGreg Kroah-Hartman p[1] = 0x80 | ((c >> 6) & 0x3f);
15060d4ae8dSGreg Kroah-Hartman p[2] = 0x80 | (c & 0x3f);
15160d4ae8dSGreg Kroah-Hartman return 3;
152df155d2dSAdam Borowski } else if (c < 0x110000) {
153df155d2dSAdam Borowski /* 11110*** 10****** 10****** 10****** */
154df155d2dSAdam Borowski p[0] = 0xf0 | (c >> 18);
155df155d2dSAdam Borowski p[1] = 0x80 | ((c >> 12) & 0x3f);
156df155d2dSAdam Borowski p[2] = 0x80 | ((c >> 6) & 0x3f);
157df155d2dSAdam Borowski p[3] = 0x80 | (c & 0x3f);
158df155d2dSAdam Borowski return 4;
159df155d2dSAdam Borowski } else {
160df155d2dSAdam Borowski /* outside Unicode, replace with U+FFFD */
161df155d2dSAdam Borowski p[0] = 0xef;
162df155d2dSAdam Borowski p[1] = 0xbf;
163df155d2dSAdam Borowski p[2] = 0xbd;
164df155d2dSAdam Borowski return 3;
16560d4ae8dSGreg Kroah-Hartman }
16660d4ae8dSGreg Kroah-Hartman }
16760d4ae8dSGreg Kroah-Hartman
1685289475dSAlan Cox /**
169496124e5SOkash Khawaja * set_selection_user - set the current selection.
1705289475dSAlan Cox * @sel: user selection info
1715289475dSAlan Cox * @tty: the console tty
1725289475dSAlan Cox *
1735289475dSAlan Cox * Invoked by the ioctl handle for the vt layer.
1745289475dSAlan Cox *
1755289475dSAlan Cox * The entire selection process is managed under the console_lock. It's
1765289475dSAlan Cox * a lot under the lock but its hardly a performance path
1775289475dSAlan Cox */
set_selection_user(const struct tiocl_selection __user * sel,struct tty_struct * tty)178496124e5SOkash Khawaja int set_selection_user(const struct tiocl_selection __user *sel,
179496124e5SOkash Khawaja struct tty_struct *tty)
180496124e5SOkash Khawaja {
181496124e5SOkash Khawaja struct tiocl_selection v;
182496124e5SOkash Khawaja
183496124e5SOkash Khawaja if (copy_from_user(&v, sel, sizeof(*sel)))
184496124e5SOkash Khawaja return -EFAULT;
185496124e5SOkash Khawaja
186496124e5SOkash Khawaja return set_selection_kernel(&v, tty);
187496124e5SOkash Khawaja }
188496124e5SOkash Khawaja
vc_selection_store_chars(struct vc_data * vc,bool unicode)1898fd31e69SJiri Slaby static int vc_selection_store_chars(struct vc_data *vc, bool unicode)
1908fd31e69SJiri Slaby {
1918fd31e69SJiri Slaby char *bp, *obp;
1928fd31e69SJiri Slaby unsigned int i;
1938fd31e69SJiri Slaby
1948fd31e69SJiri Slaby /* Allocate a new buffer before freeing the old one ... */
1958fd31e69SJiri Slaby /* chars can take up to 4 bytes with unicode */
1968fd31e69SJiri Slaby bp = kmalloc_array((vc_sel.end - vc_sel.start) / 2 + 1, unicode ? 4 : 1,
19744c413d9SAlexey Kardashevskiy GFP_KERNEL | __GFP_NOWARN);
1988fd31e69SJiri Slaby if (!bp) {
1998fd31e69SJiri Slaby printk(KERN_WARNING "selection: kmalloc() failed\n");
2008fd31e69SJiri Slaby clear_selection();
2018fd31e69SJiri Slaby return -ENOMEM;
2028fd31e69SJiri Slaby }
2038fd31e69SJiri Slaby kfree(vc_sel.buffer);
2048fd31e69SJiri Slaby vc_sel.buffer = bp;
2058fd31e69SJiri Slaby
2068fd31e69SJiri Slaby obp = bp;
2078fd31e69SJiri Slaby for (i = vc_sel.start; i <= vc_sel.end; i += 2) {
2088fd31e69SJiri Slaby u32 c = sel_pos(i, unicode);
2098fd31e69SJiri Slaby if (unicode)
2108fd31e69SJiri Slaby bp += store_utf8(c, bp);
2118fd31e69SJiri Slaby else
2128fd31e69SJiri Slaby *bp++ = c;
2137985723dSAndy Shevchenko if (!is_space_on_vt(c))
2148fd31e69SJiri Slaby obp = bp;
2158fd31e69SJiri Slaby if (!((i + 2) % vc->vc_size_row)) {
2168fd31e69SJiri Slaby /* strip trailing blanks from line and add newline,
2178fd31e69SJiri Slaby unless non-space at end of line. */
2188fd31e69SJiri Slaby if (obp != bp) {
2198fd31e69SJiri Slaby bp = obp;
2208fd31e69SJiri Slaby *bp++ = '\r';
2218fd31e69SJiri Slaby }
2228fd31e69SJiri Slaby obp = bp;
2238fd31e69SJiri Slaby }
2248fd31e69SJiri Slaby }
2258fd31e69SJiri Slaby vc_sel.buf_len = bp - vc_sel.buffer;
2268fd31e69SJiri Slaby
2278fd31e69SJiri Slaby return 0;
2288fd31e69SJiri Slaby }
2298fd31e69SJiri Slaby
vc_do_selection(struct vc_data * vc,unsigned short mode,int ps,int pe)2309ba4ddbcSJiri Slaby static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps,
2319ba4ddbcSJiri Slaby int pe)
23260d4ae8dSGreg Kroah-Hartman {
2332a479aa8SAl Viro int new_sel_start, new_sel_end, spc;
2349ba4ddbcSJiri Slaby bool unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE;
23560d4ae8dSGreg Kroah-Hartman
2369ba4ddbcSJiri Slaby switch (mode) {
23760d4ae8dSGreg Kroah-Hartman case TIOCL_SELCHAR: /* character-by-character selection */
23860d4ae8dSGreg Kroah-Hartman new_sel_start = ps;
23960d4ae8dSGreg Kroah-Hartman new_sel_end = pe;
24060d4ae8dSGreg Kroah-Hartman break;
24160d4ae8dSGreg Kroah-Hartman case TIOCL_SELWORD: /* word-by-word selection */
2427985723dSAndy Shevchenko spc = is_space_on_vt(sel_pos(ps, unicode));
243bc80932cSJiri Slaby for (new_sel_start = ps; ; ps -= 2) {
2447985723dSAndy Shevchenko if ((spc && !is_space_on_vt(sel_pos(ps, unicode))) ||
245555b4ef7SJiri Slaby (!spc && !inword(sel_pos(ps, unicode))))
24660d4ae8dSGreg Kroah-Hartman break;
24760d4ae8dSGreg Kroah-Hartman new_sel_start = ps;
24860d4ae8dSGreg Kroah-Hartman if (!(ps % vc->vc_size_row))
24960d4ae8dSGreg Kroah-Hartman break;
25060d4ae8dSGreg Kroah-Hartman }
251bc80932cSJiri Slaby
2527985723dSAndy Shevchenko spc = is_space_on_vt(sel_pos(pe, unicode));
253bc80932cSJiri Slaby for (new_sel_end = pe; ; pe += 2) {
2547985723dSAndy Shevchenko if ((spc && !is_space_on_vt(sel_pos(pe, unicode))) ||
255555b4ef7SJiri Slaby (!spc && !inword(sel_pos(pe, unicode))))
25660d4ae8dSGreg Kroah-Hartman break;
25760d4ae8dSGreg Kroah-Hartman new_sel_end = pe;
25860d4ae8dSGreg Kroah-Hartman if (!((pe + 2) % vc->vc_size_row))
25960d4ae8dSGreg Kroah-Hartman break;
26060d4ae8dSGreg Kroah-Hartman }
26160d4ae8dSGreg Kroah-Hartman break;
26260d4ae8dSGreg Kroah-Hartman case TIOCL_SELLINE: /* line-by-line selection */
263f0e8e3daSJiri Slaby new_sel_start = rounddown(ps, vc->vc_size_row);
264f0e8e3daSJiri Slaby new_sel_end = rounddown(pe, vc->vc_size_row) +
265f0e8e3daSJiri Slaby vc->vc_size_row - 2;
26660d4ae8dSGreg Kroah-Hartman break;
26760d4ae8dSGreg Kroah-Hartman case TIOCL_SELPOINTER:
26860d4ae8dSGreg Kroah-Hartman highlight_pointer(pe);
269e8c75a30SJiri Slaby return 0;
27060d4ae8dSGreg Kroah-Hartman default:
271e8c75a30SJiri Slaby return -EINVAL;
27260d4ae8dSGreg Kroah-Hartman }
27360d4ae8dSGreg Kroah-Hartman
27460d4ae8dSGreg Kroah-Hartman /* remove the pointer */
27560d4ae8dSGreg Kroah-Hartman highlight_pointer(-1);
27660d4ae8dSGreg Kroah-Hartman
27760d4ae8dSGreg Kroah-Hartman /* select to end of line if on trailing space */
27860d4ae8dSGreg Kroah-Hartman if (new_sel_end > new_sel_start &&
27960d4ae8dSGreg Kroah-Hartman !atedge(new_sel_end, vc->vc_size_row) &&
2807985723dSAndy Shevchenko is_space_on_vt(sel_pos(new_sel_end, unicode))) {
28160d4ae8dSGreg Kroah-Hartman for (pe = new_sel_end + 2; ; pe += 2)
2827985723dSAndy Shevchenko if (!is_space_on_vt(sel_pos(pe, unicode)) ||
28360d4ae8dSGreg Kroah-Hartman atedge(pe, vc->vc_size_row))
28460d4ae8dSGreg Kroah-Hartman break;
2857985723dSAndy Shevchenko if (is_space_on_vt(sel_pos(pe, unicode)))
28660d4ae8dSGreg Kroah-Hartman new_sel_end = pe;
28760d4ae8dSGreg Kroah-Hartman }
2889256d09fSJiri Slaby if (vc_sel.start == -1) /* no current selection */
28960d4ae8dSGreg Kroah-Hartman highlight(new_sel_start, new_sel_end);
2909256d09fSJiri Slaby else if (new_sel_start == vc_sel.start)
29160d4ae8dSGreg Kroah-Hartman {
2929256d09fSJiri Slaby if (new_sel_end == vc_sel.end) /* no action required */
293e8c75a30SJiri Slaby return 0;
2949256d09fSJiri Slaby else if (new_sel_end > vc_sel.end) /* extend to right */
2959256d09fSJiri Slaby highlight(vc_sel.end + 2, new_sel_end);
29660d4ae8dSGreg Kroah-Hartman else /* contract from right */
2979256d09fSJiri Slaby highlight(new_sel_end + 2, vc_sel.end);
29860d4ae8dSGreg Kroah-Hartman }
2999256d09fSJiri Slaby else if (new_sel_end == vc_sel.end)
30060d4ae8dSGreg Kroah-Hartman {
3019256d09fSJiri Slaby if (new_sel_start < vc_sel.start) /* extend to left */
3029256d09fSJiri Slaby highlight(new_sel_start, vc_sel.start - 2);
30360d4ae8dSGreg Kroah-Hartman else /* contract from left */
3049256d09fSJiri Slaby highlight(vc_sel.start, new_sel_start - 2);
30560d4ae8dSGreg Kroah-Hartman }
30660d4ae8dSGreg Kroah-Hartman else /* some other case; start selection from scratch */
30760d4ae8dSGreg Kroah-Hartman {
30860d4ae8dSGreg Kroah-Hartman clear_selection();
30960d4ae8dSGreg Kroah-Hartman highlight(new_sel_start, new_sel_end);
31060d4ae8dSGreg Kroah-Hartman }
3119256d09fSJiri Slaby vc_sel.start = new_sel_start;
3129256d09fSJiri Slaby vc_sel.end = new_sel_end;
31360d4ae8dSGreg Kroah-Hartman
3148fd31e69SJiri Slaby return vc_selection_store_chars(vc, unicode);
31560d4ae8dSGreg Kroah-Hartman }
3164b70dd57SJiri Slaby
vc_selection(struct vc_data * vc,struct tiocl_selection * v,struct tty_struct * tty)3179ba4ddbcSJiri Slaby static int vc_selection(struct vc_data *vc, struct tiocl_selection *v,
3189ba4ddbcSJiri Slaby struct tty_struct *tty)
3199ba4ddbcSJiri Slaby {
3209ba4ddbcSJiri Slaby int ps, pe;
3219ba4ddbcSJiri Slaby
3229ba4ddbcSJiri Slaby poke_blanked_console();
3239ba4ddbcSJiri Slaby
3249ba4ddbcSJiri Slaby if (v->sel_mode == TIOCL_SELCLEAR) {
3259ba4ddbcSJiri Slaby /* useful for screendump without selection highlights */
3269ba4ddbcSJiri Slaby clear_selection();
3279ba4ddbcSJiri Slaby return 0;
3289ba4ddbcSJiri Slaby }
3299ba4ddbcSJiri Slaby
3309ba4ddbcSJiri Slaby v->xs = min_t(u16, v->xs - 1, vc->vc_cols - 1);
3319ba4ddbcSJiri Slaby v->ys = min_t(u16, v->ys - 1, vc->vc_rows - 1);
3329ba4ddbcSJiri Slaby v->xe = min_t(u16, v->xe - 1, vc->vc_cols - 1);
3339ba4ddbcSJiri Slaby v->ye = min_t(u16, v->ye - 1, vc->vc_rows - 1);
3349ba4ddbcSJiri Slaby
3359ba4ddbcSJiri Slaby if (mouse_reporting() && (v->sel_mode & TIOCL_SELMOUSEREPORT)) {
3369ba4ddbcSJiri Slaby mouse_report(tty, v->sel_mode & TIOCL_SELBUTTONMASK, v->xs,
3379ba4ddbcSJiri Slaby v->ys);
3389ba4ddbcSJiri Slaby return 0;
3399ba4ddbcSJiri Slaby }
3409ba4ddbcSJiri Slaby
3419ba4ddbcSJiri Slaby ps = v->ys * vc->vc_size_row + (v->xs << 1);
3429ba4ddbcSJiri Slaby pe = v->ye * vc->vc_size_row + (v->xe << 1);
3439ba4ddbcSJiri Slaby if (ps > pe) /* make vc_sel.start <= vc_sel.end */
3449ba4ddbcSJiri Slaby swap(ps, pe);
3459ba4ddbcSJiri Slaby
3469ba4ddbcSJiri Slaby if (vc_sel.cons != vc) {
3479ba4ddbcSJiri Slaby clear_selection();
3489ba4ddbcSJiri Slaby vc_sel.cons = vc;
3499ba4ddbcSJiri Slaby }
3509ba4ddbcSJiri Slaby
3519ba4ddbcSJiri Slaby return vc_do_selection(vc, v->sel_mode, ps, pe);
3529ba4ddbcSJiri Slaby }
3539ba4ddbcSJiri Slaby
set_selection_kernel(struct tiocl_selection * v,struct tty_struct * tty)3544b70dd57SJiri Slaby int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
3554b70dd57SJiri Slaby {
3564b70dd57SJiri Slaby int ret;
3574b70dd57SJiri Slaby
358cb05c6c8SGreg Kroah-Hartman mutex_lock(&vc_sel.lock);
3594b70dd57SJiri Slaby console_lock();
3609ba4ddbcSJiri Slaby ret = vc_selection(vc_cons[fg_console].d, v, tty);
3614b70dd57SJiri Slaby console_unlock();
3629256d09fSJiri Slaby mutex_unlock(&vc_sel.lock);
3634b70dd57SJiri Slaby
36460d4ae8dSGreg Kroah-Hartman return ret;
36560d4ae8dSGreg Kroah-Hartman }
366496124e5SOkash Khawaja EXPORT_SYMBOL_GPL(set_selection_kernel);
36760d4ae8dSGreg Kroah-Hartman
36860d4ae8dSGreg Kroah-Hartman /* Insert the contents of the selection buffer into the
36960d4ae8dSGreg Kroah-Hartman * queue of the tty associated with the current console.
37060d4ae8dSGreg Kroah-Hartman * Invoked by ioctl().
371906cbe13SJiri Slaby *
37220f62579SAlan Cox * Locking: called without locks. Calls the ldisc wrongly with
37320f62579SAlan Cox * unsafe methods,
37460d4ae8dSGreg Kroah-Hartman */
paste_selection(struct tty_struct * tty)37560d4ae8dSGreg Kroah-Hartman int paste_selection(struct tty_struct *tty)
37660d4ae8dSGreg Kroah-Hartman {
37760d4ae8dSGreg Kroah-Hartman struct vc_data *vc = tty->driver_data;
37860d4ae8dSGreg Kroah-Hartman int pasted = 0;
379*8d9526f9SJiri Slaby (SUSE) size_t count;
38060d4ae8dSGreg Kroah-Hartman struct tty_ldisc *ld;
38160d4ae8dSGreg Kroah-Hartman DECLARE_WAITQUEUE(wait, current);
382687bff0cSJiri Slaby int ret = 0;
38360d4ae8dSGreg Kroah-Hartman
384ac751efaSTorben Hohn console_lock();
38560d4ae8dSGreg Kroah-Hartman poke_blanked_console();
386ac751efaSTorben Hohn console_unlock();
38760d4ae8dSGreg Kroah-Hartman
38860d4ae8dSGreg Kroah-Hartman ld = tty_ldisc_ref_wait(tty);
389e55afd11SPeter Hurley if (!ld)
390e55afd11SPeter Hurley return -EIO; /* ldisc was hung up */
391a7c8d58cSPeter Hurley tty_buffer_lock_exclusive(&vc->port);
39260d4ae8dSGreg Kroah-Hartman
39360d4ae8dSGreg Kroah-Hartman add_wait_queue(&vc->paste_wait, &wait);
3949256d09fSJiri Slaby mutex_lock(&vc_sel.lock);
3959256d09fSJiri Slaby while (vc_sel.buffer && vc_sel.buf_len > pasted) {
39660d4ae8dSGreg Kroah-Hartman set_current_state(TASK_INTERRUPTIBLE);
397687bff0cSJiri Slaby if (signal_pending(current)) {
398687bff0cSJiri Slaby ret = -EINTR;
399687bff0cSJiri Slaby break;
400687bff0cSJiri Slaby }
40197ef38b8SPeter Hurley if (tty_throttled(tty)) {
4029256d09fSJiri Slaby mutex_unlock(&vc_sel.lock);
40360d4ae8dSGreg Kroah-Hartman schedule();
4049256d09fSJiri Slaby mutex_lock(&vc_sel.lock);
40560d4ae8dSGreg Kroah-Hartman continue;
40660d4ae8dSGreg Kroah-Hartman }
40761e86cc9SPeter Hurley __set_current_state(TASK_RUNNING);
4089256d09fSJiri Slaby count = vc_sel.buf_len - pasted;
4099256d09fSJiri Slaby count = tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL,
41024a89d1cSPeter Hurley count);
41160d4ae8dSGreg Kroah-Hartman pasted += count;
41260d4ae8dSGreg Kroah-Hartman }
4139256d09fSJiri Slaby mutex_unlock(&vc_sel.lock);
41460d4ae8dSGreg Kroah-Hartman remove_wait_queue(&vc->paste_wait, &wait);
41560d4ae8dSGreg Kroah-Hartman __set_current_state(TASK_RUNNING);
41660d4ae8dSGreg Kroah-Hartman
417a7c8d58cSPeter Hurley tty_buffer_unlock_exclusive(&vc->port);
41860d4ae8dSGreg Kroah-Hartman tty_ldisc_deref(ld);
419687bff0cSJiri Slaby return ret;
42060d4ae8dSGreg Kroah-Hartman }
421496124e5SOkash Khawaja EXPORT_SYMBOL_GPL(paste_selection);
422