diff options
Diffstat (limited to 'drivers/staging/speakup/speakup_decext.c')
-rw-r--r-- | drivers/staging/speakup/speakup_decext.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/drivers/staging/speakup/speakup_decext.c b/drivers/staging/speakup/speakup_decext.c new file mode 100644 index 00000000000..351bd86d42b --- /dev/null +++ b/drivers/staging/speakup/speakup_decext.c | |||
@@ -0,0 +1,242 @@ | |||
1 | /* | ||
2 | * originally written by: Kirk Reiser <kirk@braille.uwo.ca> | ||
3 | * this version considerably modified by David Borowski, david575@rogers.com | ||
4 | * | ||
5 | * Copyright (C) 1998-99 Kirk Reiser. | ||
6 | * Copyright (C) 2003 David Borowski. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | * specificly written as a driver for the speakup screenreview | ||
23 | * s not a general device driver. | ||
24 | */ | ||
25 | #include <linux/jiffies.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/timer.h> | ||
28 | #include <linux/kthread.h> | ||
29 | |||
30 | #include "spk_priv.h" | ||
31 | #include "serialio.h" | ||
32 | #include "speakup.h" | ||
33 | |||
34 | #define DRV_VERSION "2.14" | ||
35 | #define SYNTH_CLEAR 0x03 | ||
36 | #define PROCSPEECH 0x0b | ||
37 | static unsigned char last_char; | ||
38 | #define get_last_char() ((inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR)? \ | ||
39 | (last_char = inb_p(speakup_info.port_tts + UART_RX)) : last_char) | ||
40 | #define synth_full() (get_last_char() == 0x13) | ||
41 | |||
42 | static void do_catch_up(struct spk_synth *synth); | ||
43 | static void synth_flush(struct spk_synth *synth); | ||
44 | |||
45 | static int in_escape; | ||
46 | |||
47 | static struct var_t vars[] = { | ||
48 | { CAPS_START, .u.s = {"[:dv ap 222]" }}, | ||
49 | { CAPS_STOP, .u.s = {"[:dv ap 100]" }}, | ||
50 | { RATE, .u.n = {"[:ra %d]", 7, 0, 9, 150, 25, NULL }}, | ||
51 | { PITCH, .u.n = {"[:dv ap %d]", 100, 0, 100, 0, 0, NULL }}, | ||
52 | { VOL, .u.n = {"[:dv gv %d]", 13, 0, 16, 0, 5, NULL }}, | ||
53 | { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" }}, | ||
54 | { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" }}, | ||
55 | { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }}, | ||
56 | V_LAST_VAR | ||
57 | }; | ||
58 | |||
59 | /* | ||
60 | * These attributes will appear in /sys/accessibility/speakup/decext. | ||
61 | */ | ||
62 | static struct kobj_attribute caps_start_attribute = | ||
63 | __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); | ||
64 | static struct kobj_attribute caps_stop_attribute = | ||
65 | __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); | ||
66 | static struct kobj_attribute pitch_attribute = | ||
67 | __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); | ||
68 | static struct kobj_attribute punct_attribute = | ||
69 | __ATTR(punct, USER_RW, spk_var_show, spk_var_store); | ||
70 | static struct kobj_attribute rate_attribute = | ||
71 | __ATTR(rate, USER_RW, spk_var_show, spk_var_store); | ||
72 | static struct kobj_attribute voice_attribute = | ||
73 | __ATTR(voice, USER_RW, spk_var_show, spk_var_store); | ||
74 | static struct kobj_attribute vol_attribute = | ||
75 | __ATTR(vol, USER_RW, spk_var_show, spk_var_store); | ||
76 | |||
77 | static struct kobj_attribute delay_time_attribute = | ||
78 | __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); | ||
79 | static struct kobj_attribute direct_attribute = | ||
80 | __ATTR(direct, USER_RW, spk_var_show, spk_var_store); | ||
81 | static struct kobj_attribute full_time_attribute = | ||
82 | __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); | ||
83 | static struct kobj_attribute jiffy_delta_attribute = | ||
84 | __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); | ||
85 | static struct kobj_attribute trigger_time_attribute = | ||
86 | __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); | ||
87 | |||
88 | /* | ||
89 | * Create a group of attributes so that we can create and destroy them all | ||
90 | * at once. | ||
91 | */ | ||
92 | static struct attribute *synth_attrs[] = { | ||
93 | &caps_start_attribute.attr, | ||
94 | &caps_stop_attribute.attr, | ||
95 | &pitch_attribute.attr, | ||
96 | &punct_attribute.attr, | ||
97 | &rate_attribute.attr, | ||
98 | &voice_attribute.attr, | ||
99 | &vol_attribute.attr, | ||
100 | &delay_time_attribute.attr, | ||
101 | &direct_attribute.attr, | ||
102 | &full_time_attribute.attr, | ||
103 | &jiffy_delta_attribute.attr, | ||
104 | &trigger_time_attribute.attr, | ||
105 | NULL, /* need to NULL terminate the list of attributes */ | ||
106 | }; | ||
107 | |||
108 | static struct spk_synth synth_decext = { | ||
109 | .name = "decext", | ||
110 | .version = DRV_VERSION, | ||
111 | .long_name = "Dectalk External", | ||
112 | .init = "[:pe -380]", | ||
113 | .procspeech = PROCSPEECH, | ||
114 | .clear = SYNTH_CLEAR, | ||
115 | .delay = 500, | ||
116 | .trigger = 50, | ||
117 | .jiffies = 50, | ||
118 | .full = 40000, | ||
119 | .flags = SF_DEC, | ||
120 | .startup = SYNTH_START, | ||
121 | .checkval = SYNTH_CHECK, | ||
122 | .vars = vars, | ||
123 | .probe = serial_synth_probe, | ||
124 | .release = spk_serial_release, | ||
125 | .synth_immediate = spk_synth_immediate, | ||
126 | .catch_up = do_catch_up, | ||
127 | .flush = synth_flush, | ||
128 | .is_alive = spk_synth_is_alive_restart, | ||
129 | .synth_adjust = NULL, | ||
130 | .read_buff_add = NULL, | ||
131 | .get_index = NULL, | ||
132 | .indexing = { | ||
133 | .command = NULL, | ||
134 | .lowindex = 0, | ||
135 | .highindex = 0, | ||
136 | .currindex = 0, | ||
137 | }, | ||
138 | .attributes = { | ||
139 | .attrs = synth_attrs, | ||
140 | .name = "decext", | ||
141 | }, | ||
142 | }; | ||
143 | |||
144 | static void do_catch_up(struct spk_synth *synth) | ||
145 | { | ||
146 | u_char ch; | ||
147 | static u_char last = '\0'; | ||
148 | unsigned long flags; | ||
149 | unsigned long jiff_max; | ||
150 | struct var_t *jiffy_delta; | ||
151 | struct var_t *delay_time; | ||
152 | int jiffy_delta_val = 0; | ||
153 | int delay_time_val = 0; | ||
154 | |||
155 | jiffy_delta = get_var(JIFFY); | ||
156 | delay_time = get_var(DELAY); | ||
157 | |||
158 | spk_lock(flags); | ||
159 | jiffy_delta_val = jiffy_delta->u.n.value; | ||
160 | spk_unlock(flags); | ||
161 | jiff_max = jiffies + jiffy_delta_val; | ||
162 | |||
163 | while (!kthread_should_stop()) { | ||
164 | spk_lock(flags); | ||
165 | if (speakup_info.flushing) { | ||
166 | speakup_info.flushing = 0; | ||
167 | spk_unlock(flags); | ||
168 | synth->flush(synth); | ||
169 | continue; | ||
170 | } | ||
171 | if (synth_buffer_empty()) { | ||
172 | spk_unlock(flags); | ||
173 | break; | ||
174 | } | ||
175 | ch = synth_buffer_peek(); | ||
176 | set_current_state(TASK_INTERRUPTIBLE); | ||
177 | delay_time_val = delay_time->u.n.value; | ||
178 | spk_unlock(flags); | ||
179 | if (ch == '\n') | ||
180 | ch = 0x0D; | ||
181 | if (synth_full() || !spk_serial_out(ch)) { | ||
182 | schedule_timeout(msecs_to_jiffies(delay_time_val)); | ||
183 | continue; | ||
184 | } | ||
185 | set_current_state(TASK_RUNNING); | ||
186 | spk_lock(flags); | ||
187 | synth_buffer_getc(); | ||
188 | spk_unlock(flags); | ||
189 | if (ch == '[') | ||
190 | in_escape = 1; | ||
191 | else if (ch == ']') | ||
192 | in_escape = 0; | ||
193 | else if (ch <= SPACE) { | ||
194 | if (!in_escape && strchr(",.!?;:", last)) | ||
195 | spk_serial_out(PROCSPEECH); | ||
196 | if (jiffies >= jiff_max) { | ||
197 | if ( ! in_escape ) | ||
198 | spk_serial_out(PROCSPEECH); | ||
199 | spk_lock(flags); | ||
200 | jiffy_delta_val = jiffy_delta->u.n.value; | ||
201 | delay_time_val = delay_time->u.n.value; | ||
202 | spk_unlock(flags); | ||
203 | schedule_timeout(msecs_to_jiffies(delay_time_val)); | ||
204 | jiff_max = jiffies + jiffy_delta_val; | ||
205 | } | ||
206 | } | ||
207 | last = ch; | ||
208 | } | ||
209 | if (!in_escape) | ||
210 | spk_serial_out(PROCSPEECH); | ||
211 | } | ||
212 | |||
213 | static void synth_flush(struct spk_synth *synth) | ||
214 | { | ||
215 | in_escape = 0; | ||
216 | spk_synth_immediate(synth, "\033P;10z\033\\"); | ||
217 | } | ||
218 | |||
219 | module_param_named(ser, synth_decext.ser, int, S_IRUGO); | ||
220 | module_param_named(start, synth_decext.startup, short, S_IRUGO); | ||
221 | |||
222 | MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); | ||
223 | MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); | ||
224 | |||
225 | static int __init decext_init(void) | ||
226 | { | ||
227 | return synth_add(&synth_decext); | ||
228 | } | ||
229 | |||
230 | static void __exit decext_exit(void) | ||
231 | { | ||
232 | synth_remove(&synth_decext); | ||
233 | } | ||
234 | |||
235 | module_init(decext_init); | ||
236 | module_exit(decext_exit); | ||
237 | MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>"); | ||
238 | MODULE_AUTHOR("David Borowski"); | ||
239 | MODULE_DESCRIPTION("Speakup support for DECtalk External synthesizers"); | ||
240 | MODULE_LICENSE("GPL"); | ||
241 | MODULE_VERSION(DRV_VERSION); | ||
242 | |||