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 */ 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 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 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 57 int synth_buffer_empty(void) 58 { 59 return (buff_in == buff_out); 60 } 61 EXPORT_SYMBOL_GPL(synth_buffer_empty); 62 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 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 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 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 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