^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) #include <linux/slab.h> /* for kmalloc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/consolemap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/device.h> /* for dev_warn */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/selection.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/tty_flip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "speakup.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) unsigned short spk_xs, spk_ys, spk_xe, spk_ye; /* our region points */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct vc_data *spk_sel_cons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct speakup_selection_work {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct work_struct work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct tiocl_selection sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct tty_struct *tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static void __speakup_set_selection(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct speakup_selection_work *ssw =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) container_of(work, struct speakup_selection_work, work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct tty_struct *tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct tiocl_selection sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) sel = ssw->sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* this ensures we copy sel before releasing the lock below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) rmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /* release the lock by setting tty of the struct to NULL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) tty = xchg(&ssw->tty, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if (spk_sel_cons != vc_cons[fg_console].d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) spk_sel_cons = vc_cons[fg_console].d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) pr_warn("Selection: mark console not the same as cut\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) goto unref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) clear_selection();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) set_selection_kernel(&sel, tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) unref:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) tty_kref_put(tty);
^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) static struct speakup_selection_work speakup_sel_work = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .work = __WORK_INITIALIZER(speakup_sel_work.work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) __speakup_set_selection)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) int speakup_set_selection(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /* we get kref here first in order to avoid a subtle race when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * cancelling selection work. getting kref first establishes the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * invariant that if speakup_sel_work.tty is not NULL when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * speakup_cancel_selection() is called, it must be the case that a put
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * kref is pending.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) tty_kref_get(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (cmpxchg(&speakup_sel_work.tty, NULL, tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) tty_kref_put(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* now we have the 'lock' by setting tty member of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * speakup_selection_work. wmb() ensures that writes to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * speakup_sel_work don't happen before cmpxchg() above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) speakup_sel_work.sel.xs = spk_xs + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) speakup_sel_work.sel.ys = spk_ys + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) speakup_sel_work.sel.xe = spk_xe + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) speakup_sel_work.sel.ye = spk_ye + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) speakup_sel_work.sel.sel_mode = TIOCL_SELCHAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) schedule_work_on(WORK_CPU_UNBOUND, &speakup_sel_work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) void speakup_cancel_selection(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct tty_struct *tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) cancel_work_sync(&speakup_sel_work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* setting to null so that if work fails to run and we cancel it,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * we can run it again without getting EBUSY forever from there on.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * we need to use xchg here to avoid race with speakup_set_selection()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) tty = xchg(&speakup_sel_work.tty, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) tty_kref_put(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static void __speakup_paste_selection(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct speakup_selection_work *ssw =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) container_of(work, struct speakup_selection_work, work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct tty_struct *tty = xchg(&ssw->tty, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) paste_selection(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) tty_kref_put(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static struct speakup_selection_work speakup_paste_work = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) .work = __WORK_INITIALIZER(speakup_paste_work.work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) __speakup_paste_selection)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int speakup_paste_selection(struct tty_struct *tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) tty_kref_get(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (cmpxchg(&speakup_paste_work.tty, NULL, tty)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) tty_kref_put(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) schedule_work_on(WORK_CPU_UNBOUND, &speakup_paste_work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) void speakup_cancel_paste(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct tty_struct *tty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) cancel_work_sync(&speakup_paste_work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) tty = xchg(&speakup_paste_work.tty, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) tty_kref_put(tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }