From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by befuddled.reisers.ca (Postfix, from userid 65534) id 622F01F025E; Sat, 29 Apr 2017 15:55:07 -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 466411F0234 for ; Sat, 29 Apr 2017 15:54:16 -0400 (EDT) Received: by mail-wm0-x242.google.com with SMTP id u65so17026471wmu.3 for ; Sat, 29 Apr 2017 12:54:16 -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=hFbQM9HNNOGULlK0vuBh/fYNEJQfc8aTax6Nu+A4+yA=; b=DiPHOEOdgsjmJP2qB72sTnvabYVcDLKnm7nEMKMU7iVSQL2NDUm8NY6300dFyg8McO nkzjF0P7S1WXqaHSOmQ/JTmNm0LGnsS1eGUllvefmWoxEf/fPk7C557vWWoYjOJb7S7+ 8NvGTOsF19NBaAfvNtkRiXYYri3i4Jjkmj5AKr+T2IYyEm0t35xE7KS0XTjbZlmkCWbE UVoiuNuW+pqAMc2EclF96xA/FSvbPwZO+kZjI5JSTxYozlezfiXgF55g0+q2JgtzILLn 4tMQeG0bvGYkDq1Yn06Zad7mlBdOaOT9JB6WZL84m5SNAaH0lGTrwrihPqHJZio36x84 k6Xg== 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=hFbQM9HNNOGULlK0vuBh/fYNEJQfc8aTax6Nu+A4+yA=; b=MyBBG357uFVU0yb8z9i3ZxBaQSBTZOm0sKbLg0ce40mUNxQNFv6M9QvrTJ8mUmugCz vzMOOC4qhInbNbEt2ALLemb2x5CJpzGNOz+KDs69P4bdgzg3iF9bx85K063X7uSXwxgs K+IUR40EgXHfBgFTP2azrn9DLDqudOWapxXpGEEd2HqH2XJGnR/6M2i8Eezmq5m6d0mM KzH9WHSHMrTp7/fP7QG9de0KXjNrTSKVtjQ0GL9RiFKmGURq/oIg1LAHy7HNaaGQNvFU rfK473aqHxbkFhxI5GpuDCaLjl7YqwcIgfefnYzShi+2Mc4liJWMG/AsLIT0EyvEDyFE fUlQ== X-Gm-Message-State: AN3rC/43IBKiXVAmEtOExGHyx5xTamTBaBj9jrfMqQo8uXtBLleWiY/G 4oEZlVIPHzF8Iw== X-Received: by 10.28.229.145 with SMTP id c139mr2436637wmh.107.1493495654373; Sat, 29 Apr 2017 12:54:14 -0700 (PDT) Received: from sanghar.laptop ([2a00:23c4:7320:5e00:224:d6ff:fe76:7136]) by smtp.gmail.com with ESMTPSA id o17sm6591071wra.56.2017.04.29.12.54.12 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sat, 29 Apr 2017 12:54:13 -0700 (PDT) Received: by sanghar.laptop (sSMTP sendmail emulation); Sat, 29 Apr 2017 20:54:11 +0100 Message-Id: <20170429195411.783463296@gmail.com> User-Agent: quilt/0.65 Date: Sat, 29 Apr 2017 20:53:02 +0100 From: Okash Khawaja To: Greg Kroah-Hartman , Jiri Slaby , Samuel Thibault , linux-kernel@vger.kernel.org Cc: William Hubbs , Chris Brannon , Kirk Reiser , speakup@linux-speakup.org, devel@driverdev.osuosl.org, Okash Khawaja Subject: [patch 5/6] staging: speakup: add send_xchar, tiocmset and input functionality for tty References: <20170429195257.630355823@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-15 Content-Disposition: inline; filename=05_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: Sat, 29 Apr 2017 19:55:08 -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 Reviewed-by: Samuel Thibault 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,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 +#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);