okash.khawaja@xxxxxxxxx, 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@xxxxxxxxx> Reviewed-by: Samuel Thibault <samuel.thibault@xxxxxxxxxxxx> > 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) _______________________________________________ Speakup mailing list Speakup@xxxxxxxxxxxxxxxxx http://linux-speakup.org/cgi-bin/mailman/listinfo/speakup