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;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct spk_synth *spk_ttyio_synth;
|
2017-05-16 01:45:33 +08:00
|
|
|
static struct tty_struct *speakup_tty;
|
2017-08-12 16:05:47 +08:00
|
|
|
/* mutex to protect against speakup_tty disappearing from underneath us while
|
|
|
|
* we are using it. this can happen when the device physically unplugged,
|
|
|
|
* while in use. it also serialises access to speakup_tty.
|
|
|
|
*/
|
|
|
|
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)
|
|
|
|
{
|
2017-08-12 16:05:47 +08:00
|
|
|
mutex_lock(&speakup_tty_mutex);
|
2017-05-16 01:45:35 +08:00
|
|
|
kfree(speakup_tty->disc_data);
|
2017-05-16 01:45:33 +08:00
|
|
|
speakup_tty = NULL;
|
2017-08-12 16:05:47 +08:00
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
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;
|
|
|
|
|
|
|
|
if (spk_ttyio_synth->read_buff_add) {
|
|
|
|
int i;
|
2017-06-09 20:14:32 +08:00
|
|
|
|
2017-05-16 01:45:35 +08:00
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
spk_ttyio_synth->read_buff_add(cp[i]);
|
|
|
|
|
|
|
|
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);
|
2017-05-16 01:45:35 +08:00
|
|
|
static void spk_ttyio_send_xchar(char ch);
|
|
|
|
static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear);
|
|
|
|
static unsigned char spk_ttyio_in(void);
|
|
|
|
static unsigned char spk_ttyio_in_nowait(void);
|
2017-05-16 01:45:37 +08:00
|
|
|
static void spk_ttyio_flush_buffer(void);
|
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
|
|
|
|
2017-07-20 15:22:37 +08:00
|
|
|
tty = tty_kopen(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);
|
2017-07-17 00:18:26 +08:00
|
|
|
if (ret)
|
2020-11-30 03:35:23 +08:00
|
|
|
speakup_tty = NULL;
|
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
/* Success */
|
|
|
|
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);
|
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)
|
|
|
|
{
|
2017-08-12 16:05:47 +08:00
|
|
|
mutex_lock(&speakup_tty_mutex);
|
2017-05-16 01:45:33 +08:00
|
|
|
if (in_synth->alive && speakup_tty && speakup_tty->ops->write) {
|
|
|
|
int ret = speakup_tty->ops->write(speakup_tty, &ch, 1);
|
2017-06-09 20:14:32 +08:00
|
|
|
|
2017-08-12 16:05:47 +08:00
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
2017-05-16 01:45:33 +08:00
|
|
|
if (ret == 0)
|
|
|
|
/* No room */
|
|
|
|
return 0;
|
|
|
|
if (ret < 0) {
|
2019-02-28 20:29:04 +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
|
2017-05-16 01:45:33 +08:00
|
|
|
*/
|
|
|
|
in_synth->alive = 0;
|
|
|
|
speakup_start_ttys();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2017-08-12 16:05:47 +08:00
|
|
|
|
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-08-12 16:05:47 +08:00
|
|
|
static int check_tty(struct tty_struct *tty)
|
|
|
|
{
|
|
|
|
if (!tty) {
|
|
|
|
pr_warn("%s: I/O error, deactivating speakup\n",
|
|
|
|
spk_ttyio_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
|
|
|
|
*/
|
|
|
|
spk_ttyio_synth->alive = 0;
|
|
|
|
speakup_start_ttys();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-05-16 01:45:33 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-16 01:45:35 +08:00
|
|
|
static void spk_ttyio_send_xchar(char ch)
|
|
|
|
{
|
2017-08-12 16:05:47 +08:00
|
|
|
mutex_lock(&speakup_tty_mutex);
|
|
|
|
if (check_tty(speakup_tty)) {
|
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-30 17:49:34 +08:00
|
|
|
if (speakup_tty->ops->send_xchar)
|
|
|
|
speakup_tty->ops->send_xchar(speakup_tty, ch);
|
2017-08-12 16:05:47 +08:00
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
2017-05-16 01:45:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear)
|
|
|
|
{
|
2017-08-12 16:05:47 +08:00
|
|
|
mutex_lock(&speakup_tty_mutex);
|
|
|
|
if (check_tty(speakup_tty)) {
|
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-30 17:49:34 +08:00
|
|
|
if (speakup_tty->ops->tiocmset)
|
|
|
|
speakup_tty->ops->tiocmset(speakup_tty, set, clear);
|
2017-08-12 16:05:47 +08:00
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
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;
|
|
|
|
}
|
|
|
|
|
2017-05-16 01:45:35 +08:00
|
|
|
static unsigned char ttyio_in(int timeout)
|
|
|
|
{
|
|
|
|
struct spk_ldisc_data *ldisc_data = speakup_tty->disc_data;
|
|
|
|
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 */
|
|
|
|
tty_schedule_flip(speakup_tty->port);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned char spk_ttyio_in(void)
|
|
|
|
{
|
|
|
|
return ttyio_in(SPK_SYNTH_TIMEOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned char spk_ttyio_in_nowait(void)
|
|
|
|
{
|
2017-05-20 05:27:18 +08:00
|
|
|
u8 rv = ttyio_in(0);
|
2017-05-16 01:45:35 +08:00
|
|
|
|
|
|
|
return (rv == 0xff) ? 0 : rv;
|
|
|
|
}
|
|
|
|
|
2017-05-16 01:45:37 +08:00
|
|
|
static void spk_ttyio_flush_buffer(void)
|
|
|
|
{
|
2017-08-12 16:05:47 +08:00
|
|
|
mutex_lock(&speakup_tty_mutex);
|
|
|
|
if (check_tty(speakup_tty)) {
|
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-01 03:50:12 +08:00
|
|
|
if (speakup_tty->ops->flush_buffer)
|
|
|
|
speakup_tty->ops->flush_buffer(speakup_tty);
|
2017-08-12 16:05:47 +08:00
|
|
|
|
|
|
|
mutex_unlock(&speakup_tty_mutex);
|
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;
|
2017-05-16 01:45:35 +08:00
|
|
|
spk_ttyio_synth = synth;
|
2017-05-16 01:45:33 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(spk_ttyio_synth_probe);
|
|
|
|
|
|
|
|
void spk_ttyio_release(void)
|
|
|
|
{
|
|
|
|
if (!speakup_tty)
|
|
|
|
return;
|
|
|
|
|
|
|
|
tty_lock(speakup_tty);
|
|
|
|
|
|
|
|
if (speakup_tty->ops->close)
|
|
|
|
speakup_tty->ops->close(speakup_tty, NULL);
|
|
|
|
|
|
|
|
tty_ldisc_flush(speakup_tty);
|
|
|
|
tty_unlock(speakup_tty);
|
2017-07-20 15:22:37 +08:00
|
|
|
tty_kclose(speakup_tty);
|
2017-05-16 01:45:33 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(spk_ttyio_release);
|
|
|
|
|
|
|
|
const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff)
|
|
|
|
{
|
|
|
|
u_char ch;
|
|
|
|
|
|
|
|
while ((ch = *buff)) {
|
|
|
|
if (ch == '\n')
|
|
|
|
ch = synth->procspeech;
|
2019-02-28 20:29:04 +08:00
|
|
|
if (tty_write_room(speakup_tty) < 1 ||
|
|
|
|
!synth->io_ops->synth_out(synth, ch))
|
2017-05-16 01:45:33 +08:00
|
|
|
return buff;
|
|
|
|
buff++;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(spk_ttyio_synth_immediate);
|