From: Kirk Reiser <kirk@reisers.ca>
To: Samuel Thibault <samuel.thibault@ens-lyon.org>
Cc: gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org,
speakup@linux-speakup.org
Subject: Re: [PATCH] speakup: Add /dev/synthu device
Date: Sun, 4 Feb 2024 11:07:14 -0500 (EST) [thread overview]
Message-ID: <eacaf4db-5b1e-e42e-96aa-3c803fda9180@reisers.ca> (raw)
In-Reply-To: <20240204155825.ditstifsbqndnce3@begin>
Samuel: Would you possibly look into passing the characters from
saychar and it's family through to the softsynu device? There is a
disconnect because espeakup/espeak-ng pronounces characters one way
and the chartab look up has a different way of saying them. I believe
passing them on is probably better although we give up the ability to
pronounce them as we'd like to hear them.
Thank you for dealing with all this stuff!
Kirk
On Sun, 4 Feb 2024, Samuel Thibault wrote:
> /dev/synth has always been 8bit, but applications nowadays mostly
> expect to be using utf-8 encoding. This adds /dev/synthu to be able
> to synthesize non-latin1 characters. This however remains limited
> to 16bit unicode like the rest of speakup. Any odd input or input
> beyond 16bit is just discarded.
>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
>
> Index: linux-6.4/drivers/accessibility/speakup/devsynth.c
> ===================================================================
> --- linux-6.4.orig/drivers/accessibility/speakup/devsynth.c
> +++ linux-6.4/drivers/accessibility/speakup/devsynth.c
> @@ -7,9 +7,10 @@
> #include "speakup.h"
> #include "spk_priv.h"
>
> -static int misc_registered;
> +static int synth_registered, synthu_registered;
> static int dev_opened;
>
> +/* Latin1 version */
> static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,
> size_t nbytes, loff_t *ppos)
> {
> @@ -34,6 +35,97 @@ static ssize_t speakup_file_write(struct
> return (ssize_t)nbytes;
> }
>
> +/* UTF-8 version */
> +static ssize_t speakup_file_writeu(struct file *fp, const char __user *buffer,
> + size_t nbytes, loff_t *ppos)
> +{
> + size_t count = nbytes, want;
> + const char __user *ptr = buffer;
> + size_t bytes;
> + unsigned long flags;
> + unsigned char buf[256];
> + u16 ubuf[256];
> + size_t in, in2, out;
> +
> + if (!synth)
> + return -ENODEV;
> +
> + want = 1;
> + while (count >= want) {
> + /* Copy some UTF-8 piece from userland */
> + bytes = min(count, sizeof(buf));
> + if (copy_from_user(buf, ptr, bytes))
> + return -EFAULT;
> +
> + /* Convert to u16 */
> + for (in = 0, out = 0; in < bytes; in++) {
> + unsigned char c = buf[in];
> + int nbytes = 8 - fls(c ^ 0xff);
> + u32 value;
> +
> + switch (nbytes) {
> + case 8: /* 0xff */
> + case 7: /* 0xfe */
> + case 1: /* 0x80 */
> + /* Invalid, drop */
> + goto drop;
> +
> + case 0:
> + /* ASCII, copy */
> + ubuf[out++] = c;
> + continue;
> +
> + default:
> + /* 2..6-byte UTF-8 */
> +
> + if (bytes - in < nbytes) {
> + /* We don't have it all yet, stop here
> + * and wait for the rest
> + */
> + bytes = in;
> + want = nbytes;
> + continue;
> + }
> +
> + /* First byte */
> + value = c & ((1u << (7 - nbytes)) - 1);
> +
> + /* Other bytes */
> + for (in2 = 2; in2 <= nbytes; in2++) {
> + c = buf[in + 1];
> + if ((c & 0xc0) != 0x80) {
> + /* Invalid, drop the head */
> + want = 1;
> + goto drop;
> + }
> + value = (value << 6) | (c & 0x3f);
> + in++;
> + }
> +
> + if (value < 0x10000)
> + ubuf[out++] = value;
> + want = 1;
> + break;
> + }
> +drop:
> + }
> +
> + count -= bytes;
> + ptr += bytes;
> +
> + /* And speak this up */
> + if (out) {
> + spin_lock_irqsave(&speakup_info.spinlock, flags);
> + for (in = 0; in < out; in++)
> + synth_buffer_add(ubuf[in]);
> + synth_start();
> + spin_unlock_irqrestore(&speakup_info.spinlock, flags);
> + }
> + }
> +
> + return (ssize_t)(nbytes - count);
> +}
> +
> static ssize_t speakup_file_read(struct file *fp, char __user *buf,
> size_t nbytes, loff_t *ppos)
> {
> @@ -62,31 +154,57 @@ static const struct file_operations synt
> .release = speakup_file_release,
> };
>
> +static const struct file_operations synthu_fops = {
> + .read = speakup_file_read,
> + .write = speakup_file_writeu,
> + .open = speakup_file_open,
> + .release = speakup_file_release,
> +};
> +
> static struct miscdevice synth_device = {
> .minor = MISC_DYNAMIC_MINOR,
> .name = "synth",
> .fops = &synth_fops,
> };
>
> +static struct miscdevice synthu_device = {
> + .minor = MISC_DYNAMIC_MINOR,
> + .name = "synthu",
> + .fops = &synthu_fops,
> +};
> +
> void speakup_register_devsynth(void)
> {
> - if (misc_registered != 0)
> - return;
> -/* zero it so if register fails, deregister will not ref invalid ptrs */
> - if (misc_register(&synth_device)) {
> - pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
> - } else {
> - pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
> - MISC_MAJOR, synth_device.minor);
> - misc_registered = 1;
> + if (!synth_registered) {
> + if (misc_register(&synth_device)) {
> + pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
> + } else {
> + pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
> + MISC_MAJOR, synth_device.minor);
> + synth_registered = 1;
> + }
> + }
> + if (!synthu_registered) {
> + if (misc_register(&synthu_device)) {
> + pr_warn("Couldn't initialize miscdevice /dev/synthu.\n");
> + } else {
> + pr_info("initialized device: /dev/synthu, node (MAJOR %d, MINOR %d)\n",
> + MISC_MAJOR, synthu_device.minor);
> + synthu_registered = 1;
> + }
> }
> }
>
> void speakup_unregister_devsynth(void)
> {
> - if (!misc_registered)
> - return;
> - pr_info("speakup: unregistering synth device /dev/synth\n");
> - misc_deregister(&synth_device);
> - misc_registered = 0;
> + if (synth_registered) {
> + pr_info("speakup: unregistering synth device /dev/synth\n");
> + misc_deregister(&synth_device);
> + synth_registered = 0;
> + }
> + if (synthu_registered) {
> + pr_info("speakup: unregistering synth device /dev/synthu\n");
> + misc_deregister(&synthu_device);
> + synthu_registered = 0;
> + }
> }
>
prev parent reply other threads:[~2024-02-04 16:14 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-04 15:58 Samuel Thibault
2024-02-04 16:07 ` Kirk Reiser [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=eacaf4db-5b1e-e42e-96aa-3c803fda9180@reisers.ca \
--to=kirk@reisers.ca \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=samuel.thibault@ens-lyon.org \
--cc=speakup@linux-speakup.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®