18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/console.h>
38c2ecf20Sopenharmony_ci#include <linux/types.h>
48c2ecf20Sopenharmony_ci#include <linux/wait.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "speakup.h"
78c2ecf20Sopenharmony_ci#include "spk_priv.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define SYNTH_BUF_SIZE 8192	/* currently 8K bytes */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic u16 synth_buffer[SYNTH_BUF_SIZE];	/* guess what this is for! */
128c2ecf20Sopenharmony_cistatic u16 *buff_in = synth_buffer;
138c2ecf20Sopenharmony_cistatic u16 *buff_out = synth_buffer;
148c2ecf20Sopenharmony_cistatic u16 *buffer_end = synth_buffer + SYNTH_BUF_SIZE - 1;
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/* These try to throttle applications by stopping the TTYs
178c2ecf20Sopenharmony_ci * Note: we need to make sure that we will restart them eventually, which is
188c2ecf20Sopenharmony_ci * usually not possible to do from the notifiers. TODO: it should be possible
198c2ecf20Sopenharmony_ci * starting from linux 2.6.26.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * So we only stop when we know alive == 1 (else we discard the data anyway),
228c2ecf20Sopenharmony_ci * and the alive synth will eventually call start_ttys from the thread context.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_civoid speakup_start_ttys(void)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	int i;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_NR_CONSOLES; i++) {
298c2ecf20Sopenharmony_ci		if (speakup_console[i] && speakup_console[i]->tty_stopped)
308c2ecf20Sopenharmony_ci			continue;
318c2ecf20Sopenharmony_ci		if (vc_cons[i].d && vc_cons[i].d->port.tty)
328c2ecf20Sopenharmony_ci			start_tty(vc_cons[i].d->port.tty);
338c2ecf20Sopenharmony_ci	}
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(speakup_start_ttys);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic void speakup_stop_ttys(void)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	int i;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_NR_CONSOLES; i++)
428c2ecf20Sopenharmony_ci		if (vc_cons[i].d && vc_cons[i].d->port.tty)
438c2ecf20Sopenharmony_ci			stop_tty(vc_cons[i].d->port.tty);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic int synth_buffer_free(void)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	int chars_free;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	if (buff_in >= buff_out)
518c2ecf20Sopenharmony_ci		chars_free = SYNTH_BUF_SIZE - (buff_in - buff_out);
528c2ecf20Sopenharmony_ci	else
538c2ecf20Sopenharmony_ci		chars_free = buff_out - buff_in;
548c2ecf20Sopenharmony_ci	return chars_free;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ciint synth_buffer_empty(void)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	return (buff_in == buff_out);
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_empty);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_civoid synth_buffer_add(u16 ch)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	if (!synth->alive) {
668c2ecf20Sopenharmony_ci		/* This makes sure that we won't stop TTYs if there is no synth
678c2ecf20Sopenharmony_ci		 * to restart them
688c2ecf20Sopenharmony_ci		 */
698c2ecf20Sopenharmony_ci		return;
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci	if (synth_buffer_free() <= 100) {
728c2ecf20Sopenharmony_ci		synth_start();
738c2ecf20Sopenharmony_ci		speakup_stop_ttys();
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci	if (synth_buffer_free() <= 1)
768c2ecf20Sopenharmony_ci		return;
778c2ecf20Sopenharmony_ci	*buff_in++ = ch;
788c2ecf20Sopenharmony_ci	if (buff_in > buffer_end)
798c2ecf20Sopenharmony_ci		buff_in = synth_buffer;
808c2ecf20Sopenharmony_ci	/* We have written something to the speech synthesis, so we are not
818c2ecf20Sopenharmony_ci	 * paused any more.
828c2ecf20Sopenharmony_ci	 */
838c2ecf20Sopenharmony_ci	spk_paused = false;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ciu16 synth_buffer_getc(void)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	u16 ch;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (buff_out == buff_in)
918c2ecf20Sopenharmony_ci		return 0;
928c2ecf20Sopenharmony_ci	ch = *buff_out++;
938c2ecf20Sopenharmony_ci	if (buff_out > buffer_end)
948c2ecf20Sopenharmony_ci		buff_out = synth_buffer;
958c2ecf20Sopenharmony_ci	return ch;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_getc);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciu16 synth_buffer_peek(void)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	if (buff_out == buff_in)
1028c2ecf20Sopenharmony_ci		return 0;
1038c2ecf20Sopenharmony_ci	return *buff_out;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_peek);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_civoid synth_buffer_skip_nonlatin1(void)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	while (buff_out != buff_in) {
1108c2ecf20Sopenharmony_ci		if (*buff_out < 0x100)
1118c2ecf20Sopenharmony_ci			return;
1128c2ecf20Sopenharmony_ci		buff_out++;
1138c2ecf20Sopenharmony_ci		if (buff_out > buffer_end)
1148c2ecf20Sopenharmony_ci			buff_out = synth_buffer;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_skip_nonlatin1);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_civoid synth_buffer_clear(void)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	buff_in = synth_buffer;
1228c2ecf20Sopenharmony_ci	buff_out = synth_buffer;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_clear);
125