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