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