All of lore.kernel.org
 help / color / mirror / Atom feed
From: Okash Khawaja <okash.khawaja@gmail.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Jiri Slaby <jslaby@suse.com>,
	Samuel Thibault <samuel.thibault@ens-lyon.org>,
	linux-kernel@vger.kernel.org
Cc: William Hubbs <w.d.hubbs@gmail.com>,
	Chris Brannon <chris@the-brannons.com>,
	Kirk Reiser <kirk@reisers.ca>,
	speakup@linux-speakup.org, devel@driverdev.osuosl.org,
	Okash Khawaja <okash.khawaja@gmail.com>
Subject: [patch v2 4/6] staging: speakup: add send_xchar, tiocmset and input functionality for tty
Date: Mon, 15 May 2017 18:45:35 +0100	[thread overview]
Message-ID: <20170515175620.748042289@gmail.com> (raw)
In-Reply-To: 20170515174531.968330974@gmail.com

[-- Attachment #1: 05_add_tty_send_xchar_tiocmset_and_input_functionality --]
[-- Type: text/plain, Size: 6646 bytes --]

This patch adds further TTY-based functionality, specifically implementation
of send_xchar and tiocmset methods, and input. send_xchar and tiocmset
methods simply delegate to corresponding TTY operations.

For input, it implements the receive_buf2 callback in tty_ldisc_ops of
speakup's ldisc. If a synth defines read_buff_add method then receive_buf2
simply delegates to that and returns.

For spk_ttyio_in, the data is passed from receive_buf2 thread to
spk_ttyio_in thread through spk_ldisc_data structure. It has following
members:

- char buf: represents data received
- struct semaphore sem: used to signal to spk_ttyio_in thread that data
	is available to be read without having to busy wait
- bool buf_free: this is used in comination with mb() calls to syncronise
	the two threads over buf

receive_buf2 only writes to buf if buf_free is true. The check for buf_free
and writing to buf are separated by mb() to ensure that spk_ttyio_in has read
buf before receive_buf2 writes to it. After writing, it ups the semaphore to
signal to spk_ttyio_in that there is now data to read.

spk_ttyio_in waits for data to read by downing the semaphore. Thus when
signalled by receive_buf2 thread above, it reads from buf and sets buf_free
to true. These two operations are separated by mb() to ensure that
receive_buf2 thread finds buf_free to be true only after buf has been read.
After that spk_ttyio_in calls tty_schedule_flip for subsequent data to come
in through receive_buf2.

Signed-off-by: Okash Khawaja <okash.khawaja@gmail.com>
Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

Index: linux-staging/drivers/staging/speakup/spk_ttyio.c
===================================================================
--- linux-staging.orig/drivers/staging/speakup/spk_ttyio.c
+++ linux-staging/drivers/staging/speakup/spk_ttyio.c
@@ -1,36 +1,97 @@
 #include <linux/types.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
 
 #include "speakup.h"
 #include "spk_types.h"
+#include "spk_priv.h"
 
+struct spk_ldisc_data {
+	char buf;
+	struct semaphore sem;
+	bool buf_free;
+};
+
+static struct spk_synth *spk_ttyio_synth;
 static struct tty_struct *speakup_tty;
 
 static int spk_ttyio_ldisc_open(struct tty_struct *tty)
 {
+	struct spk_ldisc_data *ldisc_data;
+
 	if (tty->ops->write == NULL)
 		return -EOPNOTSUPP;
 	speakup_tty = tty;
 
+	ldisc_data = kmalloc(sizeof(struct spk_ldisc_data), GFP_KERNEL);
+	if (!ldisc_data) {
+		pr_err("speakup: Failed to allocate ldisc_data.\n");
+		return -ENOMEM;
+	}
+
+	sema_init(&ldisc_data->sem, 0);
+	ldisc_data->buf_free = true;
+	speakup_tty->disc_data = ldisc_data;
+
 	return 0;
 }
 
 static void spk_ttyio_ldisc_close(struct tty_struct *tty)
 {
+	kfree(speakup_tty->disc_data);
 	speakup_tty = NULL;
 }
 
+static int spk_ttyio_receive_buf2(struct tty_struct *tty,
+		const unsigned char *cp, char *fp, int count)
+{
+	struct spk_ldisc_data *ldisc_data = tty->disc_data;
+
+	if (spk_ttyio_synth->read_buff_add) {
+		int i;
+		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
+         * buf_free == true and overwrite buf */
+	mb();
+
+	ldisc_data->buf = cp[0];
+	ldisc_data->buf_free = false;
+	up(&ldisc_data->sem);
+
+	return 1;
+}
+
 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,
+	.receive_buf2	= spk_ttyio_receive_buf2,
 };
 
 static int spk_ttyio_out(struct spk_synth *in_synth, const char 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);
+static unsigned char spk_ttyio_in_nowait(void);
+
 struct spk_io_ops spk_ttyio_ops = {
 	.synth_out = spk_ttyio_out,
+	.send_xchar = spk_ttyio_send_xchar,
+	.tiocmset = spk_ttyio_tiocmset,
+	.synth_in = spk_ttyio_in,
+	.synth_in_nowait = spk_ttyio_in_nowait,
 };
 EXPORT_SYMBOL_GPL(spk_ttyio_ops);
 
@@ -95,6 +156,51 @@
 	return 0;
 }
 
+static void spk_ttyio_send_xchar(char ch)
+{
+	speakup_tty->ops->send_xchar(speakup_tty, ch);
+}
+
+static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear)
+{
+	speakup_tty->ops->tiocmset(speakup_tty, set, clear);
+}
+
+static unsigned char ttyio_in(int timeout)
+{
+	struct spk_ldisc_data *ldisc_data = speakup_tty->disc_data;
+	char rv;
+
+	if (down_timeout(&ldisc_data->sem, usecs_to_jiffies(timeout)) == -ETIME) {
+		if (timeout)
+			pr_warn("spk_ttyio: timeout (%d)  while waiting for input\n",
+				timeout);
+		return 0xff;
+	}
+
+	rv = ldisc_data->buf;
+	/* Make sure we have read buf before we set buf_free to let
+	 * the producer overwrite it */
+	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)
+{
+	char rv = ttyio_in(0);
+
+	return (rv == 0xff) ? 0 : rv;
+}
+
 int spk_ttyio_synth_probe(struct spk_synth *synth)
 {
 	int rv = spk_ttyio_initialise_ldisc(synth->ser);
@@ -103,6 +209,7 @@
 		return rv;
 
 	synth->alive = 1;
+	spk_ttyio_synth = synth;
 
 	return 0;
 }
Index: linux-staging/drivers/staging/speakup/serialio.h
===================================================================
--- linux-staging.orig/drivers/staging/speakup/serialio.h
+++ linux-staging/drivers/staging/speakup/serialio.h
@@ -8,6 +8,8 @@
 #endif
 #include <linux/serial_core.h>
 
+#include "spk_priv.h"
+
 /*
  * this is cut&paste from 8250.h. Get rid of the structure, the definitions
  * and this whole broken driver.
@@ -21,7 +23,7 @@
 };
 
 /* countdown values for serial timeouts in us */
-#define SPK_SERIAL_TIMEOUT 100000
+#define SPK_SERIAL_TIMEOUT SPK_SYNTH_TIMEOUT
 /* countdown values transmitter/dsr timeouts in us */
 #define SPK_XMITR_TIMEOUT 100000
 /* countdown values cts timeouts in us */
Index: linux-staging/drivers/staging/speakup/spk_priv.h
===================================================================
--- linux-staging.orig/drivers/staging/speakup/spk_priv.h
+++ linux-staging/drivers/staging/speakup/spk_priv.h
@@ -39,6 +39,7 @@
 #endif
 
 #define KT_SPKUP 15
+#define SPK_SYNTH_TIMEOUT 100000 /* in micro-seconds */
 
 const struct old_serial_port *spk_serial_init(int index);
 void spk_stop_serial_interrupt(void);

  parent reply	other threads:[~2017-05-15 17:56 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-15 17:45 [patch v2 0/6] staging: speakup: migrate synths to use TTY-based comms Okash Khawaja
2017-05-15 17:45 ` [patch v2 1/6] tty: export tty_open_by_driver Okash Khawaja
2017-05-21  6:09   ` Christoph Hellwig
2017-05-21  7:43     ` Greg Kroah-Hartman
2017-05-15 17:45 ` [patch v2 2/6] staging: speakup: add tty-based comms functions Okash Khawaja
2017-05-15 17:45 ` [patch v2 3/6] staging: speakup: migrate acntsa, bns, dummy and txprt to ttyio Okash Khawaja
2017-05-15 17:45 ` Okash Khawaja [this message]
2017-05-15 17:45 ` [patch v2 5/6] staging: speakup: migrate apollo, ltlk, audptr, decext, dectlk and spkout Okash Khawaja
2017-05-15 17:45 ` [patch v2 6/6] staging: speakup: flush tty buffers and ensure hardware flow control Okash Khawaja
2017-05-16 12:00   ` Greg Kroah-Hartman
2017-05-16 12:19     ` Okash Khawaja
2017-05-16 12:28       ` Greg Kroah-Hartman
2017-05-16 12:51         ` Okash Khawaja

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=20170515175620.748042289@gmail.com \
    --to=okash.khawaja@gmail.com \
    --cc=chris@the-brannons.com \
    --cc=devel@driverdev.osuosl.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=jslaby@suse.com \
    --cc=kirk@reisers.ca \
    --cc=linux-kernel@vger.kernel.org \
    --cc=samuel.thibault@ens-lyon.org \
    --cc=speakup@linux-speakup.org \
    --cc=w.d.hubbs@gmail.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.