in speakup/spk_ttyio.c [144:212]
static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
{
int ret = 0;
struct tty_struct *tty;
struct ktermios tmp_termios;
dev_t dev;
ret = get_dev_to_use(synth, &dev);
if (ret)
return ret;
tty = tty_kopen_exclusive(dev);
if (IS_ERR(tty))
return PTR_ERR(tty);
if (tty->ops->open)
ret = tty->ops->open(tty, NULL);
else
ret = -ENODEV;
if (ret) {
tty_unlock(tty);
return ret;
}
clear_bit(TTY_HUPPED, &tty->flags);
/* ensure hardware flow control is enabled */
get_termios(tty, &tmp_termios);
if (!(tmp_termios.c_cflag & CRTSCTS)) {
tmp_termios.c_cflag |= CRTSCTS;
tty_set_termios(tty, &tmp_termios);
/*
* check c_cflag to see if it's updated as tty_set_termios
* may not return error even when no tty bits are
* changed by the request.
*/
get_termios(tty, &tmp_termios);
if (!(tmp_termios.c_cflag & CRTSCTS))
pr_warn("speakup: Failed to set hardware flow control\n");
}
tty_unlock(tty);
mutex_lock(&speakup_tty_mutex);
speakup_tty = tty;
ret = tty_set_ldisc(tty, N_SPEAKUP);
speakup_tty = NULL;
mutex_unlock(&speakup_tty_mutex);
if (!ret) {
/* Success */
struct spk_ldisc_data *ldisc_data = tty->disc_data;
ldisc_data->synth = synth;
synth->dev = tty;
return 0;
}
pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
tty_lock(tty);
if (tty->ops->close)
tty->ops->close(tty, NULL);
tty_unlock(tty);
tty_kclose(tty);
return ret;
}