18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/console.h> 38c2ecf20Sopenharmony_ci#include <linux/types.h> 48c2ecf20Sopenharmony_ci#include <linux/wait.h> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "speakup.h" 78c2ecf20Sopenharmony_ci#include "spk_priv.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define SYNTH_BUF_SIZE 8192 /* currently 8K bytes */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic u16 synth_buffer[SYNTH_BUF_SIZE]; /* guess what this is for! */ 128c2ecf20Sopenharmony_cistatic u16 *buff_in = synth_buffer; 138c2ecf20Sopenharmony_cistatic u16 *buff_out = synth_buffer; 148c2ecf20Sopenharmony_cistatic u16 *buffer_end = synth_buffer + SYNTH_BUF_SIZE - 1; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* These try to throttle applications by stopping the TTYs 178c2ecf20Sopenharmony_ci * Note: we need to make sure that we will restart them eventually, which is 188c2ecf20Sopenharmony_ci * usually not possible to do from the notifiers. TODO: it should be possible 198c2ecf20Sopenharmony_ci * starting from linux 2.6.26. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * So we only stop when we know alive == 1 (else we discard the data anyway), 228c2ecf20Sopenharmony_ci * and the alive synth will eventually call start_ttys from the thread context. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_civoid speakup_start_ttys(void) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci int i; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) { 298c2ecf20Sopenharmony_ci if (speakup_console[i] && speakup_console[i]->tty_stopped) 308c2ecf20Sopenharmony_ci continue; 318c2ecf20Sopenharmony_ci if (vc_cons[i].d && vc_cons[i].d->port.tty) 328c2ecf20Sopenharmony_ci start_tty(vc_cons[i].d->port.tty); 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(speakup_start_ttys); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic void speakup_stop_ttys(void) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci int i; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) 428c2ecf20Sopenharmony_ci if (vc_cons[i].d && vc_cons[i].d->port.tty) 438c2ecf20Sopenharmony_ci stop_tty(vc_cons[i].d->port.tty); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int synth_buffer_free(void) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci int chars_free; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (buff_in >= buff_out) 518c2ecf20Sopenharmony_ci chars_free = SYNTH_BUF_SIZE - (buff_in - buff_out); 528c2ecf20Sopenharmony_ci else 538c2ecf20Sopenharmony_ci chars_free = buff_out - buff_in; 548c2ecf20Sopenharmony_ci return chars_free; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciint synth_buffer_empty(void) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci return (buff_in == buff_out); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_empty); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_civoid synth_buffer_add(u16 ch) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci if (!synth->alive) { 668c2ecf20Sopenharmony_ci /* This makes sure that we won't stop TTYs if there is no synth 678c2ecf20Sopenharmony_ci * to restart them 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci return; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci if (synth_buffer_free() <= 100) { 728c2ecf20Sopenharmony_ci synth_start(); 738c2ecf20Sopenharmony_ci speakup_stop_ttys(); 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci if (synth_buffer_free() <= 1) 768c2ecf20Sopenharmony_ci return; 778c2ecf20Sopenharmony_ci *buff_in++ = ch; 788c2ecf20Sopenharmony_ci if (buff_in > buffer_end) 798c2ecf20Sopenharmony_ci buff_in = synth_buffer; 808c2ecf20Sopenharmony_ci /* We have written something to the speech synthesis, so we are not 818c2ecf20Sopenharmony_ci * paused any more. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci spk_paused = false; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ciu16 synth_buffer_getc(void) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci u16 ch; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (buff_out == buff_in) 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci ch = *buff_out++; 938c2ecf20Sopenharmony_ci if (buff_out > buffer_end) 948c2ecf20Sopenharmony_ci buff_out = synth_buffer; 958c2ecf20Sopenharmony_ci return ch; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_getc); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciu16 synth_buffer_peek(void) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci if (buff_out == buff_in) 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci return *buff_out; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_peek); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_civoid synth_buffer_skip_nonlatin1(void) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci while (buff_out != buff_in) { 1108c2ecf20Sopenharmony_ci if (*buff_out < 0x100) 1118c2ecf20Sopenharmony_ci return; 1128c2ecf20Sopenharmony_ci buff_out++; 1138c2ecf20Sopenharmony_ci if (buff_out > buffer_end) 1148c2ecf20Sopenharmony_ci buff_out = synth_buffer; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_skip_nonlatin1); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid synth_buffer_clear(void) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci buff_in = synth_buffer; 1228c2ecf20Sopenharmony_ci buff_out = synth_buffer; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(synth_buffer_clear); 125