Skip to content

Commit 1ab92da

Browse files
bytefiregregkh
authored andcommitted
staging: speakup: add tty-based comms functions
This adds spk_ttyio.c file. It contains a set of functions which implement those methods in spk_synth struct which relate to sending bytes out using serial comms. Implementations in this file perform the same function but using TTY subsystem instead. Currently synths access serial ports, directly poking standard ISA ports by trying to steal them from serial driver. Some ISA cards actually need this way of doing it, but most other synthesizers don't, and can actually work by using the proper TTY subsystem through a new N_SPEAKUP line discipline. So this adds the methods for drivers to switch to accessing serial ports through the TTY subsystem, whenever appropriate. 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 12e84c7 commit 1ab92da

File tree

5 files changed

+151
-0
lines changed

5 files changed

+151
-0
lines changed

drivers/staging/speakup/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ speakup-y := \
2525
kobjects.o \
2626
selection.o \
2727
serialio.o \
28+
spk_ttyio.o \
2829
synth.o \
2930
thread.o \
3031
varhandlers.o

drivers/staging/speakup/spk_priv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const struct old_serial_port *spk_serial_init(int index);
4444
void spk_stop_serial_interrupt(void);
4545
int spk_wait_for_xmitr(struct spk_synth *in_synth);
4646
void spk_serial_release(void);
47+
void spk_ttyio_release(void);
4748

4849
void synth_buffer_skip_nonlatin1(void);
4950
u16 synth_buffer_getc(void);
@@ -56,7 +57,9 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
5657
const char *buf, size_t count);
5758

5859
int spk_serial_synth_probe(struct spk_synth *synth);
60+
int spk_ttyio_synth_probe(struct spk_synth *synth);
5961
const char *spk_serial_synth_immediate(struct spk_synth *synth, const char *buff);
62+
const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff);
6063
void spk_do_catch_up(struct spk_synth *synth);
6164
void spk_synth_flush(struct spk_synth *synth);
6265
unsigned char spk_synth_get_index(struct spk_synth *synth);
@@ -78,5 +81,6 @@ extern struct speakup_info_t speakup_info;
7881
extern struct var_t synth_time_vars[];
7982

8083
extern struct spk_io_ops spk_serial_io_ops;
84+
extern struct spk_io_ops spk_ttyio_ops;
8185

8286
#endif

drivers/staging/speakup/spk_ttyio.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#include <linux/types.h>
2+
#include <linux/tty.h>
3+
4+
#include "speakup.h"
5+
#include "spk_types.h"
6+
7+
static struct tty_struct *speakup_tty;
8+
9+
static int spk_ttyio_ldisc_open(struct tty_struct *tty)
10+
{
11+
if (tty->ops->write == NULL)
12+
return -EOPNOTSUPP;
13+
speakup_tty = tty;
14+
15+
return 0;
16+
}
17+
18+
static void spk_ttyio_ldisc_close(struct tty_struct *tty)
19+
{
20+
speakup_tty = NULL;
21+
}
22+
23+
static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
24+
.owner = THIS_MODULE,
25+
.magic = TTY_LDISC_MAGIC,
26+
.name = "speakup_ldisc",
27+
.open = spk_ttyio_ldisc_open,
28+
.close = spk_ttyio_ldisc_close,
29+
};
30+
31+
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch);
32+
struct spk_io_ops spk_ttyio_ops = {
33+
.synth_out = spk_ttyio_out,
34+
};
35+
EXPORT_SYMBOL_GPL(spk_ttyio_ops);
36+
37+
static int spk_ttyio_initialise_ldisc(int ser)
38+
{
39+
int ret = 0;
40+
struct tty_struct *tty;
41+
42+
ret = tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops);
43+
if (ret) {
44+
pr_err("Error registering line discipline.\n");
45+
return ret;
46+
}
47+
48+
if (ser < 0 || ser > (255 - 64)) {
49+
pr_err("speakup: Invalid ser param. Must be between 0 and 191 inclusive.\n");
50+
return -EINVAL;
51+
}
52+
53+
/* TODO: support more than ttyS* */
54+
tty = tty_open_by_driver(MKDEV(4, (ser + 64)), NULL, NULL);
55+
if (IS_ERR(tty))
56+
return PTR_ERR(tty);
57+
58+
if (tty->ops->open)
59+
ret = tty->ops->open(tty, NULL);
60+
else
61+
ret = -ENODEV;
62+
63+
if (ret) {
64+
tty_unlock(tty);
65+
return ret;
66+
}
67+
68+
clear_bit(TTY_HUPPED, &tty->flags);
69+
tty_unlock(tty);
70+
71+
ret = tty_set_ldisc(tty, N_SPEAKUP);
72+
73+
return ret;
74+
}
75+
76+
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
77+
{
78+
if (in_synth->alive && speakup_tty && speakup_tty->ops->write) {
79+
int ret = speakup_tty->ops->write(speakup_tty, &ch, 1);
80+
if (ret == 0)
81+
/* No room */
82+
return 0;
83+
if (ret < 0) {
84+
pr_warn("%s: I/O error, deactivating speakup\n", in_synth->long_name);
85+
/* No synth any more, so nobody will restart TTYs, and we thus
86+
* need to do it ourselves. Now that there is no synth we can
87+
* let application flood anyway
88+
*/
89+
in_synth->alive = 0;
90+
speakup_start_ttys();
91+
return 0;
92+
}
93+
return 1;
94+
}
95+
return 0;
96+
}
97+
98+
int spk_ttyio_synth_probe(struct spk_synth *synth)
99+
{
100+
int rv = spk_ttyio_initialise_ldisc(synth->ser);
101+
102+
if (rv)
103+
return rv;
104+
105+
synth->alive = 1;
106+
107+
return 0;
108+
}
109+
EXPORT_SYMBOL_GPL(spk_ttyio_synth_probe);
110+
111+
void spk_ttyio_release(void)
112+
{
113+
int idx;
114+
115+
if (!speakup_tty)
116+
return;
117+
118+
tty_lock(speakup_tty);
119+
idx = speakup_tty->index;
120+
121+
if (speakup_tty->ops->close)
122+
speakup_tty->ops->close(speakup_tty, NULL);
123+
124+
tty_ldisc_flush(speakup_tty);
125+
tty_unlock(speakup_tty);
126+
tty_ldisc_release(speakup_tty);
127+
}
128+
EXPORT_SYMBOL_GPL(spk_ttyio_release);
129+
130+
const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff)
131+
{
132+
u_char ch;
133+
134+
while ((ch = *buff)) {
135+
if (ch == '\n')
136+
ch = synth->procspeech;
137+
if (tty_write_room(speakup_tty) < 1 || !synth->io_ops->synth_out(synth, ch))
138+
return buff;
139+
buff++;
140+
}
141+
return NULL;
142+
}
143+
EXPORT_SYMBOL_GPL(spk_ttyio_synth_immediate);

drivers/tty/tty_ldisc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ int tty_set_ldisc(struct tty_struct *tty, int disc)
605605
tty_unlock(tty);
606606
return retval;
607607
}
608+
EXPORT_SYMBOL_GPL(tty_set_ldisc);
608609

609610
/**
610611
* tty_ldisc_kill - teardown ldisc
@@ -797,6 +798,7 @@ void tty_ldisc_release(struct tty_struct *tty)
797798

798799
tty_ldisc_debug(tty, "released\n");
799800
}
801+
EXPORT_SYMBOL_GPL(tty_ldisc_release);
800802

801803
/**
802804
* tty_ldisc_init - ldisc setup for new tty

include/uapi/linux/tty.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,6 @@
3535
#define N_TRACESINK 23 /* Trace data routing for MIPI P1149.7 */
3636
#define N_TRACEROUTER 24 /* Trace data routing for MIPI P1149.7 */
3737
#define N_NCI 25 /* NFC NCI UART */
38+
#define N_SPEAKUP 26 /* Speakup communication with synths */
3839

3940
#endif /* _UAPI_LINUX_TTY_H */

0 commit comments

Comments
 (0)