1*60d4ae8dSGreg Kroah-Hartman /* 2*60d4ae8dSGreg Kroah-Hartman * linux/drivers/char/selection.c 3*60d4ae8dSGreg Kroah-Hartman * 4*60d4ae8dSGreg Kroah-Hartman * This module exports the functions: 5*60d4ae8dSGreg Kroah-Hartman * 6*60d4ae8dSGreg Kroah-Hartman * 'int set_selection(struct tiocl_selection __user *, struct tty_struct *)' 7*60d4ae8dSGreg Kroah-Hartman * 'void clear_selection(void)' 8*60d4ae8dSGreg Kroah-Hartman * 'int paste_selection(struct tty_struct *)' 9*60d4ae8dSGreg Kroah-Hartman * 'int sel_loadlut(char __user *)' 10*60d4ae8dSGreg Kroah-Hartman * 11*60d4ae8dSGreg Kroah-Hartman * Now that /dev/vcs exists, most of this can disappear again. 12*60d4ae8dSGreg Kroah-Hartman */ 13*60d4ae8dSGreg Kroah-Hartman 14*60d4ae8dSGreg Kroah-Hartman #include <linux/module.h> 15*60d4ae8dSGreg Kroah-Hartman #include <linux/tty.h> 16*60d4ae8dSGreg Kroah-Hartman #include <linux/sched.h> 17*60d4ae8dSGreg Kroah-Hartman #include <linux/mm.h> 18*60d4ae8dSGreg Kroah-Hartman #include <linux/slab.h> 19*60d4ae8dSGreg Kroah-Hartman #include <linux/types.h> 20*60d4ae8dSGreg Kroah-Hartman 21*60d4ae8dSGreg Kroah-Hartman #include <asm/uaccess.h> 22*60d4ae8dSGreg Kroah-Hartman 23*60d4ae8dSGreg Kroah-Hartman #include <linux/kbd_kern.h> 24*60d4ae8dSGreg Kroah-Hartman #include <linux/vt_kern.h> 25*60d4ae8dSGreg Kroah-Hartman #include <linux/consolemap.h> 26*60d4ae8dSGreg Kroah-Hartman #include <linux/selection.h> 27*60d4ae8dSGreg Kroah-Hartman #include <linux/tiocl.h> 28*60d4ae8dSGreg Kroah-Hartman #include <linux/console.h> 29*60d4ae8dSGreg Kroah-Hartman #include <linux/smp_lock.h> 30*60d4ae8dSGreg Kroah-Hartman 31*60d4ae8dSGreg Kroah-Hartman /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ 32*60d4ae8dSGreg Kroah-Hartman #define isspace(c) ((c) == ' ') 33*60d4ae8dSGreg Kroah-Hartman 34*60d4ae8dSGreg Kroah-Hartman extern void poke_blanked_console(void); 35*60d4ae8dSGreg Kroah-Hartman 36*60d4ae8dSGreg Kroah-Hartman /* Variables for selection control. */ 37*60d4ae8dSGreg Kroah-Hartman /* Use a dynamic buffer, instead of static (Dec 1994) */ 38*60d4ae8dSGreg Kroah-Hartman struct vc_data *sel_cons; /* must not be deallocated */ 39*60d4ae8dSGreg Kroah-Hartman static int use_unicode; 40*60d4ae8dSGreg Kroah-Hartman static volatile int sel_start = -1; /* cleared by clear_selection */ 41*60d4ae8dSGreg Kroah-Hartman static int sel_end; 42*60d4ae8dSGreg Kroah-Hartman static int sel_buffer_lth; 43*60d4ae8dSGreg Kroah-Hartman static char *sel_buffer; 44*60d4ae8dSGreg Kroah-Hartman 45*60d4ae8dSGreg Kroah-Hartman /* clear_selection, highlight and highlight_pointer can be called 46*60d4ae8dSGreg Kroah-Hartman from interrupt (via scrollback/front) */ 47*60d4ae8dSGreg Kroah-Hartman 48*60d4ae8dSGreg Kroah-Hartman /* set reverse video on characters s-e of console with selection. */ 49*60d4ae8dSGreg Kroah-Hartman static inline void highlight(const int s, const int e) 50*60d4ae8dSGreg Kroah-Hartman { 51*60d4ae8dSGreg Kroah-Hartman invert_screen(sel_cons, s, e-s+2, 1); 52*60d4ae8dSGreg Kroah-Hartman } 53*60d4ae8dSGreg Kroah-Hartman 54*60d4ae8dSGreg Kroah-Hartman /* use complementary color to show the pointer */ 55*60d4ae8dSGreg Kroah-Hartman static inline void highlight_pointer(const int where) 56*60d4ae8dSGreg Kroah-Hartman { 57*60d4ae8dSGreg Kroah-Hartman complement_pos(sel_cons, where); 58*60d4ae8dSGreg Kroah-Hartman } 59*60d4ae8dSGreg Kroah-Hartman 60*60d4ae8dSGreg Kroah-Hartman static u16 61*60d4ae8dSGreg Kroah-Hartman sel_pos(int n) 62*60d4ae8dSGreg Kroah-Hartman { 63*60d4ae8dSGreg Kroah-Hartman return inverse_translate(sel_cons, screen_glyph(sel_cons, n), 64*60d4ae8dSGreg Kroah-Hartman use_unicode); 65*60d4ae8dSGreg Kroah-Hartman } 66*60d4ae8dSGreg Kroah-Hartman 67*60d4ae8dSGreg Kroah-Hartman /* remove the current selection highlight, if any, 68*60d4ae8dSGreg Kroah-Hartman from the console holding the selection. */ 69*60d4ae8dSGreg Kroah-Hartman void 70*60d4ae8dSGreg Kroah-Hartman clear_selection(void) { 71*60d4ae8dSGreg Kroah-Hartman highlight_pointer(-1); /* hide the pointer */ 72*60d4ae8dSGreg Kroah-Hartman if (sel_start != -1) { 73*60d4ae8dSGreg Kroah-Hartman highlight(sel_start, sel_end); 74*60d4ae8dSGreg Kroah-Hartman sel_start = -1; 75*60d4ae8dSGreg Kroah-Hartman } 76*60d4ae8dSGreg Kroah-Hartman } 77*60d4ae8dSGreg Kroah-Hartman 78*60d4ae8dSGreg Kroah-Hartman /* 79*60d4ae8dSGreg Kroah-Hartman * User settable table: what characters are to be considered alphabetic? 80*60d4ae8dSGreg Kroah-Hartman * 256 bits 81*60d4ae8dSGreg Kroah-Hartman */ 82*60d4ae8dSGreg Kroah-Hartman static u32 inwordLut[8]={ 83*60d4ae8dSGreg Kroah-Hartman 0x00000000, /* control chars */ 84*60d4ae8dSGreg Kroah-Hartman 0x03FF0000, /* digits */ 85*60d4ae8dSGreg Kroah-Hartman 0x87FFFFFE, /* uppercase and '_' */ 86*60d4ae8dSGreg Kroah-Hartman 0x07FFFFFE, /* lowercase */ 87*60d4ae8dSGreg Kroah-Hartman 0x00000000, 88*60d4ae8dSGreg Kroah-Hartman 0x00000000, 89*60d4ae8dSGreg Kroah-Hartman 0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */ 90*60d4ae8dSGreg Kroah-Hartman 0xFF7FFFFF /* latin-1 accented letters, not division sign */ 91*60d4ae8dSGreg Kroah-Hartman }; 92*60d4ae8dSGreg Kroah-Hartman 93*60d4ae8dSGreg Kroah-Hartman static inline int inword(const u16 c) { 94*60d4ae8dSGreg Kroah-Hartman return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1); 95*60d4ae8dSGreg Kroah-Hartman } 96*60d4ae8dSGreg Kroah-Hartman 97*60d4ae8dSGreg Kroah-Hartman /* set inwordLut contents. Invoked by ioctl(). */ 98*60d4ae8dSGreg Kroah-Hartman int sel_loadlut(char __user *p) 99*60d4ae8dSGreg Kroah-Hartman { 100*60d4ae8dSGreg Kroah-Hartman return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0; 101*60d4ae8dSGreg Kroah-Hartman } 102*60d4ae8dSGreg Kroah-Hartman 103*60d4ae8dSGreg Kroah-Hartman /* does screen address p correspond to character at LH/RH edge of screen? */ 104*60d4ae8dSGreg Kroah-Hartman static inline int atedge(const int p, int size_row) 105*60d4ae8dSGreg Kroah-Hartman { 106*60d4ae8dSGreg Kroah-Hartman return (!(p % size_row) || !((p + 2) % size_row)); 107*60d4ae8dSGreg Kroah-Hartman } 108*60d4ae8dSGreg Kroah-Hartman 109*60d4ae8dSGreg Kroah-Hartman /* constrain v such that v <= u */ 110*60d4ae8dSGreg Kroah-Hartman static inline unsigned short limit(const unsigned short v, const unsigned short u) 111*60d4ae8dSGreg Kroah-Hartman { 112*60d4ae8dSGreg Kroah-Hartman return (v > u) ? u : v; 113*60d4ae8dSGreg Kroah-Hartman } 114*60d4ae8dSGreg Kroah-Hartman 115*60d4ae8dSGreg Kroah-Hartman /* stores the char in UTF8 and returns the number of bytes used (1-3) */ 116*60d4ae8dSGreg Kroah-Hartman static int store_utf8(u16 c, char *p) 117*60d4ae8dSGreg Kroah-Hartman { 118*60d4ae8dSGreg Kroah-Hartman if (c < 0x80) { 119*60d4ae8dSGreg Kroah-Hartman /* 0******* */ 120*60d4ae8dSGreg Kroah-Hartman p[0] = c; 121*60d4ae8dSGreg Kroah-Hartman return 1; 122*60d4ae8dSGreg Kroah-Hartman } else if (c < 0x800) { 123*60d4ae8dSGreg Kroah-Hartman /* 110***** 10****** */ 124*60d4ae8dSGreg Kroah-Hartman p[0] = 0xc0 | (c >> 6); 125*60d4ae8dSGreg Kroah-Hartman p[1] = 0x80 | (c & 0x3f); 126*60d4ae8dSGreg Kroah-Hartman return 2; 127*60d4ae8dSGreg Kroah-Hartman } else { 128*60d4ae8dSGreg Kroah-Hartman /* 1110**** 10****** 10****** */ 129*60d4ae8dSGreg Kroah-Hartman p[0] = 0xe0 | (c >> 12); 130*60d4ae8dSGreg Kroah-Hartman p[1] = 0x80 | ((c >> 6) & 0x3f); 131*60d4ae8dSGreg Kroah-Hartman p[2] = 0x80 | (c & 0x3f); 132*60d4ae8dSGreg Kroah-Hartman return 3; 133*60d4ae8dSGreg Kroah-Hartman } 134*60d4ae8dSGreg Kroah-Hartman } 135*60d4ae8dSGreg Kroah-Hartman 136*60d4ae8dSGreg Kroah-Hartman /* set the current selection. Invoked by ioctl() or by kernel code. */ 137*60d4ae8dSGreg Kroah-Hartman int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) 138*60d4ae8dSGreg Kroah-Hartman { 139*60d4ae8dSGreg Kroah-Hartman struct vc_data *vc = vc_cons[fg_console].d; 140*60d4ae8dSGreg Kroah-Hartman int sel_mode, new_sel_start, new_sel_end, spc; 141*60d4ae8dSGreg Kroah-Hartman char *bp, *obp; 142*60d4ae8dSGreg Kroah-Hartman int i, ps, pe, multiplier; 143*60d4ae8dSGreg Kroah-Hartman u16 c; 144*60d4ae8dSGreg Kroah-Hartman struct kbd_struct *kbd = kbd_table + fg_console; 145*60d4ae8dSGreg Kroah-Hartman 146*60d4ae8dSGreg Kroah-Hartman poke_blanked_console(); 147*60d4ae8dSGreg Kroah-Hartman 148*60d4ae8dSGreg Kroah-Hartman { unsigned short xs, ys, xe, ye; 149*60d4ae8dSGreg Kroah-Hartman 150*60d4ae8dSGreg Kroah-Hartman if (!access_ok(VERIFY_READ, sel, sizeof(*sel))) 151*60d4ae8dSGreg Kroah-Hartman return -EFAULT; 152*60d4ae8dSGreg Kroah-Hartman __get_user(xs, &sel->xs); 153*60d4ae8dSGreg Kroah-Hartman __get_user(ys, &sel->ys); 154*60d4ae8dSGreg Kroah-Hartman __get_user(xe, &sel->xe); 155*60d4ae8dSGreg Kroah-Hartman __get_user(ye, &sel->ye); 156*60d4ae8dSGreg Kroah-Hartman __get_user(sel_mode, &sel->sel_mode); 157*60d4ae8dSGreg Kroah-Hartman xs--; ys--; xe--; ye--; 158*60d4ae8dSGreg Kroah-Hartman xs = limit(xs, vc->vc_cols - 1); 159*60d4ae8dSGreg Kroah-Hartman ys = limit(ys, vc->vc_rows - 1); 160*60d4ae8dSGreg Kroah-Hartman xe = limit(xe, vc->vc_cols - 1); 161*60d4ae8dSGreg Kroah-Hartman ye = limit(ye, vc->vc_rows - 1); 162*60d4ae8dSGreg Kroah-Hartman ps = ys * vc->vc_size_row + (xs << 1); 163*60d4ae8dSGreg Kroah-Hartman pe = ye * vc->vc_size_row + (xe << 1); 164*60d4ae8dSGreg Kroah-Hartman 165*60d4ae8dSGreg Kroah-Hartman if (sel_mode == TIOCL_SELCLEAR) { 166*60d4ae8dSGreg Kroah-Hartman /* useful for screendump without selection highlights */ 167*60d4ae8dSGreg Kroah-Hartman clear_selection(); 168*60d4ae8dSGreg Kroah-Hartman return 0; 169*60d4ae8dSGreg Kroah-Hartman } 170*60d4ae8dSGreg Kroah-Hartman 171*60d4ae8dSGreg Kroah-Hartman if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) { 172*60d4ae8dSGreg Kroah-Hartman mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys); 173*60d4ae8dSGreg Kroah-Hartman return 0; 174*60d4ae8dSGreg Kroah-Hartman } 175*60d4ae8dSGreg Kroah-Hartman } 176*60d4ae8dSGreg Kroah-Hartman 177*60d4ae8dSGreg Kroah-Hartman if (ps > pe) /* make sel_start <= sel_end */ 178*60d4ae8dSGreg Kroah-Hartman { 179*60d4ae8dSGreg Kroah-Hartman int tmp = ps; 180*60d4ae8dSGreg Kroah-Hartman ps = pe; 181*60d4ae8dSGreg Kroah-Hartman pe = tmp; 182*60d4ae8dSGreg Kroah-Hartman } 183*60d4ae8dSGreg Kroah-Hartman 184*60d4ae8dSGreg Kroah-Hartman if (sel_cons != vc_cons[fg_console].d) { 185*60d4ae8dSGreg Kroah-Hartman clear_selection(); 186*60d4ae8dSGreg Kroah-Hartman sel_cons = vc_cons[fg_console].d; 187*60d4ae8dSGreg Kroah-Hartman } 188*60d4ae8dSGreg Kroah-Hartman use_unicode = kbd && kbd->kbdmode == VC_UNICODE; 189*60d4ae8dSGreg Kroah-Hartman 190*60d4ae8dSGreg Kroah-Hartman switch (sel_mode) 191*60d4ae8dSGreg Kroah-Hartman { 192*60d4ae8dSGreg Kroah-Hartman case TIOCL_SELCHAR: /* character-by-character selection */ 193*60d4ae8dSGreg Kroah-Hartman new_sel_start = ps; 194*60d4ae8dSGreg Kroah-Hartman new_sel_end = pe; 195*60d4ae8dSGreg Kroah-Hartman break; 196*60d4ae8dSGreg Kroah-Hartman case TIOCL_SELWORD: /* word-by-word selection */ 197*60d4ae8dSGreg Kroah-Hartman spc = isspace(sel_pos(ps)); 198*60d4ae8dSGreg Kroah-Hartman for (new_sel_start = ps; ; ps -= 2) 199*60d4ae8dSGreg Kroah-Hartman { 200*60d4ae8dSGreg Kroah-Hartman if ((spc && !isspace(sel_pos(ps))) || 201*60d4ae8dSGreg Kroah-Hartman (!spc && !inword(sel_pos(ps)))) 202*60d4ae8dSGreg Kroah-Hartman break; 203*60d4ae8dSGreg Kroah-Hartman new_sel_start = ps; 204*60d4ae8dSGreg Kroah-Hartman if (!(ps % vc->vc_size_row)) 205*60d4ae8dSGreg Kroah-Hartman break; 206*60d4ae8dSGreg Kroah-Hartman } 207*60d4ae8dSGreg Kroah-Hartman spc = isspace(sel_pos(pe)); 208*60d4ae8dSGreg Kroah-Hartman for (new_sel_end = pe; ; pe += 2) 209*60d4ae8dSGreg Kroah-Hartman { 210*60d4ae8dSGreg Kroah-Hartman if ((spc && !isspace(sel_pos(pe))) || 211*60d4ae8dSGreg Kroah-Hartman (!spc && !inword(sel_pos(pe)))) 212*60d4ae8dSGreg Kroah-Hartman break; 213*60d4ae8dSGreg Kroah-Hartman new_sel_end = pe; 214*60d4ae8dSGreg Kroah-Hartman if (!((pe + 2) % vc->vc_size_row)) 215*60d4ae8dSGreg Kroah-Hartman break; 216*60d4ae8dSGreg Kroah-Hartman } 217*60d4ae8dSGreg Kroah-Hartman break; 218*60d4ae8dSGreg Kroah-Hartman case TIOCL_SELLINE: /* line-by-line selection */ 219*60d4ae8dSGreg Kroah-Hartman new_sel_start = ps - ps % vc->vc_size_row; 220*60d4ae8dSGreg Kroah-Hartman new_sel_end = pe + vc->vc_size_row 221*60d4ae8dSGreg Kroah-Hartman - pe % vc->vc_size_row - 2; 222*60d4ae8dSGreg Kroah-Hartman break; 223*60d4ae8dSGreg Kroah-Hartman case TIOCL_SELPOINTER: 224*60d4ae8dSGreg Kroah-Hartman highlight_pointer(pe); 225*60d4ae8dSGreg Kroah-Hartman return 0; 226*60d4ae8dSGreg Kroah-Hartman default: 227*60d4ae8dSGreg Kroah-Hartman return -EINVAL; 228*60d4ae8dSGreg Kroah-Hartman } 229*60d4ae8dSGreg Kroah-Hartman 230*60d4ae8dSGreg Kroah-Hartman /* remove the pointer */ 231*60d4ae8dSGreg Kroah-Hartman highlight_pointer(-1); 232*60d4ae8dSGreg Kroah-Hartman 233*60d4ae8dSGreg Kroah-Hartman /* select to end of line if on trailing space */ 234*60d4ae8dSGreg Kroah-Hartman if (new_sel_end > new_sel_start && 235*60d4ae8dSGreg Kroah-Hartman !atedge(new_sel_end, vc->vc_size_row) && 236*60d4ae8dSGreg Kroah-Hartman isspace(sel_pos(new_sel_end))) { 237*60d4ae8dSGreg Kroah-Hartman for (pe = new_sel_end + 2; ; pe += 2) 238*60d4ae8dSGreg Kroah-Hartman if (!isspace(sel_pos(pe)) || 239*60d4ae8dSGreg Kroah-Hartman atedge(pe, vc->vc_size_row)) 240*60d4ae8dSGreg Kroah-Hartman break; 241*60d4ae8dSGreg Kroah-Hartman if (isspace(sel_pos(pe))) 242*60d4ae8dSGreg Kroah-Hartman new_sel_end = pe; 243*60d4ae8dSGreg Kroah-Hartman } 244*60d4ae8dSGreg Kroah-Hartman if (sel_start == -1) /* no current selection */ 245*60d4ae8dSGreg Kroah-Hartman highlight(new_sel_start, new_sel_end); 246*60d4ae8dSGreg Kroah-Hartman else if (new_sel_start == sel_start) 247*60d4ae8dSGreg Kroah-Hartman { 248*60d4ae8dSGreg Kroah-Hartman if (new_sel_end == sel_end) /* no action required */ 249*60d4ae8dSGreg Kroah-Hartman return 0; 250*60d4ae8dSGreg Kroah-Hartman else if (new_sel_end > sel_end) /* extend to right */ 251*60d4ae8dSGreg Kroah-Hartman highlight(sel_end + 2, new_sel_end); 252*60d4ae8dSGreg Kroah-Hartman else /* contract from right */ 253*60d4ae8dSGreg Kroah-Hartman highlight(new_sel_end + 2, sel_end); 254*60d4ae8dSGreg Kroah-Hartman } 255*60d4ae8dSGreg Kroah-Hartman else if (new_sel_end == sel_end) 256*60d4ae8dSGreg Kroah-Hartman { 257*60d4ae8dSGreg Kroah-Hartman if (new_sel_start < sel_start) /* extend to left */ 258*60d4ae8dSGreg Kroah-Hartman highlight(new_sel_start, sel_start - 2); 259*60d4ae8dSGreg Kroah-Hartman else /* contract from left */ 260*60d4ae8dSGreg Kroah-Hartman highlight(sel_start, new_sel_start - 2); 261*60d4ae8dSGreg Kroah-Hartman } 262*60d4ae8dSGreg Kroah-Hartman else /* some other case; start selection from scratch */ 263*60d4ae8dSGreg Kroah-Hartman { 264*60d4ae8dSGreg Kroah-Hartman clear_selection(); 265*60d4ae8dSGreg Kroah-Hartman highlight(new_sel_start, new_sel_end); 266*60d4ae8dSGreg Kroah-Hartman } 267*60d4ae8dSGreg Kroah-Hartman sel_start = new_sel_start; 268*60d4ae8dSGreg Kroah-Hartman sel_end = new_sel_end; 269*60d4ae8dSGreg Kroah-Hartman 270*60d4ae8dSGreg Kroah-Hartman /* Allocate a new buffer before freeing the old one ... */ 271*60d4ae8dSGreg Kroah-Hartman multiplier = use_unicode ? 3 : 1; /* chars can take up to 3 bytes */ 272*60d4ae8dSGreg Kroah-Hartman bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL); 273*60d4ae8dSGreg Kroah-Hartman if (!bp) { 274*60d4ae8dSGreg Kroah-Hartman printk(KERN_WARNING "selection: kmalloc() failed\n"); 275*60d4ae8dSGreg Kroah-Hartman clear_selection(); 276*60d4ae8dSGreg Kroah-Hartman return -ENOMEM; 277*60d4ae8dSGreg Kroah-Hartman } 278*60d4ae8dSGreg Kroah-Hartman kfree(sel_buffer); 279*60d4ae8dSGreg Kroah-Hartman sel_buffer = bp; 280*60d4ae8dSGreg Kroah-Hartman 281*60d4ae8dSGreg Kroah-Hartman obp = bp; 282*60d4ae8dSGreg Kroah-Hartman for (i = sel_start; i <= sel_end; i += 2) { 283*60d4ae8dSGreg Kroah-Hartman c = sel_pos(i); 284*60d4ae8dSGreg Kroah-Hartman if (use_unicode) 285*60d4ae8dSGreg Kroah-Hartman bp += store_utf8(c, bp); 286*60d4ae8dSGreg Kroah-Hartman else 287*60d4ae8dSGreg Kroah-Hartman *bp++ = c; 288*60d4ae8dSGreg Kroah-Hartman if (!isspace(c)) 289*60d4ae8dSGreg Kroah-Hartman obp = bp; 290*60d4ae8dSGreg Kroah-Hartman if (! ((i + 2) % vc->vc_size_row)) { 291*60d4ae8dSGreg Kroah-Hartman /* strip trailing blanks from line and add newline, 292*60d4ae8dSGreg Kroah-Hartman unless non-space at end of line. */ 293*60d4ae8dSGreg Kroah-Hartman if (obp != bp) { 294*60d4ae8dSGreg Kroah-Hartman bp = obp; 295*60d4ae8dSGreg Kroah-Hartman *bp++ = '\r'; 296*60d4ae8dSGreg Kroah-Hartman } 297*60d4ae8dSGreg Kroah-Hartman obp = bp; 298*60d4ae8dSGreg Kroah-Hartman } 299*60d4ae8dSGreg Kroah-Hartman } 300*60d4ae8dSGreg Kroah-Hartman sel_buffer_lth = bp - sel_buffer; 301*60d4ae8dSGreg Kroah-Hartman return 0; 302*60d4ae8dSGreg Kroah-Hartman } 303*60d4ae8dSGreg Kroah-Hartman 304*60d4ae8dSGreg Kroah-Hartman /* Insert the contents of the selection buffer into the 305*60d4ae8dSGreg Kroah-Hartman * queue of the tty associated with the current console. 306*60d4ae8dSGreg Kroah-Hartman * Invoked by ioctl(). 307*60d4ae8dSGreg Kroah-Hartman */ 308*60d4ae8dSGreg Kroah-Hartman int paste_selection(struct tty_struct *tty) 309*60d4ae8dSGreg Kroah-Hartman { 310*60d4ae8dSGreg Kroah-Hartman struct vc_data *vc = tty->driver_data; 311*60d4ae8dSGreg Kroah-Hartman int pasted = 0; 312*60d4ae8dSGreg Kroah-Hartman unsigned int count; 313*60d4ae8dSGreg Kroah-Hartman struct tty_ldisc *ld; 314*60d4ae8dSGreg Kroah-Hartman DECLARE_WAITQUEUE(wait, current); 315*60d4ae8dSGreg Kroah-Hartman 316*60d4ae8dSGreg Kroah-Hartman /* always called with BTM from vt_ioctl */ 317*60d4ae8dSGreg Kroah-Hartman WARN_ON(!tty_locked()); 318*60d4ae8dSGreg Kroah-Hartman 319*60d4ae8dSGreg Kroah-Hartman acquire_console_sem(); 320*60d4ae8dSGreg Kroah-Hartman poke_blanked_console(); 321*60d4ae8dSGreg Kroah-Hartman release_console_sem(); 322*60d4ae8dSGreg Kroah-Hartman 323*60d4ae8dSGreg Kroah-Hartman ld = tty_ldisc_ref(tty); 324*60d4ae8dSGreg Kroah-Hartman if (!ld) { 325*60d4ae8dSGreg Kroah-Hartman tty_unlock(); 326*60d4ae8dSGreg Kroah-Hartman ld = tty_ldisc_ref_wait(tty); 327*60d4ae8dSGreg Kroah-Hartman tty_lock(); 328*60d4ae8dSGreg Kroah-Hartman } 329*60d4ae8dSGreg Kroah-Hartman 330*60d4ae8dSGreg Kroah-Hartman add_wait_queue(&vc->paste_wait, &wait); 331*60d4ae8dSGreg Kroah-Hartman while (sel_buffer && sel_buffer_lth > pasted) { 332*60d4ae8dSGreg Kroah-Hartman set_current_state(TASK_INTERRUPTIBLE); 333*60d4ae8dSGreg Kroah-Hartman if (test_bit(TTY_THROTTLED, &tty->flags)) { 334*60d4ae8dSGreg Kroah-Hartman schedule(); 335*60d4ae8dSGreg Kroah-Hartman continue; 336*60d4ae8dSGreg Kroah-Hartman } 337*60d4ae8dSGreg Kroah-Hartman count = sel_buffer_lth - pasted; 338*60d4ae8dSGreg Kroah-Hartman count = min(count, tty->receive_room); 339*60d4ae8dSGreg Kroah-Hartman tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, 340*60d4ae8dSGreg Kroah-Hartman NULL, count); 341*60d4ae8dSGreg Kroah-Hartman pasted += count; 342*60d4ae8dSGreg Kroah-Hartman } 343*60d4ae8dSGreg Kroah-Hartman remove_wait_queue(&vc->paste_wait, &wait); 344*60d4ae8dSGreg Kroah-Hartman __set_current_state(TASK_RUNNING); 345*60d4ae8dSGreg Kroah-Hartman 346*60d4ae8dSGreg Kroah-Hartman tty_ldisc_deref(ld); 347*60d4ae8dSGreg Kroah-Hartman return 0; 348*60d4ae8dSGreg Kroah-Hartman } 349