[patch 6/8] staging: speakup: add tty-based comms functions

Samuel Thibault samuel.thibault at ens-lyon.org
Sun Mar 12 08:29:33 EDT 2017


okash.khawaja at gmail.com, on dim. 12 mars 2017 12:16:50 +0000, wrote:
> This adds spk_ttyio.c file. It contains a set of functions which implement
> those methods in spk_synth struct which relate to sending bytes out using
> serial comms. Implementations in this file perform the same function but
> using TTY subsystem instead. Currently synths access serial ports, directly
> poking standard ISA ports by trying to steal them from serial driver. Some ISA
> cards actually need this way of doing it, but most other synthesizers don't,
> and can actually work by using the proper TTY subsystem through a new N_SPEAKUP
> line discipline. So this adds the methods for drivers to switch to accessing
> serial ports through the TTY subsystem, whenever appropriate.
> 
> Signed-off-by: Okash Khawaja <okash.khawaja at gmail.com>

Reviewed-by: Samuel Thibault <samuel.thibault at ens-lyon.org>

> Index: linux-4.10.1/drivers/staging/speakup/Makefile
> ===================================================================
> --- linux-4.10.1.orig/drivers/staging/speakup/Makefile
> +++ linux-4.10.1/drivers/staging/speakup/Makefile
> @@ -25,6 +25,7 @@
>  	kobjects.o \
>  	selection.o \
>  	serialio.o \
> +	spk_ttyio.o \
>  	synth.o \
>  	thread.o \
>  	varhandlers.o
> Index: linux-4.10.1/drivers/staging/speakup/spk_priv.h
> ===================================================================
> --- linux-4.10.1.orig/drivers/staging/speakup/spk_priv.h
> +++ linux-4.10.1/drivers/staging/speakup/spk_priv.h
> @@ -46,6 +46,7 @@
>  unsigned char spk_serial_in(void);
>  unsigned char spk_serial_in_nowait(void);
>  void spk_serial_release(void);
> +void spk_ttyio_release(void);
>  
>  void synth_buffer_skip_nonlatin1(void);
>  u16 synth_buffer_getc(void);
> @@ -58,7 +59,9 @@
>  		      const char *buf, size_t count);
>  
>  int spk_serial_synth_probe(struct spk_synth *synth);
> +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_synth_flush(struct spk_synth *synth);
>  int spk_synth_is_alive_nop(struct spk_synth *synth);
> @@ -78,5 +81,6 @@
>  extern struct var_t synth_time_vars[];
>  
>  extern struct spk_io_ops spk_serial_io_ops;
> +extern struct spk_io_ops spk_ttyio_ops;
>  
>  #endif
> Index: linux-4.10.1/drivers/staging/speakup/spk_ttyio.c
> ===================================================================
> --- /dev/null
> +++ linux-4.10.1/drivers/staging/speakup/spk_ttyio.c
> @@ -0,0 +1,143 @@
> +#include <linux/types.h>
> +#include <linux/tty.h>
> +
> +#include "speakup.h"
> +#include "spk_types.h"
> +
> +static struct tty_struct *speakup_tty;
> +
> +static int spk_ttyio_ldisc_open(struct tty_struct *tty)
> +{
> +	if (tty->ops->write == NULL)
> +		return -EOPNOTSUPP;
> +	speakup_tty = tty;
> +
> +	return 0;
> +}
> +
> +static void spk_ttyio_ldisc_close(struct tty_struct *tty)
> +{
> +	speakup_tty = NULL;
> +}
> +
> +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,
> +};
> +
> +static int spk_ttyio_out(struct spk_synth *in_synth, const char ch);
> +struct spk_io_ops spk_ttyio_ops = {
> +	.synth_out = spk_ttyio_out,
> +};
> +EXPORT_SYMBOL_GPL(spk_ttyio_ops);
> +
> +static int spk_ttyio_initialise_ldisc(int ser)
> +{
> +	int ret = 0;
> +	struct tty_struct *tty;
> +
> +	ret = tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops);
> +	if (ret) {
> +		pr_err("Error registering line discipline.\n");
> +		return ret;
> +	}
> +
> +	if (ser < 0 || ser > (255 - 64)) {
> +		pr_err("speakup: Invalid ser param. Must be between 0 and 191 inclusive.\n");
> +		return -EINVAL;
> +	}
> +
> +	/* TODO: support more than ttyS* */
> +	tty = tty_open_by_driver(MKDEV(4, (ser +  64)), NULL, NULL);
> +	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);
> +	tty_unlock(tty);
> +
> +	ret = tty_set_ldisc(tty, N_SPEAKUP);
> +
> +	return ret;
> +}
> +
> +static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
> +{
> +	if (in_synth->alive && speakup_tty && speakup_tty->ops->write) {
> +		int ret = speakup_tty->ops->write(speakup_tty, &ch, 1);
> +		if (ret == 0)
> +			/* No room */
> +			return 0;
> +		if (ret < 0) {
> +			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
> +			 */
> +			in_synth->alive = 0;
> +			speakup_start_ttys();
> +			return 0;
> +		}
> +		return 1;
> +	}
> +	return 0;
> +}
> +
> +int spk_ttyio_synth_probe(struct spk_synth *synth)
> +{
> +	int rv = spk_ttyio_initialise_ldisc(synth->ser);
> +
> +	if (rv)
> +		return rv;
> +
> +	synth->alive = 1;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(spk_ttyio_synth_probe);
> +
> +void spk_ttyio_release(void)
> +{
> +	int idx;
> +
> +	if (!speakup_tty)
> +		return;
> +
> +	tty_lock(speakup_tty);
> +	idx = speakup_tty->index;
> +
> +	if (speakup_tty->ops->close)
> +		speakup_tty->ops->close(speakup_tty, NULL);
> +
> +	tty_ldisc_flush(speakup_tty);
> +	tty_unlock(speakup_tty);
> +	tty_ldisc_release(speakup_tty);
> +}
> +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;
> +		if (tty_write_room(speakup_tty) < 1 || !synth->io_ops->synth_out(synth, ch))
> +			return buff;
> +		buff++;
> +	}
> +	return NULL;
> +}
> +EXPORT_SYMBOL_GPL(spk_ttyio_synth_immediate);
> Index: linux-4.10.1/drivers/tty/tty_ldisc.c
> ===================================================================
> --- linux-4.10.1.orig/drivers/tty/tty_ldisc.c
> +++ linux-4.10.1/drivers/tty/tty_ldisc.c
> @@ -602,6 +602,7 @@
>  	tty_unlock(tty);
>  	return retval;
>  }
> +EXPORT_SYMBOL(tty_set_ldisc);
>  
>  /**
>   *	tty_ldisc_kill	-	teardown ldisc
> @@ -794,6 +795,7 @@
>  
>  	tty_ldisc_debug(tty, "released\n");
>  }
> +EXPORT_SYMBOL(tty_ldisc_release);
>  
>  /**
>   *	tty_ldisc_init		-	ldisc setup for new tty
> Index: linux-4.10.1/include/uapi/linux/tty.h
> ===================================================================
> --- linux-4.10.1.orig/include/uapi/linux/tty.h
> +++ linux-4.10.1/include/uapi/linux/tty.h
> @@ -35,5 +35,6 @@
>  #define N_TRACESINK	23	/* Trace data routing for MIPI P1149.7 */
>  #define N_TRACEROUTER	24	/* Trace data routing for MIPI P1149.7 */
>  #define N_NCI		25	/* NFC NCI UART */
> +#define N_SPEAKUP	26	/* Speakup communication with synths*/
>  
>  #endif /* _UAPI_LINUX_TTY_H */
> 

-- 
Samuel
"...[Linux's] capacity to talk via any medium except smoke signals."
(By Dr. Greg Wettstein, Roger Maris Cancer Center)


More information about the Speakup mailing list