Okash Khawaja, on sam. 29 avril 2017 14:53:18 +0100, wrote: > 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@xxxxxxxxx> Reviewed-by: Samuel Thibault <samuel.thibault@xxxxxxxxxxxx> > 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); > -- Samuel <y> t1 faich <y> les programmes ils segfaultent jamais quand on veut -+- #ens-mim en plein débogage -+- _______________________________________________ Speakup mailing list Speakup@xxxxxxxxxxxxxxxxx http://linux-speakup.org/cgi-bin/mailman/listinfo/speakup