Line discipline

Okash Khawaja okash.khawaja at gmail.com
Tue Jan 24 16:52:26 EST 2017


Hi,

On Tue, Jan 24, 2017 at 8:30 AM, Samuel Thibault
<samuel.thibault at ens-lyon.org> wrote:
> Okash Khawaja, on Tue 24 Jan 2017 06:16:46 +0000, wrote:
>> Combined the refactor changes with your tty code to test speakup_dummy. It
>> seems okay
>
> Good :)
>
>> except for problem when unloading speakup.ko - it is in use so can't
>> be unloaded. I have just got this so investigating it.
>
> I guess it's a release issue on the tty or such. Could you share your
> code so we can investigate too?
>
>> One question. Using your code, we can obtain tty, cache it and use it directly
>> for all subsequent writes. Why then use ldisc?
>
> To be able to read characters. There is no "read" operation in the tty.
> We'll receive characters through the receive_buf callback.

Thanks for clarification.
>
> Samuel

I have attached the relevant diff. This is applied after the refactor
changes which allow us to use tty version of spk_serial_out(). Also
I've just hacked it together to test speakup_dummy - other synths
won't work after this change. Please not that since I haven't been
able to look into it yet, it might be a trivial error on my part.
-------------- next part --------------
diff --git a/drivers/staging/speakup/serialio.c b/drivers/staging/speakup/serialio.c
index d8b891f..61c82ba 100644
--- a/drivers/staging/speakup/serialio.c
+++ b/drivers/staging/speakup/serialio.c
@@ -217,9 +217,19 @@ int spk_serial_out(const char ch)
 }
 EXPORT_SYMBOL_GPL(spk_serial_out);
 
+extern struct tty_struct *speakup_tty;
+
 int spk_serial_out_tty(const char ch)
 {
-	return spk_serial_out(ch);
+	// return spk_serial_out(ch);
+	
+	pr_warn("spk_serial_out_tty(): ch=%c, speakup_tty=0x%x\n", ch, speakup_tty);
+
+	if (speakup_tty && speakup_tty->ops->write) {
+		speakup_tty->ops->write(speakup_tty, &ch, 1);
+		return 1;
+	}
+	return 0;
 }
 EXPORT_SYMBOL_GPL(spk_serial_out_tty);
 
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c
index 425438b..dd192a6 100644
--- a/drivers/staging/speakup/synth.c
+++ b/drivers/staging/speakup/synth.c
@@ -12,6 +12,7 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/kthread.h>
+#include <linux/tty.h>
 
 #include "spk_priv.h"
 #include "speakup.h"
@@ -44,8 +45,116 @@ EXPORT_SYMBOL_GPL(speakup_info);
 
 static int do_synth_init(struct spk_synth *in_synth);
 
+struct tty_struct *speakup_tty;
+EXPORT_SYMBOL_GPL(speakup_tty);
+
+static int speakup_ldisc_open(struct tty_struct *tty)
+{   
+    int rv;
+
+    // okashTODO: check for errors
+
+    pr_warn("speakup_test_open(): tty->name: %s; tty->ldisc->ops->name: %s\n",
+        tty->name, tty->ldisc->ops->name);
+    rv = tty->ops->write(tty, "hi ldisc\n", 9);
+    pr_warn("speakup_test_open(): done writing. rv=%d\n", rv);
+    speakup_tty = tty;
+
+    return 0;
+}
+
+static void speakup_ldisc_close(struct tty_struct *tty)
+{
+    pr_warn("speakup_test_close()\n");
+    speakup_tty = NULL;
+}
+
+static struct tty_ldisc_ops speakup_ldisc_ops = {
+    .owner          = THIS_MODULE,
+    .magic          = TTY_LDISC_MAGIC,
+    .name           = "speakup_ldisc",
+    .open           = speakup_ldisc_open,
+    .close          = speakup_ldisc_close,
+};
+
+
+static int initialise_ldisc(void)
+{
+    int ret = 0;
+    struct tty_struct *tty;
+
+    ret = tty_register_ldisc(N_SPEAKUP, &speakup_ldisc_ops);
+    if (ret) {
+        pr_err("speakup_test_init(): Error registering line discipline.\n");
+        return ret;
+    }
+
+
+    tty = tty_open_by_driver(MKDEV(4, 64), NULL, NULL);
+    if (IS_ERR(tty))
+        return PTR_ERR(tty);
+
+    printk("got tty %p\n", tty);
+
+    if (tty->ops->open)
+        ret = tty->ops->open(tty, NULL);
+    else
+        ret = -ENODEV;
+
+/* to be put in ldisc open */
+    if (tty->ops->write == NULL)
+        ret = -EOPNOTSUPP;
+/* */
+
+    if (ret) {
+        tty_unlock(tty);
+        return ret;
+    }
+        
+    clear_bit(TTY_HUPPED, &tty->flags);
+    tty_unlock(tty);
+
+    tty_set_ldisc(tty, N_SPEAKUP);
+    pr_warn(">>> finished calling tty_set_ldisc\n");
+
+    tty->ops->write(tty, "test\n", 5);
+
+    return ret;
+}
+
+static void release_ldisc(void)
+{
+	int idx;
+
+	if (!speakup_tty)
+		return;
+
+        tty_lock(speakup_tty);
+        idx = speakup_tty->index;
+
+#if 0
+        if (tty_release_checks(tty, idx)) {
+                tty_unlock(tty);
+                return 0;
+        }
+#endif
+
+        if (speakup_tty->ops->close)
+                speakup_tty->ops->close(speakup_tty, NULL);
+        tty_unlock(speakup_tty);
+#if 0
+        tty_flush_works(tty);
+#endif
+#if 0
+        mutex_lock(&tty_mutex);
+        release_tty(tty, idx);
+        mutex_unlock(&tty_mutex);
+#endif
+}
+
 int spk_serial_synth_probe(struct spk_synth *synth)
 {
+/*
 	const struct old_serial_port *ser;
 	int failed = 0;
 
@@ -68,7 +177,10 @@ int spk_serial_synth_probe(struct spk_synth *synth)
 	}
 	pr_info("%s: ttyS%i, Driver Version %s\n",
 		synth->long_name, synth->ser, synth->version);
+*/
+	initialise_ldisc();
 	synth->alive = 1;
+	
 	return 0;
 }
 EXPORT_SYMBOL_GPL(spk_serial_synth_probe);
@@ -421,6 +533,10 @@ void synth_release(void)
 	struct var_t *var;
 	unsigned long flags;
 
+	// okashTODO: maybe speakup_tty should be part of synth.
+	
+	release_ldisc();
+
 	if (synth == NULL)
 		return;
 	spin_lock_irqsave(&speakup_info.spinlock, flags);
@@ -432,7 +548,7 @@ void synth_release(void)
 		sysfs_remove_group(speakup_kobj, &synth->attributes);
 	for (var = synth->vars; var->var_id != MAXVARS; var++)
 		speakup_unregister_var(var->var_id);
-	spk_stop_serial_interrupt();
+//	spk_stop_serial_interrupt();
 	synth->release();
 	synth = NULL;
 }


More information about the Speakup mailing list