From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by befuddled.reisers.ca (Postfix, from userid 65534) id BE0361F02CA; Sat, 29 Apr 2017 08:48:30 -0400 (EDT) Received: from mail-wm0-x242.google.com (mail-wm0-x242.google.com [IPv6:2a00:1450:400c:c09::242]) by befuddled.reisers.ca (Postfix) with ESMTPS id 436BD1F02C4 for ; Sat, 29 Apr 2017 08:48:22 -0400 (EDT) Received: by mail-wm0-x242.google.com with SMTP id y10so15750314wmh.0 for ; Sat, 29 Apr 2017 05:48:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :in-reply-to:user-agent; bh=Lds49I999okdr/gXfNSboQIelQAeGlBA0nHNSFxjJUE=; b=dPFj8NRA/JckBwAJ/sMaqoGiFob5//L4P56qTj5jh34luXY4QP5E7e+Q5Fkd8HwbKK cx+ywZu01bAVn8DBO/hPnwwTINdlCMlBA0FF5UP90OGv9wDjz0W8FRSJAZeSLrXguCq9 mF5ZSdVWW0985zeUlvEjGlHcyONII3oPOBp71woPek9wAjTnnOztI2Y8ZsqitpudfS/X IXNBYRs4fW1KyQ7zFbpvpOGvXWcTHKGt//p54c59pk5YEIlhM4BRdPDDC2W8Qf0/CSrH lR+CZLdyi0KB+dtnqFKG9K46hMc+VBCvJUSWaJgevL/nB4HRBRp8qiDmGUVxrgIcDkIQ sMmw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:in-reply-to:user-agent; bh=Lds49I999okdr/gXfNSboQIelQAeGlBA0nHNSFxjJUE=; b=cZ2DHfFquI6T6O7bJfPVBjX+GshS2xUh45WMUFsDN312873q8n1B8tQjftXAFZFZY7 RmPr21tH8lt8D7JRdZO0WW2LsaxYv2HsPxTS5Kg4KlncUpxb2Z8xcpFmaCzf1dSTi/PL cpDDKPcXUDOQJgCQb4+UNEZ2G5ddojXnK7qIRYCQTe3NG//m7BUrmtJzM6lM02Zx+Byd s6qFSj0oRsZpECqc/MLkBDwhvWEkPZlaqC/TA+hiP9gyDxojUF7L4TlpLvoj+qlMVbqZ qaJhjFoIKR2W8dE4B9eqWKmca3MNAIXLvsVGhtlvUWUzpVYuBXQrZ3hjRuXzWguTGpdU gH3A== X-Gm-Message-State: AN3rC/6X6QgLGlSCWvLmmRebev0oH3j2uEHmBQvYEwexyIpJRmK5CX6B ShxOw8HvW3uYuw== X-Received: by 10.28.56.1 with SMTP id f1mr1811264wma.20.1493470091950; Sat, 29 Apr 2017 05:48:11 -0700 (PDT) Received: from sanghar ([2a00:23c4:7320:5e00:224:d6ff:fe76:7136]) by smtp.gmail.com with ESMTPSA id 137sm8069566wmi.19.2017.04.29.05.48.10 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sat, 29 Apr 2017 05:48:11 -0700 (PDT) Date: Sat, 29 Apr 2017 13:48:09 +0100 From: Okash Khawaja To: Samuel Thibault Cc: speakup@linux-speakup.org Subject: staging: speakup: add send_xchar, tiocmset and input functionality for tty Message-ID: <20170429124809.GA1692@sanghar> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20170429120808.2mqqujwn2bp7yi6r@var.youpi.perso.aquilenet.fr> User-Agent: Mutt/1.8.2 (2017-04-18) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 X-BeenThere: speakup@linux-speakup.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Speakup is a screen review system for Linux." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 29 Apr 2017 12:48:32 -0000 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 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 #include +#include +#include #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,48 @@ 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)) != 0) { + 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) +{ + return ttyio_in(0); +} + int spk_ttyio_synth_probe(struct spk_synth *synth) { int rv = spk_ttyio_initialise_ldisc(synth->ser); @@ -103,6 +206,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 +#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);