2018-01-11 18:08:40 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2017-05-16 01:45:33 +08:00
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/tty.h>
|
2017-05-16 01:45:35 +08:00
|
|
|
#include <linux/tty_flip.h>
|
|
|
|
#include <linux/slab.h>
|
2017-05-16 01:45:33 +08:00
|
|
|
|
|
|
|
#include "speakup.h"
|
|
|
|
#include "spk_types.h"
|
2017-05-16 01:45:35 +08:00
|
|
|
#include "spk_priv.h"
|
2017-05-16 01:45:33 +08:00
|
|
|
|
2017-05-16 01:45:35 +08:00
|
|
|
struct spk_ldisc_data {
|
|
|
|
char buf;
|
2018-12-11 05:41:50 +08:00
|
|
|
struct completion completion;
|
2017-05-16 01:45:35 +08:00
|
|
|
bool buf_free;
|
2021-01-27 06:21:45 +08:00
|
|
|
struct spk_synth *synth;
|
2017-05-16 01:45:35 +08:00
|
|
|
};
|
|
|
|
|
2021-01-27 06:21:45 +08:00
|
|
|
/*
|
|
|
|
* This allows to catch within spk_ttyio_ldisc_open whether it is getting set
|
|
|
|
* on for a speakup-driven device.
|
2017-08-12 16:05:47 +08:00
|
|
|
*/
|
2021-01-27 06:21:45 +08:00
|
|
|
static struct tty_struct *speakup_tty;
|
|
|
|
/* This mutex serializes the use of such global speakup_tty variable */
|
2017-08-12 16:05:47 +08:00
|
|
|
static DEFINE_MUTEX(speakup_tty_mutex);
|
2017-05-16 01:45:33 +08:00
|
|
|
|
2017-06-28 21:13:51 +08:00
|
|
|
static int ser_to_dev(int ser, dev_t *dev_no)
|
2017-06-26 02:40:01 +08:00
|
|
|
{
|
|
|
|
if (ser < 0 || ser > (255 - 64)) {
|
|
|
|
pr_err("speakup: Invalid ser param. Must be between 0 and 191 inclusive.\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*dev_no = MKDEV(4, (64 + ser));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_dev_to_use(struct spk_synth *synth, dev_t *dev_no)
|
|
|
|
{
|
|
|
|
/* use ser only when dev is not specified */
|
|
|
|
if (strcmp(synth->dev_name, SYNTH_DEFAULT_DEV) ||
|
2017-08-12 15:39:48 +08:00
|
|
|
synth->ser == SYNTH_DEFAULT_SER)
|
2017-06-26 02:40:01 +08:00
|
|
|
return tty_dev_name_to_number(synth->dev_name, dev_no);
|
|
|
|
|
|
|
|
return ser_to_dev(synth->ser, dev_no);
|
|
|
|
}
|
|
|
|
|
2017-05-16 01:45:33 +08:00
|
|
|
static int spk_ttyio_ldisc_open(struct tty_struct *tty)
|
|
|
|
{
|
2017-05-16 01:45:35 +08:00
|
|
|
struct spk_ldisc_data *ldisc_data;
|
|
|
|
|
2020-11-30 03:35:23 +08:00
|
|
|
if (tty != speakup_tty)
|
|
|
|
/* Somebody tried to use this line discipline outside speakup */
|
|
|
|
return -ENODEV;
|
|
|
|
|
2019-03-06 16:55:41 +08:00
|
|
|
if (!tty->ops->write)
|
2017-05-16 01:45:33 +08:00
|
|
|
return -EOPNOTSUPP;
|
2020-11-11 02:35:41 +08:00
|
|
|
|
2020-03-24 18:45:48 +08:00
|
|
|
ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL);
|
2020-11-30 03:35:23 +08:00
|
|
|
if (!ldisc_data)
|
2017-05-16 01:45:35 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-12-11 05:41:50 +08:00
|
|
|
init_completion(&ldisc_data->completion);
|
2017-05-16 01:45:35 +08:00
|
|
|
ldisc_data->buf_free = true;
|
2020-11-30 03:35:23 +08:00
|
|
|
tty->disc_data = ldisc_data;
|
2017-05-16 01:45:35 +08:00
|
|
|
|
2017-05-16 01:45:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void spk_ttyio_ldisc_close(struct tty_struct *tty)
|
|
|
|
{
|
2021-01-27 06:21:45 +08:00
|
|
|
kfree(tty->disc_data);
|
2017-05-16 01:45:33 +08:00
|
|
|
}
|
|
|
|
|
2017-05-16 01:45:35 +08:00
|
|
|
static int spk_ttyio_receive_buf2(struct tty_struct *tty,
|
2018-03-06 01:34:13 +08:00
|
|
|
const unsigned char *cp, char *fp, int count)
|
2017-05-16 01:45:35 +08:00
|
|
|
{
|
|
|
|
struct spk_ldisc_data *ldisc_data = tty->disc_data;
|
2021-01-27 06:21:45 +08:00
|
|
|
struct spk_synth *synth = ldisc_data->synth;
|
2017-05-16 01:45:35 +08:00
|
|
|
|
2021-01-27 06:21:45 +08:00
|
|
|
if (synth->read_buff_add) {
|
2017-05-16 01:45:35 +08:00
|
|
|
int i;
|
2017-06-09 20:14:32 +08:00
|
|
|
|
2017-05-16 01:45:35 +08:00
|
|
|
for (i = 0; i < count; i++)
|
2021-01-27 06:21:45 +08:00
|
|
|
synth->read_buff_add(cp[i]);
|
2017-05-16 01:45:35 +08:00
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ldisc_data->buf_free)
|
|
|
|
/* ttyio_in will tty_schedule_flip */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Make sure the consumer has read buf before we have seen
|
2017-09-27 15:43:45 +08:00
|
|
|
* buf_free == true and overwrite buf
|
|
|
|
*/
|
2017-05-16 01:45:35 +08:00
|
|
|
mb();
|
|
|
|
|
|
|
|
ldisc_data->buf = cp[0];
|
|
|
|
ldisc_data->buf_free = false;
|
2018-12-11 05:41:50 +08:00
|
|
|
complete(&ldisc_data->completion);
|
2017-05-16 01:45:35 +08:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-05-16 01:45:33 +08:00
|
|
|
static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.magic = TTY_LDISC_MAGIC,
|
|
|
|
.name = "speakup_ldisc",
|
|
|
|
.open = spk_ttyio_ldisc_open,
|
|
|
|
.close = spk_ttyio_ldisc_close,
|
2017-05-16 01:45:35 +08:00
|
|
|
.receive_buf2 = spk_ttyio_receive_buf2,
|
2017-05-16 01:45:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch);
|
2018-03-10 18:56:27 +08:00
|
|
|
static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch);
|
2021-01-27 06:21:44 +08:00
|
|
|
static void spk_ttyio_send_xchar(struct spk_synth *in_synth, char ch);
|
|
|
|
static void spk_ttyio_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear);
|
|
|
|
static unsigned char spk_ttyio_in(struct spk_synth *in_synth);
|
|
|
|
static unsigned char spk_ttyio_in_nowait(struct spk_synth *in_synth);
|
|
|
|
static void spk_ttyio_flush_buffer(struct spk_synth *in_synth);
|
2020-08-05 00:06:37 +08:00
|
|
|
static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth);
|
2017-05-16 01:45:35 +08:00
|
|
|
|
2017-05-16 01:45:33 +08:00
|
|
|
struct spk_io_ops spk_ttyio_ops = {
|
|
|
|
.synth_out = spk_ttyio_out,
|
2018-03-10 18:56:27 +08:00
|
|
|
.synth_out_unicode = spk_ttyio_out_unicode,
|
2017-05-16 01:45:35 +08:00
|
|
|
.send_xchar = spk_ttyio_send_xchar,
|
|
|
|
.tiocmset = spk_ttyio_tiocmset,
|
|
|
|
.synth_in = spk_ttyio_in,
|
|
|
|
.synth_in_nowait = spk_ttyio_in_nowait,
|
2017-05-16 01:45:37 +08:00
|
|
|
.flush_buffer = spk_ttyio_flush_buffer,
|
2020-08-05 00:06:37 +08:00
|
|
|
.wait_for_xmitr = spk_ttyio_wait_for_xmitr,
|
2017-05-16 01:45:33 +08:00
|
|
|
};
|
|
|
|
EXPORT_SYMBOL_GPL(spk_ttyio_ops);
|
|
|
|
|
2019-02-28 20:29:04 +08:00
|
|
|
static inline void get_termios(struct tty_struct *tty,
|
|
|
|
struct ktermios *out_termios)
|
2017-05-16 01:45:37 +08:00
|
|
|
{
|
|
|
|
down_read(&tty->termios_rwsem);
|
|
|
|
*out_termios = tty->termios;
|
|
|
|
up_read(&tty->termios_rwsem);
|
|
|
|
}
|
|
|
|
|
staging: speakup: make ttyio synths use device name
This patch introduces new module parameter, dev, which takes a string
representing the device that the external synth is connected to, e.g.
ttyS0, ttyUSB0 etc. This is then used to communicate with the synth.
That way, speakup can support more than ttyS*. As of this patch, it
only supports ttyS*, ttyUSB* and selected synths for lp*. dev parameter
is only available for tty-migrated synths.
Users will either use dev or ser as both serve same purpose. This patch
maintains backward compatility by allowing ser to be specified. When
both are specified, whichever is non-default, i.e. not ttyS0, is used.
If both are non-default then dev is used.
Signed-off-by: Okash Khawaja <okash.khawaja@gmail.com>
Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-06-26 02:40:02 +08:00
|
|
|
static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
|
2017-05-16 01:45:33 +08:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct tty_struct *tty;
|
2017-05-16 01:45:37 +08:00
|
|
|
struct ktermios tmp_termios;
|
staging: speakup: make ttyio synths use device name
This patch introduces new module parameter, dev, which takes a string
representing the device that the external synth is connected to, e.g.
ttyS0, ttyUSB0 etc. This is then used to communicate with the synth.
That way, speakup can support more than ttyS*. As of this patch, it
only supports ttyS*, ttyUSB* and selected synths for lp*. dev parameter
is only available for tty-migrated synths.
Users will either use dev or ser as both serve same purpose. This patch
maintains backward compatility by allowing ser to be specified. When
both are specified, whichever is non-default, i.e. not ttyS0, is used.
If both are non-default then dev is used.
Signed-off-by: Okash Khawaja <okash.khawaja@gmail.com>
Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-06-26 02:40:02 +08:00
|
|
|
dev_t dev;
|
2017-05-16 01:45:33 +08:00
|
|
|
|
staging: speakup: make ttyio synths use device name
This patch introduces new module parameter, dev, which takes a string
representing the device that the external synth is connected to, e.g.
ttyS0, ttyUSB0 etc. This is then used to communicate with the synth.
That way, speakup can support more than ttyS*. As of this patch, it
only supports ttyS*, ttyUSB* and selected synths for lp*. dev parameter
is only available for tty-migrated synths.
Users will either use dev or ser as both serve same purpose. This patch
maintains backward compatility by allowing ser to be specified. When
both are specified, whichever is non-default, i.e. not ttyS0, is used.
If both are non-default then dev is used.
Signed-off-by: Okash Khawaja <okash.khawaja@gmail.com>
Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-06-26 02:40:02 +08:00
|
|
|
ret = get_dev_to_use(synth, &dev);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2017-05-16 01:45:33 +08:00
|
|
|
|
2020-12-18 18:42:44 +08:00
|
|
|
tty = tty_kopen_exclusive(dev);
|
2017-05-16 01:45:33 +08:00
|
|
|
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);
|
2017-05-16 01:45:37 +08:00
|
|
|
/* 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);
|
|
|
|
/*
|
2019-02-28 20:29:04 +08:00
|
|
|
* 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.
|
2017-05-16 01:45:37 +08:00
|
|
|
*/
|
|
|
|
get_termios(tty, &tmp_termios);
|
|
|
|
if (!(tmp_termios.c_cflag & CRTSCTS))
|
|
|
|
pr_warn("speakup: Failed to set hardware flow control\n");
|
|
|
|
}
|
|
|
|
|
2017-05-16 01:45:33 +08:00
|
|
|
tty_unlock(tty);
|
|
|
|
|
2020-11-30 03:35:23 +08:00
|
|
|
mutex_lock(&speakup_tty_mutex);
|
|
|
|
speakup_tty = tty;
|
2017-05-16 01:45:33 +08:00
|
|
|
ret = tty_set_ldisc(tty, N_SPEAKUP);
|
2021-01-27 06:21:45 +08:00
|
|
|
speakup_tty = NULL;
|
2020-11-30 03:35:23 +08:00
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
|
|
|
|
2021-01-27 06:21:45 +08:00
|
|
|
if (!ret) {
|
2020-11-30 03:35:23 +08:00
|
|
|
/* Success */
|
2021-01-27 06:21:45 +08:00
|
|
|
struct spk_ldisc_data *ldisc_data = tty->disc_data;
|
|
|
|
|
|
|
|
ldisc_data->synth = synth;
|
|
|
|
synth->dev = tty;
|
2020-11-30 03:35:23 +08:00
|
|
|
return 0;
|
2021-01-27 06:21:45 +08:00
|
|
|
}
|
2020-11-30 03:35:23 +08:00
|
|
|
|
|
|
|
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);
|
2017-05-16 01:45:33 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-07-17 00:18:25 +08:00
|
|
|
void spk_ttyio_register_ldisc(void)
|
|
|
|
{
|
|
|
|
if (tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops))
|
|
|
|
pr_warn("speakup: Error registering line discipline. Most synths won't work.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void spk_ttyio_unregister_ldisc(void)
|
|
|
|
{
|
|
|
|
if (tty_unregister_ldisc(N_SPEAKUP))
|
|
|
|
pr_warn("speakup: Couldn't unregister ldisc\n");
|
|
|
|
}
|
|
|
|
|
2017-05-16 01:45:33 +08:00
|
|
|
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
|
|
|
|
{
|
2021-01-27 06:21:45 +08:00
|
|
|
struct tty_struct *tty = in_synth->dev;
|
2021-01-27 06:21:46 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!in_synth->alive || !tty->ops->write)
|
|
|
|
return 0;
|
2021-01-27 06:21:45 +08:00
|
|
|
|
2021-01-27 06:21:46 +08:00
|
|
|
ret = tty->ops->write(tty, &ch, 1);
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
/* No room */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
/* Success */
|
2017-05-16 01:45:33 +08:00
|
|
|
return 1;
|
2017-08-12 16:05:47 +08:00
|
|
|
|
2021-01-27 06:21:46 +08:00
|
|
|
pr_warn("%s: I/O error, deactivating speakup\n",
|
|
|
|
in_synth->long_name);
|
|
|
|
/* No synth any more, so nobody will restart TTYs,
|
|
|
|
* and we thus need to do it ourselves. Now that there
|
|
|
|
* is no synth we can let application flood anyway
|
|
|
|
*/
|
|
|
|
in_synth->alive = 0;
|
|
|
|
speakup_start_ttys();
|
2017-08-12 16:05:47 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-10 18:56:27 +08:00
|
|
|
static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch)
|
|
|
|
{
|
|
|
|
int ret;
|
2018-03-15 02:22:10 +08:00
|
|
|
|
2018-10-18 09:16:00 +08:00
|
|
|
if (ch < 0x80) {
|
2018-03-10 18:56:27 +08:00
|
|
|
ret = spk_ttyio_out(in_synth, ch);
|
2018-10-18 09:16:00 +08:00
|
|
|
} else if (ch < 0x800) {
|
2018-03-10 18:56:27 +08:00
|
|
|
ret = spk_ttyio_out(in_synth, 0xc0 | (ch >> 6));
|
|
|
|
ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
|
|
|
|
} else {
|
|
|
|
ret = spk_ttyio_out(in_synth, 0xe0 | (ch >> 12));
|
|
|
|
ret &= spk_ttyio_out(in_synth, 0x80 | ((ch >> 6) & 0x3f));
|
|
|
|
ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-01-27 06:21:44 +08:00
|
|
|
static void spk_ttyio_send_xchar(struct spk_synth *in_synth, char ch)
|
2017-05-16 01:45:35 +08:00
|
|
|
{
|
2021-01-27 06:21:45 +08:00
|
|
|
struct tty_struct *tty = in_synth->dev;
|
2017-08-12 16:05:47 +08:00
|
|
|
|
2021-01-27 06:21:45 +08:00
|
|
|
if (tty->ops->send_xchar)
|
|
|
|
tty->ops->send_xchar(tty, ch);
|
2017-05-16 01:45:35 +08:00
|
|
|
}
|
|
|
|
|
2021-01-27 06:21:44 +08:00
|
|
|
static void spk_ttyio_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear)
|
2017-05-16 01:45:35 +08:00
|
|
|
{
|
2021-01-27 06:21:45 +08:00
|
|
|
struct tty_struct *tty = in_synth->dev;
|
2017-08-12 16:05:47 +08:00
|
|
|
|
2021-01-27 06:21:45 +08:00
|
|
|
if (tty->ops->tiocmset)
|
|
|
|
tty->ops->tiocmset(tty, set, clear);
|
2017-05-16 01:45:35 +08:00
|
|
|
}
|
|
|
|
|
2020-08-05 00:06:37 +08:00
|
|
|
static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-01-27 06:21:44 +08:00
|
|
|
static unsigned char ttyio_in(struct spk_synth *in_synth, int timeout)
|
2017-05-16 01:45:35 +08:00
|
|
|
{
|
2021-01-27 06:21:45 +08:00
|
|
|
struct tty_struct *tty = in_synth->dev;
|
|
|
|
struct spk_ldisc_data *ldisc_data = tty->disc_data;
|
2017-05-16 01:45:35 +08:00
|
|
|
char rv;
|
|
|
|
|
2020-11-08 21:12:33 +08:00
|
|
|
if (!timeout) {
|
|
|
|
if (!try_wait_for_completion(&ldisc_data->completion))
|
|
|
|
return 0xff;
|
|
|
|
} else if (wait_for_completion_timeout(&ldisc_data->completion,
|
2018-12-11 05:41:50 +08:00
|
|
|
usecs_to_jiffies(timeout)) == 0) {
|
2020-11-08 21:12:33 +08:00
|
|
|
pr_warn("spk_ttyio: timeout (%d) while waiting for input\n",
|
|
|
|
timeout);
|
2017-05-16 01:45:35 +08:00
|
|
|
return 0xff;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = ldisc_data->buf;
|
|
|
|
/* Make sure we have read buf before we set buf_free to let
|
2017-09-27 15:43:45 +08:00
|
|
|
* the producer overwrite it
|
|
|
|
*/
|
2017-05-16 01:45:35 +08:00
|
|
|
mb();
|
|
|
|
ldisc_data->buf_free = true;
|
|
|
|
/* Let TTY push more characters */
|
2021-01-27 06:21:45 +08:00
|
|
|
tty_schedule_flip(tty->port);
|
2017-05-16 01:45:35 +08:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2021-01-27 06:21:44 +08:00
|
|
|
static unsigned char spk_ttyio_in(struct spk_synth *in_synth)
|
2017-05-16 01:45:35 +08:00
|
|
|
{
|
2021-01-27 06:21:44 +08:00
|
|
|
return ttyio_in(in_synth, SPK_SYNTH_TIMEOUT);
|
2017-05-16 01:45:35 +08:00
|
|
|
}
|
|
|
|
|
2021-01-27 06:21:44 +08:00
|
|
|
static unsigned char spk_ttyio_in_nowait(struct spk_synth *in_synth)
|
2017-05-16 01:45:35 +08:00
|
|
|
{
|
2021-01-27 06:21:44 +08:00
|
|
|
u8 rv = ttyio_in(in_synth, 0);
|
2017-05-16 01:45:35 +08:00
|
|
|
|
|
|
|
return (rv == 0xff) ? 0 : rv;
|
|
|
|
}
|
|
|
|
|
2021-01-27 06:21:44 +08:00
|
|
|
static void spk_ttyio_flush_buffer(struct spk_synth *in_synth)
|
2017-05-16 01:45:37 +08:00
|
|
|
{
|
2021-01-27 06:21:45 +08:00
|
|
|
struct tty_struct *tty = in_synth->dev;
|
2017-08-12 16:05:47 +08:00
|
|
|
|
2021-01-27 06:21:45 +08:00
|
|
|
if (tty->ops->flush_buffer)
|
|
|
|
tty->ops->flush_buffer(tty);
|
2017-05-16 01:45:37 +08:00
|
|
|
}
|
|
|
|
|
2017-05-16 01:45:33 +08:00
|
|
|
int spk_ttyio_synth_probe(struct spk_synth *synth)
|
|
|
|
{
|
staging: speakup: make ttyio synths use device name
This patch introduces new module parameter, dev, which takes a string
representing the device that the external synth is connected to, e.g.
ttyS0, ttyUSB0 etc. This is then used to communicate with the synth.
That way, speakup can support more than ttyS*. As of this patch, it
only supports ttyS*, ttyUSB* and selected synths for lp*. dev parameter
is only available for tty-migrated synths.
Users will either use dev or ser as both serve same purpose. This patch
maintains backward compatility by allowing ser to be specified. When
both are specified, whichever is non-default, i.e. not ttyS0, is used.
If both are non-default then dev is used.
Signed-off-by: Okash Khawaja <okash.khawaja@gmail.com>
Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-06-26 02:40:02 +08:00
|
|
|
int rv = spk_ttyio_initialise_ldisc(synth);
|
2017-05-16 01:45:33 +08:00
|
|
|
|
|
|
|
if (rv)
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
synth->alive = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(spk_ttyio_synth_probe);
|
|
|
|
|
2021-01-27 06:21:44 +08:00
|
|
|
void spk_ttyio_release(struct spk_synth *in_synth)
|
2017-05-16 01:45:33 +08:00
|
|
|
{
|
2021-01-27 06:21:45 +08:00
|
|
|
struct tty_struct *tty = in_synth->dev;
|
2017-05-16 01:45:33 +08:00
|
|
|
|
2021-01-27 06:21:45 +08:00
|
|
|
tty_lock(tty);
|
2017-05-16 01:45:33 +08:00
|
|
|
|
2021-01-27 06:21:45 +08:00
|
|
|
if (tty->ops->close)
|
|
|
|
tty->ops->close(tty, NULL);
|
|
|
|
|
|
|
|
tty_ldisc_flush(tty);
|
|
|
|
tty_unlock(tty);
|
|
|
|
tty_kclose(tty);
|
2017-05-16 01:45:33 +08:00
|
|
|
|
2021-01-27 06:21:45 +08:00
|
|
|
in_synth->dev = NULL;
|
2017-05-16 01:45:33 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(spk_ttyio_release);
|
|
|
|
|
2021-01-27 06:21:44 +08:00
|
|
|
const char *spk_ttyio_synth_immediate(struct spk_synth *in_synth, const char *buff)
|
2017-05-16 01:45:33 +08:00
|
|
|
{
|
2021-01-27 06:21:45 +08:00
|
|
|
struct tty_struct *tty = in_synth->dev;
|
2017-05-16 01:45:33 +08:00
|
|
|
u_char ch;
|
|
|
|
|
|
|
|
while ((ch = *buff)) {
|
|
|
|
if (ch == '\n')
|
2021-01-27 06:21:44 +08:00
|
|
|
ch = in_synth->procspeech;
|
2021-01-27 06:21:45 +08:00
|
|
|
if (tty_write_room(tty) < 1 ||
|
2021-01-27 06:21:44 +08:00
|
|
|
!in_synth->io_ops->synth_out(in_synth, ch))
|
2017-05-16 01:45:33 +08:00
|
|
|
return buff;
|
|
|
|
buff++;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(spk_ttyio_synth_immediate);
|