162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/console.h>
362306a36Sopenharmony_ci#include <linux/types.h>
462306a36Sopenharmony_ci#include <linux/wait.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "speakup.h"
762306a36Sopenharmony_ci#include "spk_priv.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define SYNTH_BUF_SIZE 8192	/* currently 8K bytes */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic u16 synth_buffer[SYNTH_BUF_SIZE];	/* guess what this is for! */
1262306a36Sopenharmony_cistatic u16 *buff_in = synth_buffer;
1362306a36Sopenharmony_cistatic u16 *buff_out = synth_buffer;
1462306a36Sopenharmony_cistatic u16 *buffer_end = synth_buffer + SYNTH_BUF_SIZE - 1;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/* These try to throttle applications by stopping the TTYs
1762306a36Sopenharmony_ci * Note: we need to make sure that we will restart them eventually, which is
1862306a36Sopenharmony_ci * usually not possible to do from the notifiers. TODO: it should be possible
1962306a36Sopenharmony_ci * starting from linux 2.6.26.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * So we only stop when we know alive == 1 (else we discard the data anyway),
2262306a36Sopenharmony_ci * and the alive synth will eventually call start_ttys from the thread context.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_civoid speakup_start_ttys(void)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	int i;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	for (i = 0; i < MAX_NR_CONSOLES; i++) {
2962306a36Sopenharmony_ci		if (speakup_console[i] && speakup_console[i]->tty_stopped)
3062306a36Sopenharmony_ci			continue;
3162306a36Sopenharmony_ci		if (vc_cons[i].d && vc_cons[i].d->port.tty)
3262306a36Sopenharmony_ci			start_tty(vc_cons[i].d->port.tty);
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(speakup_start_ttys);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic void speakup_stop_ttys(void)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	int i;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	for (i = 0; i < MAX_NR_CONSOLES; i++)
4262306a36Sopenharmony_ci		if (vc_cons[i].d && vc_cons[i].d->port.tty)
4362306a36Sopenharmony_ci			stop_tty(vc_cons[i].d->port.tty);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int synth_buffer_free(void)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	int chars_free;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (buff_in >= buff_out)
5162306a36Sopenharmony_ci		chars_free = SYNTH_BUF_SIZE - (buff_in - buff_out);
5262306a36Sopenharmony_ci	else
5362306a36Sopenharmony_ci		chars_free = buff_out - buff_in;
5462306a36Sopenharmony_ci	return chars_free;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ciint synth_buffer_empty(void)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	return (buff_in == buff_out);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_empty);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_civoid synth_buffer_add(u16 ch)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	if (!synth->alive) {
6662306a36Sopenharmony_ci		/* This makes sure that we won't stop TTYs if there is no synth
6762306a36Sopenharmony_ci		 * to restart them
6862306a36Sopenharmony_ci		 */
6962306a36Sopenharmony_ci		return;
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci	if (synth_buffer_free() <= 100) {
7262306a36Sopenharmony_ci		synth_start();
7362306a36Sopenharmony_ci		speakup_stop_ttys();
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci	if (synth_buffer_free() <= 1)
7662306a36Sopenharmony_ci		return;
7762306a36Sopenharmony_ci	*buff_in++ = ch;
7862306a36Sopenharmony_ci	if (buff_in > buffer_end)
7962306a36Sopenharmony_ci		buff_in = synth_buffer;
8062306a36Sopenharmony_ci	/* We have written something to the speech synthesis, so we are not
8162306a36Sopenharmony_ci	 * paused any more.
8262306a36Sopenharmony_ci	 */
8362306a36Sopenharmony_ci	spk_paused = false;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciu16 synth_buffer_getc(void)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	u16 ch;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (buff_out == buff_in)
9162306a36Sopenharmony_ci		return 0;
9262306a36Sopenharmony_ci	ch = *buff_out++;
9362306a36Sopenharmony_ci	if (buff_out > buffer_end)
9462306a36Sopenharmony_ci		buff_out = synth_buffer;
9562306a36Sopenharmony_ci	return ch;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_getc);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciu16 synth_buffer_peek(void)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	if (buff_out == buff_in)
10262306a36Sopenharmony_ci		return 0;
10362306a36Sopenharmony_ci	return *buff_out;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_peek);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_civoid synth_buffer_skip_nonlatin1(void)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	while (buff_out != buff_in) {
11062306a36Sopenharmony_ci		if (*buff_out < 0x100)
11162306a36Sopenharmony_ci			return;
11262306a36Sopenharmony_ci		buff_out++;
11362306a36Sopenharmony_ci		if (buff_out > buffer_end)
11462306a36Sopenharmony_ci			buff_out = synth_buffer;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_skip_nonlatin1);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_civoid synth_buffer_clear(void)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	buff_in = synth_buffer;
12262306a36Sopenharmony_ci	buff_out = synth_buffer;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_clear);
125