Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/accessibility/speakup/spk_ttyio.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <linux/types.h>
3
#include <linux/tty.h>
4
#include <linux/tty_flip.h>
5
#include <linux/slab.h>
6
7
#include "speakup.h"
8
#include "spk_types.h"
9
#include "spk_priv.h"
10
11
struct spk_ldisc_data {
12
char buf;
13
struct completion completion;
14
bool buf_free;
15
struct spk_synth *synth;
16
};
17
18
/*
19
* This allows to catch within spk_ttyio_ldisc_open whether it is getting set
20
* on for a speakup-driven device.
21
*/
22
static struct tty_struct *speakup_tty;
23
/* This mutex serializes the use of such global speakup_tty variable */
24
static DEFINE_MUTEX(speakup_tty_mutex);
25
26
static int ser_to_dev(int ser, dev_t *dev_no)
27
{
28
if (ser < 0 || ser > (255 - 64)) {
29
pr_err("speakup: Invalid ser param. Must be between 0 and 191 inclusive.\n");
30
return -EINVAL;
31
}
32
33
*dev_no = MKDEV(4, (64 + ser));
34
return 0;
35
}
36
37
static int get_dev_to_use(struct spk_synth *synth, dev_t *dev_no)
38
{
39
/* use ser only when dev is not specified */
40
if (strcmp(synth->dev_name, SYNTH_DEFAULT_DEV) ||
41
synth->ser == SYNTH_DEFAULT_SER)
42
return tty_dev_name_to_number(synth->dev_name, dev_no);
43
44
return ser_to_dev(synth->ser, dev_no);
45
}
46
47
static int spk_ttyio_ldisc_open(struct tty_struct *tty)
48
{
49
struct spk_ldisc_data *ldisc_data;
50
51
if (tty != speakup_tty)
52
/* Somebody tried to use this line discipline outside speakup */
53
return -ENODEV;
54
55
if (!tty->ops->write)
56
return -EOPNOTSUPP;
57
58
ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL);
59
if (!ldisc_data)
60
return -ENOMEM;
61
62
init_completion(&ldisc_data->completion);
63
ldisc_data->buf_free = true;
64
tty->disc_data = ldisc_data;
65
66
return 0;
67
}
68
69
static void spk_ttyio_ldisc_close(struct tty_struct *tty)
70
{
71
kfree(tty->disc_data);
72
}
73
74
static size_t spk_ttyio_receive_buf2(struct tty_struct *tty, const u8 *cp,
75
const u8 *fp, size_t count)
76
{
77
struct spk_ldisc_data *ldisc_data = tty->disc_data;
78
struct spk_synth *synth = ldisc_data->synth;
79
80
if (synth->read_buff_add) {
81
unsigned int i;
82
83
for (i = 0; i < count; i++)
84
synth->read_buff_add(cp[i]);
85
86
return count;
87
}
88
89
if (!ldisc_data->buf_free)
90
/* ttyio_in will tty_flip_buffer_push */
91
return 0;
92
93
/* Make sure the consumer has read buf before we have seen
94
* buf_free == true and overwrite buf
95
*/
96
mb();
97
98
ldisc_data->buf = cp[0];
99
ldisc_data->buf_free = false;
100
complete(&ldisc_data->completion);
101
102
return 1;
103
}
104
105
static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
106
.owner = THIS_MODULE,
107
.num = N_SPEAKUP,
108
.name = "speakup_ldisc",
109
.open = spk_ttyio_ldisc_open,
110
.close = spk_ttyio_ldisc_close,
111
.receive_buf2 = spk_ttyio_receive_buf2,
112
};
113
114
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch);
115
static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch);
116
static void spk_ttyio_send_xchar(struct spk_synth *in_synth, char ch);
117
static void spk_ttyio_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear);
118
static unsigned char spk_ttyio_in(struct spk_synth *in_synth);
119
static unsigned char spk_ttyio_in_nowait(struct spk_synth *in_synth);
120
static void spk_ttyio_flush_buffer(struct spk_synth *in_synth);
121
static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth);
122
123
struct spk_io_ops spk_ttyio_ops = {
124
.synth_out = spk_ttyio_out,
125
.synth_out_unicode = spk_ttyio_out_unicode,
126
.send_xchar = spk_ttyio_send_xchar,
127
.tiocmset = spk_ttyio_tiocmset,
128
.synth_in = spk_ttyio_in,
129
.synth_in_nowait = spk_ttyio_in_nowait,
130
.flush_buffer = spk_ttyio_flush_buffer,
131
.wait_for_xmitr = spk_ttyio_wait_for_xmitr,
132
};
133
EXPORT_SYMBOL_GPL(spk_ttyio_ops);
134
135
static inline void get_termios(struct tty_struct *tty,
136
struct ktermios *out_termios)
137
{
138
down_read(&tty->termios_rwsem);
139
*out_termios = tty->termios;
140
up_read(&tty->termios_rwsem);
141
}
142
143
static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
144
{
145
int ret = 0;
146
struct tty_struct *tty;
147
struct ktermios tmp_termios;
148
dev_t dev;
149
150
ret = get_dev_to_use(synth, &dev);
151
if (ret)
152
return ret;
153
154
tty = tty_kopen_exclusive(dev);
155
if (IS_ERR(tty))
156
return PTR_ERR(tty);
157
158
if (tty->ops->open)
159
ret = tty->ops->open(tty, NULL);
160
else
161
ret = -ENODEV;
162
163
if (ret) {
164
tty_unlock(tty);
165
return ret;
166
}
167
168
clear_bit(TTY_HUPPED, &tty->flags);
169
/* ensure hardware flow control is enabled */
170
get_termios(tty, &tmp_termios);
171
if (!(tmp_termios.c_cflag & CRTSCTS)) {
172
tmp_termios.c_cflag |= CRTSCTS;
173
tty_set_termios(tty, &tmp_termios);
174
/*
175
* check c_cflag to see if it's updated as tty_set_termios
176
* may not return error even when no tty bits are
177
* changed by the request.
178
*/
179
get_termios(tty, &tmp_termios);
180
if (!(tmp_termios.c_cflag & CRTSCTS))
181
pr_warn("speakup: Failed to set hardware flow control\n");
182
}
183
184
tty_unlock(tty);
185
186
mutex_lock(&speakup_tty_mutex);
187
speakup_tty = tty;
188
ret = tty_set_ldisc(tty, N_SPEAKUP);
189
speakup_tty = NULL;
190
mutex_unlock(&speakup_tty_mutex);
191
192
if (!ret) {
193
/* Success */
194
struct spk_ldisc_data *ldisc_data = tty->disc_data;
195
196
ldisc_data->synth = synth;
197
synth->dev = tty;
198
return 0;
199
}
200
201
pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
202
203
tty_lock(tty);
204
if (tty->ops->close)
205
tty->ops->close(tty, NULL);
206
tty_unlock(tty);
207
208
tty_kclose(tty);
209
210
return ret;
211
}
212
213
void spk_ttyio_register_ldisc(void)
214
{
215
if (tty_register_ldisc(&spk_ttyio_ldisc_ops))
216
pr_warn("speakup: Error registering line discipline. Most synths won't work.\n");
217
}
218
219
void spk_ttyio_unregister_ldisc(void)
220
{
221
tty_unregister_ldisc(&spk_ttyio_ldisc_ops);
222
}
223
224
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
225
{
226
struct tty_struct *tty = in_synth->dev;
227
int ret;
228
229
if (!in_synth->alive || !tty->ops->write)
230
return 0;
231
232
ret = tty->ops->write(tty, &ch, 1);
233
234
if (ret == 0)
235
/* No room */
236
return 0;
237
238
if (ret > 0)
239
/* Success */
240
return 1;
241
242
pr_warn("%s: I/O error, deactivating speakup\n",
243
in_synth->long_name);
244
/* No synth any more, so nobody will restart TTYs,
245
* and we thus need to do it ourselves. Now that there
246
* is no synth we can let application flood anyway
247
*/
248
in_synth->alive = 0;
249
speakup_start_ttys();
250
return 0;
251
}
252
253
static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch)
254
{
255
int ret;
256
257
if (ch < 0x80) {
258
ret = spk_ttyio_out(in_synth, ch);
259
} else if (ch < 0x800) {
260
ret = spk_ttyio_out(in_synth, 0xc0 | (ch >> 6));
261
ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
262
} else {
263
ret = spk_ttyio_out(in_synth, 0xe0 | (ch >> 12));
264
ret &= spk_ttyio_out(in_synth, 0x80 | ((ch >> 6) & 0x3f));
265
ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
266
}
267
return ret;
268
}
269
270
static void spk_ttyio_send_xchar(struct spk_synth *in_synth, char ch)
271
{
272
struct tty_struct *tty = in_synth->dev;
273
274
if (tty->ops->send_xchar)
275
tty->ops->send_xchar(tty, ch);
276
}
277
278
static void spk_ttyio_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear)
279
{
280
struct tty_struct *tty = in_synth->dev;
281
282
if (tty->ops->tiocmset)
283
tty->ops->tiocmset(tty, set, clear);
284
}
285
286
static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth)
287
{
288
return 1;
289
}
290
291
static unsigned char ttyio_in(struct spk_synth *in_synth, int timeout)
292
{
293
struct tty_struct *tty = in_synth->dev;
294
struct spk_ldisc_data *ldisc_data = tty->disc_data;
295
char rv;
296
297
if (!timeout) {
298
if (!try_wait_for_completion(&ldisc_data->completion))
299
return 0xff;
300
} else if (wait_for_completion_timeout(&ldisc_data->completion,
301
usecs_to_jiffies(timeout)) == 0) {
302
pr_warn("spk_ttyio: timeout (%d) while waiting for input\n",
303
timeout);
304
return 0xff;
305
}
306
307
rv = ldisc_data->buf;
308
/* Make sure we have read buf before we set buf_free to let
309
* the producer overwrite it
310
*/
311
mb();
312
ldisc_data->buf_free = true;
313
/* Let TTY push more characters */
314
tty_flip_buffer_push(tty->port);
315
316
return rv;
317
}
318
319
static unsigned char spk_ttyio_in(struct spk_synth *in_synth)
320
{
321
return ttyio_in(in_synth, SPK_SYNTH_TIMEOUT);
322
}
323
324
static unsigned char spk_ttyio_in_nowait(struct spk_synth *in_synth)
325
{
326
u8 rv = ttyio_in(in_synth, 0);
327
328
return (rv == 0xff) ? 0 : rv;
329
}
330
331
static void spk_ttyio_flush_buffer(struct spk_synth *in_synth)
332
{
333
struct tty_struct *tty = in_synth->dev;
334
335
if (tty->ops->flush_buffer)
336
tty->ops->flush_buffer(tty);
337
}
338
339
int spk_ttyio_synth_probe(struct spk_synth *synth)
340
{
341
int rv = spk_ttyio_initialise_ldisc(synth);
342
343
if (rv)
344
return rv;
345
346
synth->alive = 1;
347
348
return 0;
349
}
350
EXPORT_SYMBOL_GPL(spk_ttyio_synth_probe);
351
352
void spk_ttyio_release(struct spk_synth *in_synth)
353
{
354
struct tty_struct *tty = in_synth->dev;
355
356
if (tty == NULL)
357
return;
358
359
tty_lock(tty);
360
361
if (tty->ops->close)
362
tty->ops->close(tty, NULL);
363
364
tty_ldisc_flush(tty);
365
tty_unlock(tty);
366
tty_kclose(tty);
367
368
in_synth->dev = NULL;
369
}
370
EXPORT_SYMBOL_GPL(spk_ttyio_release);
371
372
const char *spk_ttyio_synth_immediate(struct spk_synth *in_synth, const char *buff)
373
{
374
struct tty_struct *tty = in_synth->dev;
375
u_char ch;
376
377
while ((ch = *buff)) {
378
if (ch == '\n')
379
ch = in_synth->procspeech;
380
if (tty_write_room(tty) < 1 ||
381
!in_synth->io_ops->synth_out(in_synth, ch))
382
return buff;
383
buff++;
384
}
385
return NULL;
386
}
387
EXPORT_SYMBOL_GPL(spk_ttyio_synth_immediate);
388
389