From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by befuddled.reisers.ca (Postfix, from userid 65534) id 6CAE71EFFE1; Thu, 13 Apr 2017 13:48:49 -0400 (EDT) Received: from mail-wr0-f193.google.com (mail-wr0-f193.google.com [209.85.128.193]) by befuddled.reisers.ca (Postfix) with ESMTPS id 9E83C1F0785 for ; Thu, 13 Apr 2017 13:47:46 -0400 (EDT) Received: by mail-wr0-f193.google.com with SMTP id u18so9644842wrc.1 for ; Thu, 13 Apr 2017 10:47:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:user-agent:date:from:to:cc:subject:references :mime-version:content-disposition; bh=D0PYkBUn0dPKeLgROL4sDzdFGWnC9JknnbkQs+Gwg5E=; b=pY2XguHz3Sf9UbyE5r0mLQoqD6mBD9PGLH4j3gAHnZqeYHIyUfI/5Vexv6zlcOnD8f VqctxN+I6/KlUzZRYV/e976aKUbe1MF4Q1YDe6hJQtKsYP8aYlpj65cTBX57XxAKjnLw fUBlntXRiJE5SSe5BBANNX+YYwHs1P2zcnCckoCGPjjaCY43MpNR6kOUKANi6I4aJFaG I+9RjgjLcwVMk413mA6nGZxrKZkgbURJvBWbR1Xkd9/7sQTm9tHChskxbDsc9NO70iwP wbvhLpzenH9dL1tUsnwCfMTKEdvWGCOEhXkFkLgKBWUp+EFxu2DqUut6h+pKxbqG57bj mAvg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:user-agent:date:from:to:cc:subject :references:mime-version:content-disposition; bh=D0PYkBUn0dPKeLgROL4sDzdFGWnC9JknnbkQs+Gwg5E=; b=UFlPT2NnKhcNYR6hp3eAKtxkpzErIc2sZc//z6w9e3dtqLXq/xm1mfKfJn16Fey6xM yf3HK6ZUEQpK3Dh+HoA9jXyJFHTtTRGieM3072BEbgXUj8vrTbRCPmgz8CRgzhnGEXNN Pw9iLLqdViKtnBBpd7CHLVDoqpGaD35oT5APLGZJqsXYtw8rxHNXUuk2J5itplgnXbuN 8nfF9JMUZxNmAes25MXlmrUiq2DyyyErZgebNz14k6fuj0F6akBzJfw/mJkG3IXW8hOV SamxdCOORejiW/ao9sjeiD9x/sORdTeRjThpps6K6/4qbUPuGdKEgQ70pRZoPuCHwk0W W87A== X-Gm-Message-State: AN3rC/4YTS/aE6oVINBfW7fhwG8IHBzYOiqyCK1npKwMXvE76NzJY/Jj edyGIL4PW5h3lA== X-Received: by 10.223.138.232 with SMTP id z37mr3976623wrz.50.1492105655186; Thu, 13 Apr 2017 10:47:35 -0700 (PDT) Received: from sanghar ([2a00:23c4:7320:5e00:224:d6ff:fe76:7136]) by smtp.gmail.com with ESMTPSA id k63sm11382125wmf.9.2017.04.13.10.47.33 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 13 Apr 2017 10:47:34 -0700 (PDT) Message-Id: <20170413174733.472443648@gmail.com> User-Agent: quilt/0.65 Date: Thu, 13 Apr 2017 18:41:34 +0100 From: Okash Khawaja To: Samuel Thibault Cc: speakup@linux-speakup.org, Okash Khawaja Subject: [patch 6/7] staging: speakup: add send_xchar, tiocmset and input functionality for tty References: <20170413174128.794011516@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-15 Content-Disposition: inline; filename=06_add_tty_send_xchar_tiocmset_and_input_functionality 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: Thu, 13 Apr 2017 17:48:51 -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,98 @@ #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; +/* TODO: make this part of synth and remove the global */ 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 = (struct spk_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); @@ -41,7 +103,7 @@ static int spk_ttyio_initialise_ldisc(in ret = tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops); if (ret) { - pr_err("Error registering line discipline.\n"); + pr_err("speakup: Error registering line discipline.\n"); return ret; } @@ -95,6 +157,49 @@ static int spk_ttyio_out(struct spk_synt 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 = + (struct spk_ldisc_data *)speakup_tty->disc_data; + char rv; + + if (!down_timeout(&ldisc_data->sem, usecs_to_jiffies(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; + tty_schedule_flip(speakup_tty->port); + up(&ldisc_data->sem); + + 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 +208,7 @@ int spk_ttyio_synth_probe(struct spk_syn 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 @@ struct old_serial_port { }; /* 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 const struct old_serial_port *spk_serial_init(int index); void spk_stop_serial_interrupt(void);