.. | .. |
---|
2 | 2 | /* |
---|
3 | 3 | * This module exports the functions: |
---|
4 | 4 | * |
---|
5 | | - * 'int set_selection(struct tiocl_selection __user *, struct tty_struct *)' |
---|
| 5 | + * 'int set_selection_user(struct tiocl_selection __user *, |
---|
| 6 | + * struct tty_struct *)' |
---|
| 7 | + * 'int set_selection_kernel(struct tiocl_selection *, struct tty_struct *)' |
---|
6 | 8 | * 'void clear_selection(void)' |
---|
7 | 9 | * 'int paste_selection(struct tty_struct *)' |
---|
8 | 10 | * 'int sel_loadlut(char __user *)' |
---|
.. | .. |
---|
33 | 35 | /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ |
---|
34 | 36 | #define isspace(c) ((c) == ' ') |
---|
35 | 37 | |
---|
36 | | -extern void poke_blanked_console(void); |
---|
37 | | - |
---|
38 | 38 | /* FIXME: all this needs locking */ |
---|
39 | | -/* Variables for selection control. */ |
---|
40 | | -/* Use a dynamic buffer, instead of static (Dec 1994) */ |
---|
41 | | -struct vc_data *sel_cons; /* must not be deallocated */ |
---|
42 | | -static int use_unicode; |
---|
43 | | -static volatile int sel_start = -1; /* cleared by clear_selection */ |
---|
44 | | -static int sel_end; |
---|
45 | | -static int sel_buffer_lth; |
---|
46 | | -static char *sel_buffer; |
---|
47 | | -static DEFINE_MUTEX(sel_lock); |
---|
| 39 | +static struct vc_selection { |
---|
| 40 | + struct mutex lock; |
---|
| 41 | + struct vc_data *cons; /* must not be deallocated */ |
---|
| 42 | + char *buffer; |
---|
| 43 | + unsigned int buf_len; |
---|
| 44 | + volatile int start; /* cleared by clear_selection */ |
---|
| 45 | + int end; |
---|
| 46 | +} vc_sel = { |
---|
| 47 | + .lock = __MUTEX_INITIALIZER(vc_sel.lock), |
---|
| 48 | + .start = -1, |
---|
| 49 | +}; |
---|
48 | 50 | |
---|
49 | 51 | /* clear_selection, highlight and highlight_pointer can be called |
---|
50 | 52 | from interrupt (via scrollback/front) */ |
---|
.. | .. |
---|
52 | 54 | /* set reverse video on characters s-e of console with selection. */ |
---|
53 | 55 | static inline void highlight(const int s, const int e) |
---|
54 | 56 | { |
---|
55 | | - invert_screen(sel_cons, s, e-s+2, 1); |
---|
| 57 | + invert_screen(vc_sel.cons, s, e-s+2, true); |
---|
56 | 58 | } |
---|
57 | 59 | |
---|
58 | 60 | /* use complementary color to show the pointer */ |
---|
59 | 61 | static inline void highlight_pointer(const int where) |
---|
60 | 62 | { |
---|
61 | | - complement_pos(sel_cons, where); |
---|
| 63 | + complement_pos(vc_sel.cons, where); |
---|
62 | 64 | } |
---|
63 | 65 | |
---|
64 | 66 | static u32 |
---|
65 | | -sel_pos(int n) |
---|
| 67 | +sel_pos(int n, bool unicode) |
---|
66 | 68 | { |
---|
67 | | - if (use_unicode) |
---|
68 | | - return screen_glyph_unicode(sel_cons, n / 2); |
---|
69 | | - return inverse_translate(sel_cons, screen_glyph(sel_cons, n), |
---|
70 | | - 0); |
---|
| 69 | + if (unicode) |
---|
| 70 | + return screen_glyph_unicode(vc_sel.cons, n / 2); |
---|
| 71 | + return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), 0); |
---|
71 | 72 | } |
---|
72 | 73 | |
---|
73 | 74 | /** |
---|
.. | .. |
---|
79 | 80 | void clear_selection(void) |
---|
80 | 81 | { |
---|
81 | 82 | highlight_pointer(-1); /* hide the pointer */ |
---|
82 | | - if (sel_start != -1) { |
---|
83 | | - highlight(sel_start, sel_end); |
---|
84 | | - sel_start = -1; |
---|
| 83 | + if (vc_sel.start != -1) { |
---|
| 84 | + highlight(vc_sel.start, vc_sel.end); |
---|
| 85 | + vc_sel.start = -1; |
---|
85 | 86 | } |
---|
86 | 87 | } |
---|
| 88 | +EXPORT_SYMBOL_GPL(clear_selection); |
---|
87 | 89 | |
---|
88 | 90 | bool vc_is_sel(struct vc_data *vc) |
---|
89 | 91 | { |
---|
90 | | - return vc == sel_cons; |
---|
| 92 | + return vc == vc_sel.cons; |
---|
91 | 93 | } |
---|
92 | 94 | |
---|
93 | 95 | /* |
---|
.. | .. |
---|
163 | 165 | } |
---|
164 | 166 | |
---|
165 | 167 | /** |
---|
166 | | - * set_selection - set the current selection. |
---|
| 168 | + * set_selection_user - set the current selection. |
---|
167 | 169 | * @sel: user selection info |
---|
168 | 170 | * @tty: the console tty |
---|
169 | 171 | * |
---|
.. | .. |
---|
172 | 174 | * The entire selection process is managed under the console_lock. It's |
---|
173 | 175 | * a lot under the lock but its hardly a performance path |
---|
174 | 176 | */ |
---|
175 | | -static int __set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) |
---|
| 177 | +int set_selection_user(const struct tiocl_selection __user *sel, |
---|
| 178 | + struct tty_struct *tty) |
---|
176 | 179 | { |
---|
177 | | - struct vc_data *vc = vc_cons[fg_console].d; |
---|
178 | | - int new_sel_start, new_sel_end, spc; |
---|
179 | 180 | struct tiocl_selection v; |
---|
180 | | - char *bp, *obp; |
---|
181 | | - int i, ps, pe, multiplier; |
---|
182 | | - u32 c; |
---|
183 | | - int mode, ret = 0; |
---|
184 | 181 | |
---|
185 | | - poke_blanked_console(); |
---|
186 | 182 | if (copy_from_user(&v, sel, sizeof(*sel))) |
---|
187 | 183 | return -EFAULT; |
---|
188 | 184 | |
---|
189 | | - v.xs = min_t(u16, v.xs - 1, vc->vc_cols - 1); |
---|
190 | | - v.ys = min_t(u16, v.ys - 1, vc->vc_rows - 1); |
---|
191 | | - v.xe = min_t(u16, v.xe - 1, vc->vc_cols - 1); |
---|
192 | | - v.ye = min_t(u16, v.ye - 1, vc->vc_rows - 1); |
---|
193 | | - ps = v.ys * vc->vc_size_row + (v.xs << 1); |
---|
194 | | - pe = v.ye * vc->vc_size_row + (v.xe << 1); |
---|
| 185 | + return set_selection_kernel(&v, tty); |
---|
| 186 | +} |
---|
195 | 187 | |
---|
196 | | - if (v.sel_mode == TIOCL_SELCLEAR) { |
---|
197 | | - /* useful for screendump without selection highlights */ |
---|
198 | | - clear_selection(); |
---|
199 | | - return 0; |
---|
200 | | - } |
---|
201 | | - |
---|
202 | | - if (mouse_reporting() && (v.sel_mode & TIOCL_SELMOUSEREPORT)) { |
---|
203 | | - mouse_report(tty, v.sel_mode & TIOCL_SELBUTTONMASK, v.xs, v.ys); |
---|
204 | | - return 0; |
---|
205 | | - } |
---|
206 | | - |
---|
207 | | - if (ps > pe) /* make sel_start <= sel_end */ |
---|
208 | | - swap(ps, pe); |
---|
209 | | - |
---|
210 | | - if (sel_cons != vc_cons[fg_console].d) { |
---|
211 | | - clear_selection(); |
---|
212 | | - sel_cons = vc_cons[fg_console].d; |
---|
213 | | - } |
---|
214 | | - mode = vt_do_kdgkbmode(fg_console); |
---|
215 | | - if (mode == K_UNICODE) |
---|
216 | | - use_unicode = 1; |
---|
217 | | - else |
---|
218 | | - use_unicode = 0; |
---|
219 | | - |
---|
220 | | - switch (v.sel_mode) |
---|
221 | | - { |
---|
222 | | - case TIOCL_SELCHAR: /* character-by-character selection */ |
---|
223 | | - new_sel_start = ps; |
---|
224 | | - new_sel_end = pe; |
---|
225 | | - break; |
---|
226 | | - case TIOCL_SELWORD: /* word-by-word selection */ |
---|
227 | | - spc = isspace(sel_pos(ps)); |
---|
228 | | - for (new_sel_start = ps; ; ps -= 2) |
---|
229 | | - { |
---|
230 | | - if ((spc && !isspace(sel_pos(ps))) || |
---|
231 | | - (!spc && !inword(sel_pos(ps)))) |
---|
232 | | - break; |
---|
233 | | - new_sel_start = ps; |
---|
234 | | - if (!(ps % vc->vc_size_row)) |
---|
235 | | - break; |
---|
236 | | - } |
---|
237 | | - spc = isspace(sel_pos(pe)); |
---|
238 | | - for (new_sel_end = pe; ; pe += 2) |
---|
239 | | - { |
---|
240 | | - if ((spc && !isspace(sel_pos(pe))) || |
---|
241 | | - (!spc && !inword(sel_pos(pe)))) |
---|
242 | | - break; |
---|
243 | | - new_sel_end = pe; |
---|
244 | | - if (!((pe + 2) % vc->vc_size_row)) |
---|
245 | | - break; |
---|
246 | | - } |
---|
247 | | - break; |
---|
248 | | - case TIOCL_SELLINE: /* line-by-line selection */ |
---|
249 | | - new_sel_start = ps - ps % vc->vc_size_row; |
---|
250 | | - new_sel_end = pe + vc->vc_size_row |
---|
251 | | - - pe % vc->vc_size_row - 2; |
---|
252 | | - break; |
---|
253 | | - case TIOCL_SELPOINTER: |
---|
254 | | - highlight_pointer(pe); |
---|
255 | | - return 0; |
---|
256 | | - default: |
---|
257 | | - return -EINVAL; |
---|
258 | | - } |
---|
259 | | - |
---|
260 | | - /* remove the pointer */ |
---|
261 | | - highlight_pointer(-1); |
---|
262 | | - |
---|
263 | | - /* select to end of line if on trailing space */ |
---|
264 | | - if (new_sel_end > new_sel_start && |
---|
265 | | - !atedge(new_sel_end, vc->vc_size_row) && |
---|
266 | | - isspace(sel_pos(new_sel_end))) { |
---|
267 | | - for (pe = new_sel_end + 2; ; pe += 2) |
---|
268 | | - if (!isspace(sel_pos(pe)) || |
---|
269 | | - atedge(pe, vc->vc_size_row)) |
---|
270 | | - break; |
---|
271 | | - if (isspace(sel_pos(pe))) |
---|
272 | | - new_sel_end = pe; |
---|
273 | | - } |
---|
274 | | - if (sel_start == -1) /* no current selection */ |
---|
275 | | - highlight(new_sel_start, new_sel_end); |
---|
276 | | - else if (new_sel_start == sel_start) |
---|
277 | | - { |
---|
278 | | - if (new_sel_end == sel_end) /* no action required */ |
---|
279 | | - return 0; |
---|
280 | | - else if (new_sel_end > sel_end) /* extend to right */ |
---|
281 | | - highlight(sel_end + 2, new_sel_end); |
---|
282 | | - else /* contract from right */ |
---|
283 | | - highlight(new_sel_end + 2, sel_end); |
---|
284 | | - } |
---|
285 | | - else if (new_sel_end == sel_end) |
---|
286 | | - { |
---|
287 | | - if (new_sel_start < sel_start) /* extend to left */ |
---|
288 | | - highlight(new_sel_start, sel_start - 2); |
---|
289 | | - else /* contract from left */ |
---|
290 | | - highlight(sel_start, new_sel_start - 2); |
---|
291 | | - } |
---|
292 | | - else /* some other case; start selection from scratch */ |
---|
293 | | - { |
---|
294 | | - clear_selection(); |
---|
295 | | - highlight(new_sel_start, new_sel_end); |
---|
296 | | - } |
---|
297 | | - sel_start = new_sel_start; |
---|
298 | | - sel_end = new_sel_end; |
---|
| 188 | +static int vc_selection_store_chars(struct vc_data *vc, bool unicode) |
---|
| 189 | +{ |
---|
| 190 | + char *bp, *obp; |
---|
| 191 | + unsigned int i; |
---|
299 | 192 | |
---|
300 | 193 | /* Allocate a new buffer before freeing the old one ... */ |
---|
301 | | - multiplier = use_unicode ? 4 : 1; /* chars can take up to 4 bytes */ |
---|
302 | | - bp = kmalloc_array((sel_end - sel_start) / 2 + 1, multiplier, |
---|
303 | | - GFP_KERNEL); |
---|
| 194 | + /* chars can take up to 4 bytes with unicode */ |
---|
| 195 | + bp = kmalloc_array((vc_sel.end - vc_sel.start) / 2 + 1, unicode ? 4 : 1, |
---|
| 196 | + GFP_KERNEL | __GFP_NOWARN); |
---|
304 | 197 | if (!bp) { |
---|
305 | 198 | printk(KERN_WARNING "selection: kmalloc() failed\n"); |
---|
306 | 199 | clear_selection(); |
---|
307 | 200 | return -ENOMEM; |
---|
308 | 201 | } |
---|
309 | | - kfree(sel_buffer); |
---|
310 | | - sel_buffer = bp; |
---|
| 202 | + kfree(vc_sel.buffer); |
---|
| 203 | + vc_sel.buffer = bp; |
---|
311 | 204 | |
---|
312 | 205 | obp = bp; |
---|
313 | | - for (i = sel_start; i <= sel_end; i += 2) { |
---|
314 | | - c = sel_pos(i); |
---|
315 | | - if (use_unicode) |
---|
| 206 | + for (i = vc_sel.start; i <= vc_sel.end; i += 2) { |
---|
| 207 | + u32 c = sel_pos(i, unicode); |
---|
| 208 | + if (unicode) |
---|
316 | 209 | bp += store_utf8(c, bp); |
---|
317 | 210 | else |
---|
318 | 211 | *bp++ = c; |
---|
319 | 212 | if (!isspace(c)) |
---|
320 | 213 | obp = bp; |
---|
321 | | - if (! ((i + 2) % vc->vc_size_row)) { |
---|
| 214 | + if (!((i + 2) % vc->vc_size_row)) { |
---|
322 | 215 | /* strip trailing blanks from line and add newline, |
---|
323 | 216 | unless non-space at end of line. */ |
---|
324 | 217 | if (obp != bp) { |
---|
.. | .. |
---|
328 | 221 | obp = bp; |
---|
329 | 222 | } |
---|
330 | 223 | } |
---|
331 | | - sel_buffer_lth = bp - sel_buffer; |
---|
| 224 | + vc_sel.buf_len = bp - vc_sel.buffer; |
---|
332 | 225 | |
---|
333 | | - return ret; |
---|
| 226 | + return 0; |
---|
334 | 227 | } |
---|
335 | 228 | |
---|
336 | | -int set_selection(const struct tiocl_selection __user *v, struct tty_struct *tty) |
---|
| 229 | +static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps, |
---|
| 230 | + int pe) |
---|
| 231 | +{ |
---|
| 232 | + int new_sel_start, new_sel_end, spc; |
---|
| 233 | + bool unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE; |
---|
| 234 | + |
---|
| 235 | + switch (mode) { |
---|
| 236 | + case TIOCL_SELCHAR: /* character-by-character selection */ |
---|
| 237 | + new_sel_start = ps; |
---|
| 238 | + new_sel_end = pe; |
---|
| 239 | + break; |
---|
| 240 | + case TIOCL_SELWORD: /* word-by-word selection */ |
---|
| 241 | + spc = isspace(sel_pos(ps, unicode)); |
---|
| 242 | + for (new_sel_start = ps; ; ps -= 2) { |
---|
| 243 | + if ((spc && !isspace(sel_pos(ps, unicode))) || |
---|
| 244 | + (!spc && !inword(sel_pos(ps, unicode)))) |
---|
| 245 | + break; |
---|
| 246 | + new_sel_start = ps; |
---|
| 247 | + if (!(ps % vc->vc_size_row)) |
---|
| 248 | + break; |
---|
| 249 | + } |
---|
| 250 | + |
---|
| 251 | + spc = isspace(sel_pos(pe, unicode)); |
---|
| 252 | + for (new_sel_end = pe; ; pe += 2) { |
---|
| 253 | + if ((spc && !isspace(sel_pos(pe, unicode))) || |
---|
| 254 | + (!spc && !inword(sel_pos(pe, unicode)))) |
---|
| 255 | + break; |
---|
| 256 | + new_sel_end = pe; |
---|
| 257 | + if (!((pe + 2) % vc->vc_size_row)) |
---|
| 258 | + break; |
---|
| 259 | + } |
---|
| 260 | + break; |
---|
| 261 | + case TIOCL_SELLINE: /* line-by-line selection */ |
---|
| 262 | + new_sel_start = rounddown(ps, vc->vc_size_row); |
---|
| 263 | + new_sel_end = rounddown(pe, vc->vc_size_row) + |
---|
| 264 | + vc->vc_size_row - 2; |
---|
| 265 | + break; |
---|
| 266 | + case TIOCL_SELPOINTER: |
---|
| 267 | + highlight_pointer(pe); |
---|
| 268 | + return 0; |
---|
| 269 | + default: |
---|
| 270 | + return -EINVAL; |
---|
| 271 | + } |
---|
| 272 | + |
---|
| 273 | + /* remove the pointer */ |
---|
| 274 | + highlight_pointer(-1); |
---|
| 275 | + |
---|
| 276 | + /* select to end of line if on trailing space */ |
---|
| 277 | + if (new_sel_end > new_sel_start && |
---|
| 278 | + !atedge(new_sel_end, vc->vc_size_row) && |
---|
| 279 | + isspace(sel_pos(new_sel_end, unicode))) { |
---|
| 280 | + for (pe = new_sel_end + 2; ; pe += 2) |
---|
| 281 | + if (!isspace(sel_pos(pe, unicode)) || |
---|
| 282 | + atedge(pe, vc->vc_size_row)) |
---|
| 283 | + break; |
---|
| 284 | + if (isspace(sel_pos(pe, unicode))) |
---|
| 285 | + new_sel_end = pe; |
---|
| 286 | + } |
---|
| 287 | + if (vc_sel.start == -1) /* no current selection */ |
---|
| 288 | + highlight(new_sel_start, new_sel_end); |
---|
| 289 | + else if (new_sel_start == vc_sel.start) |
---|
| 290 | + { |
---|
| 291 | + if (new_sel_end == vc_sel.end) /* no action required */ |
---|
| 292 | + return 0; |
---|
| 293 | + else if (new_sel_end > vc_sel.end) /* extend to right */ |
---|
| 294 | + highlight(vc_sel.end + 2, new_sel_end); |
---|
| 295 | + else /* contract from right */ |
---|
| 296 | + highlight(new_sel_end + 2, vc_sel.end); |
---|
| 297 | + } |
---|
| 298 | + else if (new_sel_end == vc_sel.end) |
---|
| 299 | + { |
---|
| 300 | + if (new_sel_start < vc_sel.start) /* extend to left */ |
---|
| 301 | + highlight(new_sel_start, vc_sel.start - 2); |
---|
| 302 | + else /* contract from left */ |
---|
| 303 | + highlight(vc_sel.start, new_sel_start - 2); |
---|
| 304 | + } |
---|
| 305 | + else /* some other case; start selection from scratch */ |
---|
| 306 | + { |
---|
| 307 | + clear_selection(); |
---|
| 308 | + highlight(new_sel_start, new_sel_end); |
---|
| 309 | + } |
---|
| 310 | + vc_sel.start = new_sel_start; |
---|
| 311 | + vc_sel.end = new_sel_end; |
---|
| 312 | + |
---|
| 313 | + return vc_selection_store_chars(vc, unicode); |
---|
| 314 | +} |
---|
| 315 | + |
---|
| 316 | +static int vc_selection(struct vc_data *vc, struct tiocl_selection *v, |
---|
| 317 | + struct tty_struct *tty) |
---|
| 318 | +{ |
---|
| 319 | + int ps, pe; |
---|
| 320 | + |
---|
| 321 | + poke_blanked_console(); |
---|
| 322 | + |
---|
| 323 | + if (v->sel_mode == TIOCL_SELCLEAR) { |
---|
| 324 | + /* useful for screendump without selection highlights */ |
---|
| 325 | + clear_selection(); |
---|
| 326 | + return 0; |
---|
| 327 | + } |
---|
| 328 | + |
---|
| 329 | + v->xs = min_t(u16, v->xs - 1, vc->vc_cols - 1); |
---|
| 330 | + v->ys = min_t(u16, v->ys - 1, vc->vc_rows - 1); |
---|
| 331 | + v->xe = min_t(u16, v->xe - 1, vc->vc_cols - 1); |
---|
| 332 | + v->ye = min_t(u16, v->ye - 1, vc->vc_rows - 1); |
---|
| 333 | + |
---|
| 334 | + if (mouse_reporting() && (v->sel_mode & TIOCL_SELMOUSEREPORT)) { |
---|
| 335 | + mouse_report(tty, v->sel_mode & TIOCL_SELBUTTONMASK, v->xs, |
---|
| 336 | + v->ys); |
---|
| 337 | + return 0; |
---|
| 338 | + } |
---|
| 339 | + |
---|
| 340 | + ps = v->ys * vc->vc_size_row + (v->xs << 1); |
---|
| 341 | + pe = v->ye * vc->vc_size_row + (v->xe << 1); |
---|
| 342 | + if (ps > pe) /* make vc_sel.start <= vc_sel.end */ |
---|
| 343 | + swap(ps, pe); |
---|
| 344 | + |
---|
| 345 | + if (vc_sel.cons != vc) { |
---|
| 346 | + clear_selection(); |
---|
| 347 | + vc_sel.cons = vc; |
---|
| 348 | + } |
---|
| 349 | + |
---|
| 350 | + return vc_do_selection(vc, v->sel_mode, ps, pe); |
---|
| 351 | +} |
---|
| 352 | + |
---|
| 353 | +int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) |
---|
337 | 354 | { |
---|
338 | 355 | int ret; |
---|
339 | 356 | |
---|
340 | | - mutex_lock(&sel_lock); |
---|
| 357 | + mutex_lock(&vc_sel.lock); |
---|
341 | 358 | console_lock(); |
---|
342 | | - ret = __set_selection(v, tty); |
---|
| 359 | + ret = vc_selection(vc_cons[fg_console].d, v, tty); |
---|
343 | 360 | console_unlock(); |
---|
344 | | - mutex_unlock(&sel_lock); |
---|
| 361 | + mutex_unlock(&vc_sel.lock); |
---|
345 | 362 | |
---|
346 | 363 | return ret; |
---|
347 | 364 | } |
---|
| 365 | +EXPORT_SYMBOL_GPL(set_selection_kernel); |
---|
348 | 366 | |
---|
349 | 367 | /* Insert the contents of the selection buffer into the |
---|
350 | 368 | * queue of the tty associated with the current console. |
---|
.. | .. |
---|
372 | 390 | tty_buffer_lock_exclusive(&vc->port); |
---|
373 | 391 | |
---|
374 | 392 | add_wait_queue(&vc->paste_wait, &wait); |
---|
375 | | - mutex_lock(&sel_lock); |
---|
376 | | - while (sel_buffer && sel_buffer_lth > pasted) { |
---|
| 393 | + mutex_lock(&vc_sel.lock); |
---|
| 394 | + while (vc_sel.buffer && vc_sel.buf_len > pasted) { |
---|
377 | 395 | set_current_state(TASK_INTERRUPTIBLE); |
---|
378 | 396 | if (signal_pending(current)) { |
---|
379 | 397 | ret = -EINTR; |
---|
380 | 398 | break; |
---|
381 | 399 | } |
---|
382 | 400 | if (tty_throttled(tty)) { |
---|
383 | | - mutex_unlock(&sel_lock); |
---|
| 401 | + mutex_unlock(&vc_sel.lock); |
---|
384 | 402 | schedule(); |
---|
385 | | - mutex_lock(&sel_lock); |
---|
| 403 | + mutex_lock(&vc_sel.lock); |
---|
386 | 404 | continue; |
---|
387 | 405 | } |
---|
388 | 406 | __set_current_state(TASK_RUNNING); |
---|
389 | | - count = sel_buffer_lth - pasted; |
---|
390 | | - count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL, |
---|
| 407 | + count = vc_sel.buf_len - pasted; |
---|
| 408 | + count = tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL, |
---|
391 | 409 | count); |
---|
392 | 410 | pasted += count; |
---|
393 | 411 | } |
---|
394 | | - mutex_unlock(&sel_lock); |
---|
| 412 | + mutex_unlock(&vc_sel.lock); |
---|
395 | 413 | remove_wait_queue(&vc->paste_wait, &wait); |
---|
396 | 414 | __set_current_state(TASK_RUNNING); |
---|
397 | 415 | |
---|
.. | .. |
---|
399 | 417 | tty_ldisc_deref(ld); |
---|
400 | 418 | return ret; |
---|
401 | 419 | } |
---|
| 420 | +EXPORT_SYMBOL_GPL(paste_selection); |
---|