Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.10-rc6 403 lines 9.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2#include <linux/types.h> 3#include <linux/tty.h> 4#include <linux/tty_flip.h> 5#include <linux/slab.h> 6 7#include "speakup.h" 8#include "spk_types.h" 9#include "spk_priv.h" 10 11struct spk_ldisc_data { 12 char buf; 13 struct completion completion; 14 bool buf_free; 15}; 16 17static struct spk_synth *spk_ttyio_synth; 18static struct tty_struct *speakup_tty; 19/* mutex to protect against speakup_tty disappearing from underneath us while 20 * we are using it. this can happen when the device physically unplugged, 21 * while in use. it also serialises access to speakup_tty. 22 */ 23static DEFINE_MUTEX(speakup_tty_mutex); 24 25static int ser_to_dev(int ser, dev_t *dev_no) 26{ 27 if (ser < 0 || ser > (255 - 64)) { 28 pr_err("speakup: Invalid ser param. Must be between 0 and 191 inclusive.\n"); 29 return -EINVAL; 30 } 31 32 *dev_no = MKDEV(4, (64 + ser)); 33 return 0; 34} 35 36static int get_dev_to_use(struct spk_synth *synth, dev_t *dev_no) 37{ 38 /* use ser only when dev is not specified */ 39 if (strcmp(synth->dev_name, SYNTH_DEFAULT_DEV) || 40 synth->ser == SYNTH_DEFAULT_SER) 41 return tty_dev_name_to_number(synth->dev_name, dev_no); 42 43 return ser_to_dev(synth->ser, dev_no); 44} 45 46static int spk_ttyio_ldisc_open(struct tty_struct *tty) 47{ 48 struct spk_ldisc_data *ldisc_data; 49 50 if (!tty->ops->write) 51 return -EOPNOTSUPP; 52 53 mutex_lock(&speakup_tty_mutex); 54 if (speakup_tty) { 55 mutex_unlock(&speakup_tty_mutex); 56 return -EBUSY; 57 } 58 speakup_tty = tty; 59 60 ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL); 61 if (!ldisc_data) { 62 speakup_tty = NULL; 63 mutex_unlock(&speakup_tty_mutex); 64 return -ENOMEM; 65 } 66 67 init_completion(&ldisc_data->completion); 68 ldisc_data->buf_free = true; 69 speakup_tty->disc_data = ldisc_data; 70 mutex_unlock(&speakup_tty_mutex); 71 72 return 0; 73} 74 75static void spk_ttyio_ldisc_close(struct tty_struct *tty) 76{ 77 mutex_lock(&speakup_tty_mutex); 78 kfree(speakup_tty->disc_data); 79 speakup_tty = NULL; 80 mutex_unlock(&speakup_tty_mutex); 81} 82 83static int spk_ttyio_receive_buf2(struct tty_struct *tty, 84 const unsigned char *cp, char *fp, int count) 85{ 86 struct spk_ldisc_data *ldisc_data = tty->disc_data; 87 88 if (spk_ttyio_synth->read_buff_add) { 89 int i; 90 91 for (i = 0; i < count; i++) 92 spk_ttyio_synth->read_buff_add(cp[i]); 93 94 return count; 95 } 96 97 if (!ldisc_data->buf_free) 98 /* ttyio_in will tty_schedule_flip */ 99 return 0; 100 101 /* Make sure the consumer has read buf before we have seen 102 * buf_free == true and overwrite buf 103 */ 104 mb(); 105 106 ldisc_data->buf = cp[0]; 107 ldisc_data->buf_free = false; 108 complete(&ldisc_data->completion); 109 110 return 1; 111} 112 113static struct tty_ldisc_ops spk_ttyio_ldisc_ops = { 114 .owner = THIS_MODULE, 115 .magic = TTY_LDISC_MAGIC, 116 .name = "speakup_ldisc", 117 .open = spk_ttyio_ldisc_open, 118 .close = spk_ttyio_ldisc_close, 119 .receive_buf2 = spk_ttyio_receive_buf2, 120}; 121 122static int spk_ttyio_out(struct spk_synth *in_synth, const char ch); 123static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch); 124static void spk_ttyio_send_xchar(char ch); 125static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear); 126static unsigned char spk_ttyio_in(void); 127static unsigned char spk_ttyio_in_nowait(void); 128static void spk_ttyio_flush_buffer(void); 129static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth); 130 131struct spk_io_ops spk_ttyio_ops = { 132 .synth_out = spk_ttyio_out, 133 .synth_out_unicode = spk_ttyio_out_unicode, 134 .send_xchar = spk_ttyio_send_xchar, 135 .tiocmset = spk_ttyio_tiocmset, 136 .synth_in = spk_ttyio_in, 137 .synth_in_nowait = spk_ttyio_in_nowait, 138 .flush_buffer = spk_ttyio_flush_buffer, 139 .wait_for_xmitr = spk_ttyio_wait_for_xmitr, 140}; 141EXPORT_SYMBOL_GPL(spk_ttyio_ops); 142 143static inline void get_termios(struct tty_struct *tty, 144 struct ktermios *out_termios) 145{ 146 down_read(&tty->termios_rwsem); 147 *out_termios = tty->termios; 148 up_read(&tty->termios_rwsem); 149} 150 151static int spk_ttyio_initialise_ldisc(struct spk_synth *synth) 152{ 153 int ret = 0; 154 struct tty_struct *tty; 155 struct ktermios tmp_termios; 156 dev_t dev; 157 158 ret = get_dev_to_use(synth, &dev); 159 if (ret) 160 return ret; 161 162 tty = tty_kopen(dev); 163 if (IS_ERR(tty)) 164 return PTR_ERR(tty); 165 166 if (tty->ops->open) 167 ret = tty->ops->open(tty, NULL); 168 else 169 ret = -ENODEV; 170 171 if (ret) { 172 tty_unlock(tty); 173 return ret; 174 } 175 176 clear_bit(TTY_HUPPED, &tty->flags); 177 /* ensure hardware flow control is enabled */ 178 get_termios(tty, &tmp_termios); 179 if (!(tmp_termios.c_cflag & CRTSCTS)) { 180 tmp_termios.c_cflag |= CRTSCTS; 181 tty_set_termios(tty, &tmp_termios); 182 /* 183 * check c_cflag to see if it's updated as tty_set_termios 184 * may not return error even when no tty bits are 185 * changed by the request. 186 */ 187 get_termios(tty, &tmp_termios); 188 if (!(tmp_termios.c_cflag & CRTSCTS)) 189 pr_warn("speakup: Failed to set hardware flow control\n"); 190 } 191 192 tty_unlock(tty); 193 194 ret = tty_set_ldisc(tty, N_SPEAKUP); 195 if (ret) 196 pr_err("speakup: Failed to set N_SPEAKUP on tty\n"); 197 198 return ret; 199} 200 201void spk_ttyio_register_ldisc(void) 202{ 203 if (tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops)) 204 pr_warn("speakup: Error registering line discipline. Most synths won't work.\n"); 205} 206 207void spk_ttyio_unregister_ldisc(void) 208{ 209 if (tty_unregister_ldisc(N_SPEAKUP)) 210 pr_warn("speakup: Couldn't unregister ldisc\n"); 211} 212 213static int spk_ttyio_out(struct spk_synth *in_synth, const char ch) 214{ 215 mutex_lock(&speakup_tty_mutex); 216 if (in_synth->alive && speakup_tty && speakup_tty->ops->write) { 217 int ret = speakup_tty->ops->write(speakup_tty, &ch, 1); 218 219 mutex_unlock(&speakup_tty_mutex); 220 if (ret == 0) 221 /* No room */ 222 return 0; 223 if (ret < 0) { 224 pr_warn("%s: I/O error, deactivating speakup\n", 225 in_synth->long_name); 226 /* No synth any more, so nobody will restart TTYs, 227 * and we thus need to do it ourselves. Now that there 228 * is no synth we can let application flood anyway 229 */ 230 in_synth->alive = 0; 231 speakup_start_ttys(); 232 return 0; 233 } 234 return 1; 235 } 236 237 mutex_unlock(&speakup_tty_mutex); 238 return 0; 239} 240 241static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch) 242{ 243 int ret; 244 245 if (ch < 0x80) { 246 ret = spk_ttyio_out(in_synth, ch); 247 } else if (ch < 0x800) { 248 ret = spk_ttyio_out(in_synth, 0xc0 | (ch >> 6)); 249 ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f)); 250 } else { 251 ret = spk_ttyio_out(in_synth, 0xe0 | (ch >> 12)); 252 ret &= spk_ttyio_out(in_synth, 0x80 | ((ch >> 6) & 0x3f)); 253 ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f)); 254 } 255 return ret; 256} 257 258static int check_tty(struct tty_struct *tty) 259{ 260 if (!tty) { 261 pr_warn("%s: I/O error, deactivating speakup\n", 262 spk_ttyio_synth->long_name); 263 /* No synth any more, so nobody will restart TTYs, and we thus 264 * need to do it ourselves. Now that there is no synth we can 265 * let application flood anyway 266 */ 267 spk_ttyio_synth->alive = 0; 268 speakup_start_ttys(); 269 return 1; 270 } 271 272 return 0; 273} 274 275static void spk_ttyio_send_xchar(char ch) 276{ 277 mutex_lock(&speakup_tty_mutex); 278 if (check_tty(speakup_tty)) { 279 mutex_unlock(&speakup_tty_mutex); 280 return; 281 } 282 283 if (speakup_tty->ops->send_xchar) 284 speakup_tty->ops->send_xchar(speakup_tty, ch); 285 mutex_unlock(&speakup_tty_mutex); 286} 287 288static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear) 289{ 290 mutex_lock(&speakup_tty_mutex); 291 if (check_tty(speakup_tty)) { 292 mutex_unlock(&speakup_tty_mutex); 293 return; 294 } 295 296 if (speakup_tty->ops->tiocmset) 297 speakup_tty->ops->tiocmset(speakup_tty, set, clear); 298 mutex_unlock(&speakup_tty_mutex); 299} 300 301static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth) 302{ 303 return 1; 304} 305 306static unsigned char ttyio_in(int timeout) 307{ 308 struct spk_ldisc_data *ldisc_data = speakup_tty->disc_data; 309 char rv; 310 311 if (!timeout) { 312 if (!try_wait_for_completion(&ldisc_data->completion)) 313 return 0xff; 314 } else if (wait_for_completion_timeout(&ldisc_data->completion, 315 usecs_to_jiffies(timeout)) == 0) { 316 pr_warn("spk_ttyio: timeout (%d) while waiting for input\n", 317 timeout); 318 return 0xff; 319 } 320 321 rv = ldisc_data->buf; 322 /* Make sure we have read buf before we set buf_free to let 323 * the producer overwrite it 324 */ 325 mb(); 326 ldisc_data->buf_free = true; 327 /* Let TTY push more characters */ 328 tty_schedule_flip(speakup_tty->port); 329 330 return rv; 331} 332 333static unsigned char spk_ttyio_in(void) 334{ 335 return ttyio_in(SPK_SYNTH_TIMEOUT); 336} 337 338static unsigned char spk_ttyio_in_nowait(void) 339{ 340 u8 rv = ttyio_in(0); 341 342 return (rv == 0xff) ? 0 : rv; 343} 344 345static void spk_ttyio_flush_buffer(void) 346{ 347 mutex_lock(&speakup_tty_mutex); 348 if (check_tty(speakup_tty)) { 349 mutex_unlock(&speakup_tty_mutex); 350 return; 351 } 352 353 if (speakup_tty->ops->flush_buffer) 354 speakup_tty->ops->flush_buffer(speakup_tty); 355 356 mutex_unlock(&speakup_tty_mutex); 357} 358 359int spk_ttyio_synth_probe(struct spk_synth *synth) 360{ 361 int rv = spk_ttyio_initialise_ldisc(synth); 362 363 if (rv) 364 return rv; 365 366 synth->alive = 1; 367 spk_ttyio_synth = synth; 368 369 return 0; 370} 371EXPORT_SYMBOL_GPL(spk_ttyio_synth_probe); 372 373void spk_ttyio_release(void) 374{ 375 if (!speakup_tty) 376 return; 377 378 tty_lock(speakup_tty); 379 380 if (speakup_tty->ops->close) 381 speakup_tty->ops->close(speakup_tty, NULL); 382 383 tty_ldisc_flush(speakup_tty); 384 tty_unlock(speakup_tty); 385 tty_kclose(speakup_tty); 386} 387EXPORT_SYMBOL_GPL(spk_ttyio_release); 388 389const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff) 390{ 391 u_char ch; 392 393 while ((ch = *buff)) { 394 if (ch == '\n') 395 ch = synth->procspeech; 396 if (tty_write_room(speakup_tty) < 1 || 397 !synth->io_ops->synth_out(synth, ch)) 398 return buff; 399 buff++; 400 } 401 return NULL; 402} 403EXPORT_SYMBOL_GPL(spk_ttyio_synth_immediate);