Skip to content

Commit 6b9ad1c

Browse files
bytefiregregkh
authored andcommitted
staging: speakup: add send_xchar, tiocmset and input functionality for tty
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@gmail.com> Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent bd697e2 commit 6b9ad1c

File tree

3 files changed

+111
-1
lines changed

3 files changed

+111
-1
lines changed

drivers/staging/speakup/serialio.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#endif
99
#include <linux/serial_core.h>
1010

11+
#include "spk_priv.h"
12+
1113
/*
1214
* this is cut&paste from 8250.h. Get rid of the structure, the definitions
1315
* and this whole broken driver.
@@ -21,7 +23,7 @@ struct old_serial_port {
2123
};
2224

2325
/* countdown values for serial timeouts in us */
24-
#define SPK_SERIAL_TIMEOUT 100000
26+
#define SPK_SERIAL_TIMEOUT SPK_SYNTH_TIMEOUT
2527
/* countdown values transmitter/dsr timeouts in us */
2628
#define SPK_XMITR_TIMEOUT 100000
2729
/* countdown values cts timeouts in us */

drivers/staging/speakup/spk_priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#endif
4040

4141
#define KT_SPKUP 15
42+
#define SPK_SYNTH_TIMEOUT 100000 /* in micro-seconds */
4243

4344
const struct old_serial_port *spk_serial_init(int index);
4445
void spk_stop_serial_interrupt(void);

drivers/staging/speakup/spk_ttyio.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,97 @@
11
#include <linux/types.h>
22
#include <linux/tty.h>
3+
#include <linux/tty_flip.h>
4+
#include <linux/slab.h>
35

46
#include "speakup.h"
57
#include "spk_types.h"
8+
#include "spk_priv.h"
69

10+
struct spk_ldisc_data {
11+
char buf;
12+
struct semaphore sem;
13+
bool buf_free;
14+
};
15+
16+
static struct spk_synth *spk_ttyio_synth;
717
static struct tty_struct *speakup_tty;
818

919
static int spk_ttyio_ldisc_open(struct tty_struct *tty)
1020
{
21+
struct spk_ldisc_data *ldisc_data;
22+
1123
if (tty->ops->write == NULL)
1224
return -EOPNOTSUPP;
1325
speakup_tty = tty;
1426

27+
ldisc_data = kmalloc(sizeof(struct spk_ldisc_data), GFP_KERNEL);
28+
if (!ldisc_data) {
29+
pr_err("speakup: Failed to allocate ldisc_data.\n");
30+
return -ENOMEM;
31+
}
32+
33+
sema_init(&ldisc_data->sem, 0);
34+
ldisc_data->buf_free = true;
35+
speakup_tty->disc_data = ldisc_data;
36+
1537
return 0;
1638
}
1739

1840
static void spk_ttyio_ldisc_close(struct tty_struct *tty)
1941
{
42+
kfree(speakup_tty->disc_data);
2043
speakup_tty = NULL;
2144
}
2245

46+
static int spk_ttyio_receive_buf2(struct tty_struct *tty,
47+
const unsigned char *cp, char *fp, int count)
48+
{
49+
struct spk_ldisc_data *ldisc_data = tty->disc_data;
50+
51+
if (spk_ttyio_synth->read_buff_add) {
52+
int i;
53+
for (i = 0; i < count; i++)
54+
spk_ttyio_synth->read_buff_add(cp[i]);
55+
56+
return count;
57+
}
58+
59+
if (!ldisc_data->buf_free)
60+
/* ttyio_in will tty_schedule_flip */
61+
return 0;
62+
63+
/* Make sure the consumer has read buf before we have seen
64+
* buf_free == true and overwrite buf */
65+
mb();
66+
67+
ldisc_data->buf = cp[0];
68+
ldisc_data->buf_free = false;
69+
up(&ldisc_data->sem);
70+
71+
return 1;
72+
}
73+
2374
static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
2475
.owner = THIS_MODULE,
2576
.magic = TTY_LDISC_MAGIC,
2677
.name = "speakup_ldisc",
2778
.open = spk_ttyio_ldisc_open,
2879
.close = spk_ttyio_ldisc_close,
80+
.receive_buf2 = spk_ttyio_receive_buf2,
2981
};
3082

3183
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch);
84+
static void spk_ttyio_send_xchar(char ch);
85+
static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear);
86+
static unsigned char spk_ttyio_in(void);
87+
static unsigned char spk_ttyio_in_nowait(void);
88+
3289
struct spk_io_ops spk_ttyio_ops = {
3390
.synth_out = spk_ttyio_out,
91+
.send_xchar = spk_ttyio_send_xchar,
92+
.tiocmset = spk_ttyio_tiocmset,
93+
.synth_in = spk_ttyio_in,
94+
.synth_in_nowait = spk_ttyio_in_nowait,
3495
};
3596
EXPORT_SYMBOL_GPL(spk_ttyio_ops);
3697

@@ -95,6 +156,51 @@ static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
95156
return 0;
96157
}
97158

159+
static void spk_ttyio_send_xchar(char ch)
160+
{
161+
speakup_tty->ops->send_xchar(speakup_tty, ch);
162+
}
163+
164+
static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear)
165+
{
166+
speakup_tty->ops->tiocmset(speakup_tty, set, clear);
167+
}
168+
169+
static unsigned char ttyio_in(int timeout)
170+
{
171+
struct spk_ldisc_data *ldisc_data = speakup_tty->disc_data;
172+
char rv;
173+
174+
if (down_timeout(&ldisc_data->sem, usecs_to_jiffies(timeout)) == -ETIME) {
175+
if (timeout)
176+
pr_warn("spk_ttyio: timeout (%d) while waiting for input\n",
177+
timeout);
178+
return 0xff;
179+
}
180+
181+
rv = ldisc_data->buf;
182+
/* Make sure we have read buf before we set buf_free to let
183+
* the producer overwrite it */
184+
mb();
185+
ldisc_data->buf_free = true;
186+
/* Let TTY push more characters */
187+
tty_schedule_flip(speakup_tty->port);
188+
189+
return rv;
190+
}
191+
192+
static unsigned char spk_ttyio_in(void)
193+
{
194+
return ttyio_in(SPK_SYNTH_TIMEOUT);
195+
}
196+
197+
static unsigned char spk_ttyio_in_nowait(void)
198+
{
199+
char rv = ttyio_in(0);
200+
201+
return (rv == 0xff) ? 0 : rv;
202+
}
203+
98204
int spk_ttyio_synth_probe(struct spk_synth *synth)
99205
{
100206
int rv = spk_ttyio_initialise_ldisc(synth->ser);
@@ -103,6 +209,7 @@ int spk_ttyio_synth_probe(struct spk_synth *synth)
103209
return rv;
104210

105211
synth->alive = 1;
212+
spk_ttyio_synth = synth;
106213

107214
return 0;
108215
}

0 commit comments

Comments
 (0)