forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-02-19 1c055e55a242a33e574e48be530e06770a210dcd
kernel/drivers/tty/vt/selection.c
....@@ -2,7 +2,9 @@
22 /*
33 * This module exports the functions:
44 *
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 *)'
68 * 'void clear_selection(void)'
79 * 'int paste_selection(struct tty_struct *)'
810 * 'int sel_loadlut(char __user *)'
....@@ -33,18 +35,18 @@
3335 /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
3436 #define isspace(c) ((c) == ' ')
3537
36
-extern void poke_blanked_console(void);
37
-
3838 /* 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
+};
4850
4951 /* clear_selection, highlight and highlight_pointer can be called
5052 from interrupt (via scrollback/front) */
....@@ -52,22 +54,21 @@
5254 /* set reverse video on characters s-e of console with selection. */
5355 static inline void highlight(const int s, const int e)
5456 {
55
- invert_screen(sel_cons, s, e-s+2, 1);
57
+ invert_screen(vc_sel.cons, s, e-s+2, true);
5658 }
5759
5860 /* use complementary color to show the pointer */
5961 static inline void highlight_pointer(const int where)
6062 {
61
- complement_pos(sel_cons, where);
63
+ complement_pos(vc_sel.cons, where);
6264 }
6365
6466 static u32
65
-sel_pos(int n)
67
+sel_pos(int n, bool unicode)
6668 {
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);
7172 }
7273
7374 /**
....@@ -79,15 +80,16 @@
7980 void clear_selection(void)
8081 {
8182 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;
8586 }
8687 }
88
+EXPORT_SYMBOL_GPL(clear_selection);
8789
8890 bool vc_is_sel(struct vc_data *vc)
8991 {
90
- return vc == sel_cons;
92
+ return vc == vc_sel.cons;
9193 }
9294
9395 /*
....@@ -163,7 +165,7 @@
163165 }
164166
165167 /**
166
- * set_selection - set the current selection.
168
+ * set_selection_user - set the current selection.
167169 * @sel: user selection info
168170 * @tty: the console tty
169171 *
....@@ -172,153 +174,44 @@
172174 * The entire selection process is managed under the console_lock. It's
173175 * a lot under the lock but its hardly a performance path
174176 */
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)
176179 {
177
- struct vc_data *vc = vc_cons[fg_console].d;
178
- int new_sel_start, new_sel_end, spc;
179180 struct tiocl_selection v;
180
- char *bp, *obp;
181
- int i, ps, pe, multiplier;
182
- u32 c;
183
- int mode, ret = 0;
184181
185
- poke_blanked_console();
186182 if (copy_from_user(&v, sel, sizeof(*sel)))
187183 return -EFAULT;
188184
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
+}
195187
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;
299192
300193 /* 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);
304197 if (!bp) {
305198 printk(KERN_WARNING "selection: kmalloc() failed\n");
306199 clear_selection();
307200 return -ENOMEM;
308201 }
309
- kfree(sel_buffer);
310
- sel_buffer = bp;
202
+ kfree(vc_sel.buffer);
203
+ vc_sel.buffer = bp;
311204
312205 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)
316209 bp += store_utf8(c, bp);
317210 else
318211 *bp++ = c;
319212 if (!isspace(c))
320213 obp = bp;
321
- if (! ((i + 2) % vc->vc_size_row)) {
214
+ if (!((i + 2) % vc->vc_size_row)) {
322215 /* strip trailing blanks from line and add newline,
323216 unless non-space at end of line. */
324217 if (obp != bp) {
....@@ -328,23 +221,148 @@
328221 obp = bp;
329222 }
330223 }
331
- sel_buffer_lth = bp - sel_buffer;
224
+ vc_sel.buf_len = bp - vc_sel.buffer;
332225
333
- return ret;
226
+ return 0;
334227 }
335228
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)
337354 {
338355 int ret;
339356
340
- mutex_lock(&sel_lock);
357
+ mutex_lock(&vc_sel.lock);
341358 console_lock();
342
- ret = __set_selection(v, tty);
359
+ ret = vc_selection(vc_cons[fg_console].d, v, tty);
343360 console_unlock();
344
- mutex_unlock(&sel_lock);
361
+ mutex_unlock(&vc_sel.lock);
345362
346363 return ret;
347364 }
365
+EXPORT_SYMBOL_GPL(set_selection_kernel);
348366
349367 /* Insert the contents of the selection buffer into the
350368 * queue of the tty associated with the current console.
....@@ -372,26 +390,26 @@
372390 tty_buffer_lock_exclusive(&vc->port);
373391
374392 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) {
377395 set_current_state(TASK_INTERRUPTIBLE);
378396 if (signal_pending(current)) {
379397 ret = -EINTR;
380398 break;
381399 }
382400 if (tty_throttled(tty)) {
383
- mutex_unlock(&sel_lock);
401
+ mutex_unlock(&vc_sel.lock);
384402 schedule();
385
- mutex_lock(&sel_lock);
403
+ mutex_lock(&vc_sel.lock);
386404 continue;
387405 }
388406 __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,
391409 count);
392410 pasted += count;
393411 }
394
- mutex_unlock(&sel_lock);
412
+ mutex_unlock(&vc_sel.lock);
395413 remove_wait_queue(&vc->paste_wait, &wait);
396414 __set_current_state(TASK_RUNNING);
397415
....@@ -399,3 +417,4 @@
399417 tty_ldisc_deref(ld);
400418 return ret;
401419 }
420
+EXPORT_SYMBOL_GPL(paste_selection);