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