From 65fa72d34360c571b058afeb0e64367d3eaf064b Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sat, 10 Mar 2018 11:56:27 +0100 Subject: [PATCH] staging: speakup: Add unicode support to the speakup_dummy driver This extends spk_io_ops with a synth_out_unicode which takes a u16 character instead of just a byte, and extends spk_ttyio to implement it to emit utf-8. spk_do_catch_up_unicode can then be introduced to benefit from synth_out_unicode, and speakup_dummy made to use spk_do_catch_up_unicode instead of spk_do_catch_up. Signed-off-by: Samuel Thibault Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/speakup_dummy.c | 2 +- drivers/staging/speakup/spk_priv.h | 1 + drivers/staging/speakup/spk_ttyio.c | 18 ++++++++++++++++++ drivers/staging/speakup/spk_types.h | 1 + drivers/staging/speakup/synth.c | 25 +++++++++++++++++++++---- 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/drivers/staging/speakup/speakup_dummy.c b/drivers/staging/speakup/speakup_dummy.c index a30d60450bd5..aa0c900f79f2 100644 --- a/drivers/staging/speakup/speakup_dummy.c +++ b/drivers/staging/speakup/speakup_dummy.c @@ -94,7 +94,7 @@ static struct spk_synth synth_dummy = { .probe = spk_ttyio_synth_probe, .release = spk_ttyio_release, .synth_immediate = spk_ttyio_synth_immediate, - .catch_up = spk_do_catch_up, + .catch_up = spk_do_catch_up_unicode, .flush = spk_synth_flush, .is_alive = spk_synth_is_alive_restart, .synth_adjust = NULL, diff --git a/drivers/staging/speakup/spk_priv.h b/drivers/staging/speakup/spk_priv.h index 00430437eb4c..7b3a16e1fa23 100644 --- a/drivers/staging/speakup/spk_priv.h +++ b/drivers/staging/speakup/spk_priv.h @@ -57,6 +57,7 @@ int spk_ttyio_synth_probe(struct spk_synth *synth); const char *spk_serial_synth_immediate(struct spk_synth *synth, const char *buff); const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff); void spk_do_catch_up(struct spk_synth *synth); +void spk_do_catch_up_unicode(struct spk_synth *synth); void spk_synth_flush(struct spk_synth *synth); unsigned char spk_synth_get_index(struct spk_synth *synth); int spk_synth_is_alive_nop(struct spk_synth *synth); diff --git a/drivers/staging/speakup/spk_ttyio.c b/drivers/staging/speakup/spk_ttyio.c index 311940205bee..ade03b03bcd3 100644 --- a/drivers/staging/speakup/spk_ttyio.c +++ b/drivers/staging/speakup/spk_ttyio.c @@ -110,6 +110,7 @@ static struct tty_ldisc_ops spk_ttyio_ldisc_ops = { }; static int spk_ttyio_out(struct spk_synth *in_synth, const char ch); +static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch); 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); @@ -118,6 +119,7 @@ static void spk_ttyio_flush_buffer(void); struct spk_io_ops spk_ttyio_ops = { .synth_out = spk_ttyio_out, + .synth_out_unicode = spk_ttyio_out_unicode, .send_xchar = spk_ttyio_send_xchar, .tiocmset = spk_ttyio_tiocmset, .synth_in = spk_ttyio_in, @@ -221,6 +223,22 @@ static int spk_ttyio_out(struct spk_synth *in_synth, const char ch) return 0; } +static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch) +{ + int ret; + if (ch < 0x80) + ret = spk_ttyio_out(in_synth, ch); + else if (ch < 0x800) { + 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; +} + static int check_tty(struct tty_struct *tty) { if (!tty) { diff --git a/drivers/staging/speakup/spk_types.h b/drivers/staging/speakup/spk_types.h index c50de6035a9a..4203bed90b4f 100644 --- a/drivers/staging/speakup/spk_types.h +++ b/drivers/staging/speakup/spk_types.h @@ -151,6 +151,7 @@ struct spk_synth; struct spk_io_ops { int (*synth_out)(struct spk_synth *synth, const char ch); + int (*synth_out_unicode)(struct spk_synth *synth, u16 ch); void (*send_xchar)(char ch); void (*tiocmset)(unsigned int set, unsigned int clear); unsigned char (*synth_in)(void); diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index c06e6a810999..7deeb7061018 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c @@ -52,9 +52,9 @@ static int do_synth_init(struct spk_synth *in_synth); * For devices that have a "full" notification mechanism, the driver can * adapt the loop the way they prefer. */ -void spk_do_catch_up(struct spk_synth *synth) +static void _spk_do_catch_up(struct spk_synth *synth, int unicode) { - u_char ch; + u16 ch; unsigned long flags; unsigned long jiff_max; struct var_t *delay_time; @@ -63,6 +63,7 @@ void spk_do_catch_up(struct spk_synth *synth) int jiffy_delta_val; int delay_time_val; int full_time_val; + int ret; jiffy_delta = spk_get_var(JIFFY); full_time = spk_get_var(FULL); @@ -81,7 +82,8 @@ void spk_do_catch_up(struct spk_synth *synth) synth->flush(synth); continue; } - synth_buffer_skip_nonlatin1(); + if (!unicode) + synth_buffer_skip_nonlatin1(); if (synth_buffer_empty()) { spin_unlock_irqrestore(&speakup_info.spinlock, flags); break; @@ -92,7 +94,11 @@ void spk_do_catch_up(struct spk_synth *synth) spin_unlock_irqrestore(&speakup_info.spinlock, flags); if (ch == '\n') ch = synth->procspeech; - if (!synth->io_ops->synth_out(synth, ch)) { + if (unicode) + ret = synth->io_ops->synth_out_unicode(synth, ch); + else + ret = synth->io_ops->synth_out(synth, ch); + if (!ret) { schedule_timeout(msecs_to_jiffies(full_time_val)); continue; } @@ -117,8 +123,19 @@ void spk_do_catch_up(struct spk_synth *synth) } synth->io_ops->synth_out(synth, synth->procspeech); } + +void spk_do_catch_up(struct spk_synth *synth) +{ + _spk_do_catch_up(synth, 0); +} EXPORT_SYMBOL_GPL(spk_do_catch_up); +void spk_do_catch_up_unicode(struct spk_synth *synth) +{ + _spk_do_catch_up(synth, 1); +} +EXPORT_SYMBOL_GPL(spk_do_catch_up_unicode); + void spk_synth_flush(struct spk_synth *synth) { synth->io_ops->flush_buffer();