^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/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include "speakup.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include "spk_priv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #define SYNTH_BUF_SIZE 8192 /* currently 8K bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) static u16 synth_buffer[SYNTH_BUF_SIZE]; /* guess what this is for! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) static u16 *buff_in = synth_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static u16 *buff_out = synth_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) static u16 *buffer_end = synth_buffer + SYNTH_BUF_SIZE - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) /* These try to throttle applications by stopping the TTYs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Note: we need to make sure that we will restart them eventually, which is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * usually not possible to do from the notifiers. TODO: it should be possible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * starting from linux 2.6.26.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * So we only stop when we know alive == 1 (else we discard the data anyway),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * and the alive synth will eventually call start_ttys from the thread context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) void speakup_start_ttys(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) for (i = 0; i < MAX_NR_CONSOLES; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) if (speakup_console[i] && speakup_console[i]->tty_stopped)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (vc_cons[i].d && vc_cons[i].d->port.tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) start_tty(vc_cons[i].d->port.tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) EXPORT_SYMBOL_GPL(speakup_start_ttys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static void speakup_stop_ttys(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) for (i = 0; i < MAX_NR_CONSOLES; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (vc_cons[i].d && vc_cons[i].d->port.tty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) stop_tty(vc_cons[i].d->port.tty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static int synth_buffer_free(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int chars_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (buff_in >= buff_out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) chars_free = SYNTH_BUF_SIZE - (buff_in - buff_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) chars_free = buff_out - buff_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return chars_free;
^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) int synth_buffer_empty(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return (buff_in == buff_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) EXPORT_SYMBOL_GPL(synth_buffer_empty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) void synth_buffer_add(u16 ch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (!synth->alive) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /* This makes sure that we won't stop TTYs if there is no synth
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * to restart them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (synth_buffer_free() <= 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) synth_start();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) speakup_stop_ttys();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (synth_buffer_free() <= 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) *buff_in++ = ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (buff_in > buffer_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) buff_in = synth_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* We have written something to the speech synthesis, so we are not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * paused any more.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) spk_paused = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u16 synth_buffer_getc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) u16 ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (buff_out == buff_in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) ch = *buff_out++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (buff_out > buffer_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) buff_out = synth_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) EXPORT_SYMBOL_GPL(synth_buffer_getc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) u16 synth_buffer_peek(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (buff_out == buff_in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return *buff_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) EXPORT_SYMBOL_GPL(synth_buffer_peek);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) void synth_buffer_skip_nonlatin1(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) while (buff_out != buff_in) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (*buff_out < 0x100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) buff_out++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (buff_out > buffer_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) buff_out = synth_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) EXPORT_SYMBOL_GPL(synth_buffer_skip_nonlatin1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) void synth_buffer_clear(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) buff_in = synth_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) buff_out = synth_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) EXPORT_SYMBOL_GPL(synth_buffer_clear);