GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / accessibility / speakup / speakup_apollo.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
4  * this version considerably modified by David Borowski, david575@rogers.com
5  *
6  * Copyright (C) 1998-99  Kirk Reiser.
7  * Copyright (C) 2003 David Borowski.
8  *
9  * this code is specifically written as a driver for the speakup screenreview
10  * package and is not a general device driver.
11  */
12 #include <linux/jiffies.h>
13 #include <linux/sched.h>
14 #include <linux/timer.h>
15 #include <linux/kthread.h>
16 #include <linux/serial_reg.h>   /* for UART_MCR* constants */
17
18 #include "spk_priv.h"
19 #include "speakup.h"
20
21 #define DRV_VERSION "2.21"
22 #define SYNTH_CLEAR 0x18
23 #define PROCSPEECH '\r'
24
25 static void do_catch_up(struct spk_synth *synth);
26
27
28
29 enum default_vars_id {
30         CAPS_START_ID = 0, CAPS_STOP_ID,
31         RATE_ID, PITCH_ID,
32         VOL_ID, VOICE_ID, LANG_ID,
33         DIRECT_ID, V_LAST_VAR_ID,
34         NB_ID
35 };
36
37
38
39
40 static struct var_t vars[NB_ID] = {
41         [CAPS_START_ID] = { CAPS_START, .u.s = {"cap, " } },
42         [CAPS_STOP_ID] = { CAPS_STOP, .u.s = {"" } },
43         [RATE_ID] = { RATE, .u.n = {"@W%d", 6, 1, 9, 0, 0, NULL } },
44         [PITCH_ID] = { PITCH, .u.n = {"@F%x", 10, 0, 15, 0, 0, NULL } },
45         [VOL_ID] = { VOL, .u.n = {"@A%x", 10, 0, 15, 0, 0, NULL } },
46         [VOICE_ID] = { VOICE, .u.n = {"@V%d", 1, 1, 6, 0, 0, NULL } },
47         [LANG_ID] = { LANG, .u.n = {"@=%d,", 1, 1, 4, 0, 0, NULL } },
48         [DIRECT_ID] = { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
49         V_LAST_VAR
50 };
51
52 /*
53  * These attributes will appear in /sys/accessibility/speakup/apollo.
54  */
55 static struct kobj_attribute caps_start_attribute =
56         __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
57 static struct kobj_attribute caps_stop_attribute =
58         __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
59 static struct kobj_attribute lang_attribute =
60         __ATTR(lang, 0644, spk_var_show, spk_var_store);
61 static struct kobj_attribute pitch_attribute =
62         __ATTR(pitch, 0644, spk_var_show, spk_var_store);
63 static struct kobj_attribute rate_attribute =
64         __ATTR(rate, 0644, spk_var_show, spk_var_store);
65 static struct kobj_attribute voice_attribute =
66         __ATTR(voice, 0644, spk_var_show, spk_var_store);
67 static struct kobj_attribute vol_attribute =
68         __ATTR(vol, 0644, spk_var_show, spk_var_store);
69
70 static struct kobj_attribute delay_time_attribute =
71         __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
72 static struct kobj_attribute direct_attribute =
73         __ATTR(direct, 0644, spk_var_show, spk_var_store);
74 static struct kobj_attribute full_time_attribute =
75         __ATTR(full_time, 0644, spk_var_show, spk_var_store);
76 static struct kobj_attribute jiffy_delta_attribute =
77         __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
78 static struct kobj_attribute trigger_time_attribute =
79         __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
80
81 /*
82  * Create a group of attributes so that we can create and destroy them all
83  * at once.
84  */
85 static struct attribute *synth_attrs[] = {
86         &caps_start_attribute.attr,
87         &caps_stop_attribute.attr,
88         &lang_attribute.attr,
89         &pitch_attribute.attr,
90         &rate_attribute.attr,
91         &voice_attribute.attr,
92         &vol_attribute.attr,
93         &delay_time_attribute.attr,
94         &direct_attribute.attr,
95         &full_time_attribute.attr,
96         &jiffy_delta_attribute.attr,
97         &trigger_time_attribute.attr,
98         NULL,   /* need to NULL terminate the list of attributes */
99 };
100
101 static struct spk_synth synth_apollo = {
102         .name = "apollo",
103         .version = DRV_VERSION,
104         .long_name = "Apollo",
105         .init = "@R3@D0@K1\r",
106         .procspeech = PROCSPEECH,
107         .clear = SYNTH_CLEAR,
108         .delay = 500,
109         .trigger = 50,
110         .jiffies = 50,
111         .full = 40000,
112         .dev_name = SYNTH_DEFAULT_DEV,
113         .startup = SYNTH_START,
114         .checkval = SYNTH_CHECK,
115         .vars = vars,
116         .io_ops = &spk_ttyio_ops,
117         .probe = spk_ttyio_synth_probe,
118         .release = spk_ttyio_release,
119         .synth_immediate = spk_ttyio_synth_immediate,
120         .catch_up = do_catch_up,
121         .flush = spk_synth_flush,
122         .is_alive = spk_synth_is_alive_restart,
123         .synth_adjust = NULL,
124         .read_buff_add = NULL,
125         .get_index = NULL,
126         .indexing = {
127                 .command = NULL,
128                 .lowindex = 0,
129                 .highindex = 0,
130                 .currindex = 0,
131         },
132         .attributes = {
133                 .attrs = synth_attrs,
134                 .name = "apollo",
135         },
136 };
137
138 static void do_catch_up(struct spk_synth *synth)
139 {
140         u_char ch;
141         unsigned long flags;
142         unsigned long jiff_max;
143         struct var_t *jiffy_delta;
144         struct var_t *delay_time;
145         struct var_t *full_time;
146         int full_time_val = 0;
147         int delay_time_val = 0;
148         int jiffy_delta_val = 0;
149
150         jiffy_delta = spk_get_var(JIFFY);
151         delay_time = spk_get_var(DELAY);
152         full_time = spk_get_var(FULL);
153         spin_lock_irqsave(&speakup_info.spinlock, flags);
154         jiffy_delta_val = jiffy_delta->u.n.value;
155         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
156         jiff_max = jiffies + jiffy_delta_val;
157
158         while (!kthread_should_stop()) {
159                 spin_lock_irqsave(&speakup_info.spinlock, flags);
160                 jiffy_delta_val = jiffy_delta->u.n.value;
161                 full_time_val = full_time->u.n.value;
162                 delay_time_val = delay_time->u.n.value;
163                 if (speakup_info.flushing) {
164                         speakup_info.flushing = 0;
165                         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
166                         synth->flush(synth);
167                         continue;
168                 }
169                 synth_buffer_skip_nonlatin1();
170                 if (synth_buffer_empty()) {
171                         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
172                         break;
173                 }
174                 ch = synth_buffer_peek();
175                 set_current_state(TASK_INTERRUPTIBLE);
176                 full_time_val = full_time->u.n.value;
177                 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
178                 if (!synth->io_ops->synth_out(synth, ch)) {
179                         synth->io_ops->tiocmset(synth, 0, UART_MCR_RTS);
180                         synth->io_ops->tiocmset(synth, UART_MCR_RTS, 0);
181                         schedule_timeout(msecs_to_jiffies(full_time_val));
182                         continue;
183                 }
184                 if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
185                         spin_lock_irqsave(&speakup_info.spinlock, flags);
186                         jiffy_delta_val = jiffy_delta->u.n.value;
187                         full_time_val = full_time->u.n.value;
188                         delay_time_val = delay_time->u.n.value;
189                         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
190                         if (synth->io_ops->synth_out(synth, synth->procspeech))
191                                 schedule_timeout(msecs_to_jiffies
192                                                  (delay_time_val));
193                         else
194                                 schedule_timeout(msecs_to_jiffies
195                                                  (full_time_val));
196                         jiff_max = jiffies + jiffy_delta_val;
197                 }
198                 set_current_state(TASK_RUNNING);
199                 spin_lock_irqsave(&speakup_info.spinlock, flags);
200                 synth_buffer_getc();
201                 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
202         }
203         synth->io_ops->synth_out(synth, PROCSPEECH);
204 }
205
206 module_param_named(ser, synth_apollo.ser, int, 0444);
207 module_param_named(dev, synth_apollo.dev_name, charp, 0444);
208 module_param_named(start, synth_apollo.startup, short, 0444);
209 module_param_named(rate, vars[RATE_ID].u.n.default_val, int, 0444);
210 module_param_named(pitch, vars[PITCH_ID].u.n.default_val, int, 0444);
211 module_param_named(vol, vars[VOL_ID].u.n.default_val, int, 0444);
212 module_param_named(voice, vars[VOICE_ID].u.n.default_val, int, 0444);
213 module_param_named(lang, vars[LANG_ID].u.n.default_val, int, 0444);
214 module_param_named(direct, vars[DIRECT_ID].u.n.default_val, int, 0444);
215
216
217 MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
218 MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
219 MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
220 MODULE_PARM_DESC(rate, "Set the rate variable on load.");
221 MODULE_PARM_DESC(pitch, "Set the pitch variable on load.");
222 MODULE_PARM_DESC(vol, "Set the vol variable on load.");
223 MODULE_PARM_DESC(voice, "Set the voice variable on load.");
224 MODULE_PARM_DESC(lang, "Set the lang variable on load.");
225 MODULE_PARM_DESC(direct, "Set the direct variable on load.");
226
227
228
229 module_spk_synth(synth_apollo);
230
231 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
232 MODULE_AUTHOR("David Borowski");
233 MODULE_DESCRIPTION("Speakup support for Apollo II synthesizer");
234 MODULE_LICENSE("GPL");
235 MODULE_VERSION(DRV_VERSION);
236