aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/speakup/DefaultKeyAssignments46
-rw-r--r--drivers/staging/speakup/Kconfig195
-rw-r--r--drivers/staging/speakup/Makefile30
-rw-r--r--drivers/staging/speakup/TODO47
-rw-r--r--drivers/staging/speakup/buffers.c108
-rw-r--r--drivers/staging/speakup/devsynth.c92
-rw-r--r--drivers/staging/speakup/fakekey.c105
-rw-r--r--drivers/staging/speakup/i18n.c622
-rw-r--r--drivers/staging/speakup/i18n.h228
-rw-r--r--drivers/staging/speakup/keyhelp.c212
-rw-r--r--drivers/staging/speakup/kobjects.c1007
-rw-r--r--drivers/staging/speakup/main.c2304
-rw-r--r--drivers/staging/speakup/selection.c155
-rw-r--r--drivers/staging/speakup/serialio.c212
-rw-r--r--drivers/staging/speakup/serialio.h55
-rw-r--r--drivers/staging/speakup/speakup.h127
-rw-r--r--drivers/staging/speakup/speakup_acnt.h16
-rw-r--r--drivers/staging/speakup/speakup_acntpc.c327
-rw-r--r--drivers/staging/speakup/speakup_acntsa.c164
-rw-r--r--drivers/staging/speakup/speakup_apollo.c225
-rw-r--r--drivers/staging/speakup/speakup_audptr.c195
-rw-r--r--drivers/staging/speakup/speakup_bns.c147
-rw-r--r--drivers/staging/speakup/speakup_decext.c242
-rw-r--r--drivers/staging/speakup/speakup_decpc.c503
-rw-r--r--drivers/staging/speakup/speakup_dectlk.c315
-rw-r--r--drivers/staging/speakup/speakup_dtlk.c386
-rw-r--r--drivers/staging/speakup/speakup_dtlk.h54
-rw-r--r--drivers/staging/speakup/speakup_dummy.c148
-rw-r--r--drivers/staging/speakup/speakup_keypc.c327
-rw-r--r--drivers/staging/speakup/speakup_ltlk.c195
-rw-r--r--drivers/staging/speakup/speakup_soft.c366
-rw-r--r--drivers/staging/speakup/speakup_spkout.c165
-rw-r--r--drivers/staging/speakup/speakup_txprt.c147
-rw-r--r--drivers/staging/speakup/speakupmap.h65
-rw-r--r--drivers/staging/speakup/speakupmap.map93
-rw-r--r--drivers/staging/speakup/spk_priv.h93
-rw-r--r--drivers/staging/speakup/spk_priv_keyinfo.h110
-rw-r--r--drivers/staging/speakup/spk_types.h193
-rw-r--r--drivers/staging/speakup/spkguide.txt1575
-rw-r--r--drivers/staging/speakup/synth.c458
-rw-r--r--drivers/staging/speakup/thread.c58
-rw-r--r--drivers/staging/speakup/varhandlers.c403
44 files changed, 12518 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index a39f04f9a98..809673b60a7 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -173,5 +173,7 @@ source "drivers/staging/ft1000/Kconfig"
173 173
174source "drivers/staging/intel_sst/Kconfig" 174source "drivers/staging/intel_sst/Kconfig"
175 175
176source "drivers/staging/speakup/Kconfig"
177
176endif # !STAGING_EXCLUDE_BUILD 178endif # !STAGING_EXCLUDE_BUILD
177endif # STAGING 179endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index d071a19d831..a81af6d4948 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_USB_ENESTORAGE) += keucr/
67obj-$(CONFIG_BCM_WIMAX) += bcm/ 67obj-$(CONFIG_BCM_WIMAX) += bcm/
68obj-$(CONFIG_FT1000) += ft1000/ 68obj-$(CONFIG_FT1000) += ft1000/
69obj-$(CONFIG_SND_INTEL_SST) += intel_sst/ 69obj-$(CONFIG_SND_INTEL_SST) += intel_sst/
70obj-$(CONFIG_SPEAKUP) += speakup/
diff --git a/drivers/staging/speakup/DefaultKeyAssignments b/drivers/staging/speakup/DefaultKeyAssignments
new file mode 100644
index 00000000000..101c803b21f
--- /dev/null
+++ b/drivers/staging/speakup/DefaultKeyAssignments
@@ -0,0 +1,46 @@
1This file is intended to give you an overview of the default keys used
2by speakup for it's review functions. You may change them to be
3anything you want but that will take some familiarity with key
4mapping.
5
6We have remapped the insert or zero key on the keypad to act as a
7shift key. Well, actually as an altgr key. So in the following list
8InsKeyPad-period means hold down the insert key like a shift key and
9hit the keypad period.
10
11KeyPad-8 Say current Line
12InsKeyPad-8 say from top of screen to reading cursor.
13KeyPad-7 Say Previous Line (UP one line)
14KeyPad-9 Say Next Line (down one line)
15KeyPad-5 Say Current Word
16InsKeyPad-5 Spell Current Word
17KeyPad-4 Say Previous Word (left one word)
18InsKeyPad-4 say from left edge of line to reading cursor.
19KeyPad-6 Say Next Word (right one word)
20InsKeyPad-6 Say from reading cursor to right edge of line.
21KeyPad-2 Say Current Letter
22InsKeyPad-2 say current letter phonetically
23KeyPad-1 Say Previous Character (left one letter)
24KeyPad-3 Say Next Character (right one letter)
25KeyPad-plus Say Entire Screen
26InsKeyPad-plus Say from reading cursor line to bottom of screen.
27KeyPad-Minus Park reading cursor (toggle)
28InsKeyPad-minus Say character hex and decimal value.
29KeyPad-period Say Position (current line, position and console)
30InsKeyPad-period say colour attributes of current position.
31InsKeyPad-9 Move reading cursor to top of screen (insert pgup)
32InsKeyPad-3 Move reading cursor to bottom of screen (insert pgdn)
33InsKeyPad-7 Move reading cursor to left edge of screen (insert home)
34InsKeyPad-1 Move reading cursor to right edge of screen (insert end)
35ControlKeyPad-1 Move reading cursor to last character on current line.
36KeyPad-Enter Shut Up (until another key is hit) and sync reading cursor
37InsKeyPad-Enter Shut Up (until toggled back on).
38InsKeyPad-star n<x|y> go to line (y) or column (x). Where 'n' is any
39 allowed value for the row or column for your current screen.
40KeyPad-/ Mark and Cut screen region.
41InsKeyPad-/ Paste screen region into any console.
42
43Hitting any key while speakup is outputting speech will quiet the
44synth until it has caught up with what is being printed on the
45console.
46
diff --git a/drivers/staging/speakup/Kconfig b/drivers/staging/speakup/Kconfig
new file mode 100644
index 00000000000..d288cf03e14
--- /dev/null
+++ b/drivers/staging/speakup/Kconfig
@@ -0,0 +1,195 @@
1menu "Speakup console speech"
2
3config SPEAKUP
4 depends on VT
5 tristate "Speakup core"
6 ---help---
7 This is the Speakup screen reader. Think of it as a
8 video console for blind people. If built in to the
9 kernel, it can speak everything on the text console from
10 boot up to shutdown. For more information on Speakup,
11 point your browser at http://www.linux-speakup.org/.
12 There is also a mailing list at the above url that you
13 can subscribe to.
14
15 Supported synthesizers are accent sa, accent pc,
16 appollo II., Auddapter, Braille 'n Speak, Dectalk
17 external (old), Dectalk PC (full length isa board),
18 Dectalk express, Doubletalk, Doubletalk LT or
19 Litetalk, Keynote Gold internal PC, software
20 synthesizers, Speakout, transport, and a dummy module
21 that can be used with a plain text terminal.
22
23 Speakup can either be built in or compiled as a module
24 by answering y or m. If you answer y here, then you
25 must answer either y or m to at least one of the
26 synthesizer drivers below. If you answer m here, then
27 the synthesizer drivers below can only be built as
28 modules.
29
30 These drivers are not standalone drivers, but must be
31 used in conjunction with Speakup. Think of them as
32 video cards for blind people.
33
34
35 The Dectalk pc driver can only be built as a module, and
36 requires software to be pre-loaded on to the card before
37 the module can be loaded. See the decpc choice below
38 for more details.
39
40 If you are not a blind person, or don't have access to
41 one of the listed synthesizers, you should say n.
42
43if SPEAKUP
44config SPEAKUP_SYNTH_ACNTSA
45 tristate "Accent SA synthesizer support"
46 ---help---
47 This is the Speakup driver for the Accent SA
48 synthesizer. You can say y to build it into the kernel,
49 or m to build it as a module. See the configuration
50 help on the Speakup choice above for more info.
51
52config SPEAKUP_SYNTH_ACNTPC
53 tristate "Accent PC synthesizer support"
54 ---help---
55 This is the Speakup driver for the accent pc
56 synthesizer. You can say y to build it into the kernel,
57 or m to build it as a module. See the configuration
58 help on the Speakup choice above for more info.
59
60config SPEAKUP_SYNTH_APOLLO
61 tristate "Apollo II synthesizer support"
62 ---help---
63 This is the Speakup driver for the Apollo II
64 synthesizer. You can say y to build it into the kernel,
65 or m to build it as a module. See the configuration
66 help on the Speakup choice above for more info.
67
68config SPEAKUP_SYNTH_AUDPTR
69 tristate "Audapter synthesizer support"
70 ---help---
71 This is the Speakup driver for the Audapter synthesizer.
72 You can say y to build it into the kernel, or m to
73 build it as a module. See the configuration help on the
74 Speakup choice above for more info.
75
76config SPEAKUP_SYNTH_BNS
77 tristate "Braille 'n' Speak synthesizer support"
78 ---help---
79 This is the Speakup driver for the Braille 'n' Speak
80 synthesizer. You can say y to build it into the kernel,
81 or m to build it as a module. See the configuration
82 help on the Speakup choice above for more info.
83
84config SPEAKUP_SYNTH_DECTLK
85 tristate "DECtalk Express synthesizer support"
86 ---help---
87
88 This is the Speakup driver for the DecTalk Express
89 synthesizer. You can say y to build it into the kernel,
90 or m to build it as a module. See the configuration
91 help on the Speakup choice above for more info.
92
93config SPEAKUP_SYNTH_DECEXT
94 tristate "DECtalk External (old) synthesizer support"
95 ---help---
96
97 This is the Speakup driver for the DecTalk External
98 (old) synthesizer. You can say y to build it into the
99 kernel, or m to build it as a module. See the
100 configuration help on the Speakup choice above for more
101 info.
102
103config SPEAKUP_SYNTH_DECPC
104 depends on m
105 tristate "DECtalk PC (big ISA card) synthesizer support"
106 ---help---
107
108 This is the Speakup driver for the DecTalk PC (full
109 length ISA) synthesizer. You can say m to build it as
110 a module. See the configuration help on the Speakup
111 choice above for more info.
112
113 In order to use the DecTalk PC driver, you must download
114 the dec_pc.tgz file from linux-speakup.org. It is in
115 the pub/linux/goodies directory. The dec_pc.tgz file
116 contains the software which must be pre-loaded on to the
117 DecTalk PC board in order to use it with this driver.
118 This driver must be built as a module, and can not be
119 loaded until the file system is mounted and the DecTalk
120 PC software has been pre-loaded on to the board.
121
122 See the README file in the dec_pc.tgz file for more
123 details.
124
125config SPEAKUP_SYNTH_DTLK
126 tristate "DoubleTalk PC synthesizer support"
127 ---help---
128
129 This is the Speakup driver for the internal DoubleTalk
130 PC synthesizer. You can say y to build it into the
131 kernel, or m to build it as a module. See the
132 configuration help on the Speakup choice above for more
133 info.
134
135config SPEAKUP_SYNTH_KEYPC
136 tristate "Keynote Gold PC synthesizer support"
137 ---help---
138
139 This is the Speakup driver for the Keynote Gold
140 PC synthesizer. You can say y to build it into the
141 kernel, or m to build it as a module. See the
142 configuration help on the Speakup choice above for more
143 info.
144
145config SPEAKUP_SYNTH_LTLK
146 tristate "DoubleTalk LT/LiteTalk synthesizer support"
147---help---
148
149 This is the Speakup driver for the LiteTalk/DoubleTalk
150 LT synthesizer. You can say y to build it into the
151 kernel, or m to build it as a module. See the
152 configuration help on the Speakup choice above for more
153 info.
154
155config SPEAKUP_SYNTH_SOFT
156 tristate "Userspace software synthesizer support"
157 ---help---
158
159 This is the software synthesizer device node. It will
160 register a device /dev/softsynth which midware programs
161 and speech daemons may open and read to provide kernel
162 output to software synths such as espeak, festival,
163 flite and so forth. You can select 'y' or 'm' to have
164 it built-in to the kernel or loaded as a module.
165
166config SPEAKUP_SYNTH_SPKOUT
167 tristate "Speak Out synthesizer support"
168 ---help---
169
170 This is the Speakup driver for the Speakout synthesizer.
171 You can say y to build it into the kernel, or m to
172 build it as a module. See the configuration help on the
173 Speakup choice above for more info.
174
175config SPEAKUP_SYNTH_TXPRT
176 tristate "Transport synthesizer support"
177 ---help---
178
179 This is the Speakup driver for the Transport
180 synthesizer. You can say y to build it into the kernel,
181 or m to build it as a module. See the configuration
182 help on the Speakup choice above for more info.
183
184config SPEAKUP_SYNTH_DUMMY
185 tristate "Dummy synthesizer driver (for testing)"
186 ---help---
187
188 This is a dummy Speakup driver for plugging a mere serial
189 terminal. This is handy if you want to test speakup but
190 don't have the hardware. You can say y to build it into
191 the kernel, or m to build it as a module. See the
192 configuration help on the Speakup choice above for more info.
193
194endif # SPEAKUP
195endmenu
diff --git a/drivers/staging/speakup/Makefile b/drivers/staging/speakup/Makefile
new file mode 100644
index 00000000000..9923463687c
--- /dev/null
+++ b/drivers/staging/speakup/Makefile
@@ -0,0 +1,30 @@
1obj-$(CONFIG_SPEAKUP_SYNTH_ACNTSA) += speakup_acntsa.o
2obj-$(CONFIG_SPEAKUP_SYNTH_ACNTPC) += speakup_acntpc.o
3obj-$(CONFIG_SPEAKUP_SYNTH_APOLLO) += speakup_apollo.o
4obj-$(CONFIG_SPEAKUP_SYNTH_AUDPTR) += speakup_audptr.o
5obj-$(CONFIG_SPEAKUP_SYNTH_BNS) += speakup_bns.o
6obj-$(CONFIG_SPEAKUP_SYNTH_DECTLK) += speakup_dectlk.o
7obj-$(CONFIG_SPEAKUP_SYNTH_DECEXT) += speakup_decext.o
8obj-$(CONFIG_SPEAKUP_SYNTH_DECPC) += speakup_decpc.o
9obj-$(CONFIG_SPEAKUP_SYNTH_DTLK) += speakup_dtlk.o
10obj-$(CONFIG_SPEAKUP_SYNTH_KEYPC) += speakup_keypc.o
11obj-$(CONFIG_SPEAKUP_SYNTH_LTLK) += speakup_ltlk.o
12obj-$(CONFIG_SPEAKUP_SYNTH_SOFT) += speakup_soft.o
13obj-$(CONFIG_SPEAKUP_SYNTH_SPKOUT) += speakup_spkout.o
14obj-$(CONFIG_SPEAKUP_SYNTH_TXPRT) += speakup_txprt.o
15obj-$(CONFIG_SPEAKUP_SYNTH_DUMMY) += speakup_dummy.o
16
17obj-$(CONFIG_SPEAKUP) += speakup.o
18speakup-objs := \
19 buffers.o \
20 devsynth.o \
21 i18n.o \
22 fakekey.o \
23 main.o \
24 keyhelp.o \
25 kobjects.o \
26 selection.o \
27 serialio.o \
28 synth.o \
29 thread.o \
30 varhandlers.o
diff --git a/drivers/staging/speakup/TODO b/drivers/staging/speakup/TODO
new file mode 100644
index 00000000000..c3612e4b8ac
--- /dev/null
+++ b/drivers/staging/speakup/TODO
@@ -0,0 +1,47 @@
1Speakup project home: http://www.linux-speakup.org
2
3Mailing List: speakup@braille.uwo.ca
4
5Speakup is a kernel based screen review package for the linux operating
6system. It allows blind users to interact with applications on the
7linux console by means of synthetic speech.
8
9Currently, speakup has several issues we know of.
10
11The first issue has to do with the way speakup communicates with serial
12ports. Currently, we communicate directly with the hardware
13ports. This however conflicts with the standard serial port drivers,
14which poses various problems. This is also not working for modern hardware
15such as PCI-based serial ports. Also, there is not a way we can
16communicate with USB devices. The current serial port handling code is
17in serialio.c in this directory.
18
19Some places are currently using in_atomic() because speakup functions
20are called in various contexts, and a couple of things can't happen
21in these cases. Pushing work to some worker thread would probably help,
22as was already done for the serial port driving part.
23
24There is a duplication of the selection functions in selections.c. These
25functions should get exported from drivers/char/selection.c (clear_selection
26notably) and used from there instead.
27
28The kobjects may have to move to a more proper place in /sys. The
29discussion on lkml resulted to putting speech synthesizers in the
30"speech" class, and the speakup screen reader itself into
31/sys/class/vtconsole/vtcon0/speakup, the nasty path being handled by
32userland tools.
33
34Another issue seems to only happen on SMP systems. It seems
35that text in the output buffer gets garbled because a lock is not set.
36This bug happens regularly, but no one has been able to find a situation
37which produces it consistently.
38
39Patches, suggestions, corrections, etc, are definitely welcome.
40
41We prefer that you contact us on the mailing list; however, if you do
42not want to subscribe to a mailing list, send your email to all of the
43following:
44
45w.d.hubbs@gmail.com, chris@the-brannons.com, kirk@braille.uwo.ca and
46samuel.thibault@ens-lyon.org.
47
diff --git a/drivers/staging/speakup/buffers.c b/drivers/staging/speakup/buffers.c
new file mode 100644
index 00000000000..6dd53cf348f
--- /dev/null
+++ b/drivers/staging/speakup/buffers.c
@@ -0,0 +1,108 @@
1#include <linux/console.h>
2#include <linux/smp_lock.h>
3#include <linux/types.h>
4#include <linux/wait.h>
5
6#include "speakup.h"
7#include "spk_priv.h"
8
9#define synthBufferSize 8192 /* currently 8K bytes */
10
11static u_char synth_buffer[synthBufferSize]; /* guess what this is for! */
12static u_char *buff_in = synth_buffer;
13static u_char *buff_out = synth_buffer;
14static u_char *buffer_end = synth_buffer+synthBufferSize-1;
15
16/* These try to throttle applications by stopping the TTYs
17 * Note: we need to make sure that we will restart them eventually, which is
18 * usually not possible to do from the notifiers. TODO: it should be possible
19 * starting from linux 2.6.26.
20 *
21 * So we only stop when we know alive == 1 (else we discard the data anyway),
22 * and the alive synth will eventually call start_ttys from the thread context.
23 */
24void speakup_start_ttys(void)
25{
26 int i;
27
28 for (i = 0; i < MAX_NR_CONSOLES; i++) {
29 if (speakup_console[i] && speakup_console[i]->tty_stopped)
30 continue;
31 if ((vc_cons[i].d != NULL) && (vc_cons[i].d->vc_tty != NULL))
32 start_tty(vc_cons[i].d->vc_tty);
33 }
34}
35EXPORT_SYMBOL_GPL(speakup_start_ttys);
36
37static void speakup_stop_ttys(void)
38{
39 int i;
40
41 for (i = 0; i < MAX_NR_CONSOLES; i++)
42 if ((vc_cons[i].d != NULL) && (vc_cons[i].d->vc_tty != NULL))
43 stop_tty(vc_cons[i].d->vc_tty);
44 return;
45}
46
47static int synth_buffer_free(void)
48{
49 int bytesFree;
50
51 if (buff_in >= buff_out)
52 bytesFree = synthBufferSize - (buff_in - buff_out);
53 else
54 bytesFree = buff_out - buff_in;
55 return bytesFree;
56}
57
58int synth_buffer_empty(void)
59{
60 return (buff_in == buff_out);
61}
62EXPORT_SYMBOL_GPL(synth_buffer_empty);
63
64void synth_buffer_add(char ch)
65{
66 if (!synth->alive) {
67 /* This makes sure that we won't stop TTYs if there is no synth
68 * to restart them */
69 return;
70 }
71 if (synth_buffer_free() <= 100) {
72 synth_start();
73 speakup_stop_ttys();
74 }
75 if (synth_buffer_free() <= 1)
76 return;
77 *buff_in++ = ch;
78 if (buff_in > buffer_end)
79 buff_in = synth_buffer;
80}
81
82char synth_buffer_getc(void)
83{
84 char ch;
85
86 if (buff_out == buff_in)
87 return 0;
88 ch = *buff_out++;
89 if (buff_out > buffer_end)
90 buff_out = synth_buffer;
91 return ch;
92}
93EXPORT_SYMBOL_GPL(synth_buffer_getc);
94
95char synth_buffer_peek(void)
96{
97 if (buff_out == buff_in)
98 return 0;
99 return *buff_out;
100}
101EXPORT_SYMBOL_GPL(synth_buffer_peek);
102
103void synth_buffer_clear(void)
104{
105 buff_in = buff_out = synth_buffer;
106 return;
107}
108EXPORT_SYMBOL_GPL(synth_buffer_clear);
diff --git a/drivers/staging/speakup/devsynth.c b/drivers/staging/speakup/devsynth.c
new file mode 100644
index 00000000000..a4656533dd5
--- /dev/null
+++ b/drivers/staging/speakup/devsynth.c
@@ -0,0 +1,92 @@
1#include <linux/errno.h>
2#include <linux/miscdevice.h> /* for misc_register, and SYNTH_MINOR */
3#include <linux/types.h>
4#include <linux/uaccess.h>
5
6#include "speakup.h"
7#include "spk_priv.h"
8
9#ifndef SYNTH_MINOR
10#define SYNTH_MINOR 25
11#endif
12
13static int misc_registered;
14static int dev_opened;
15
16static ssize_t speakup_file_write(struct file *fp, const char *buffer,
17 size_t nbytes, loff_t *ppos)
18{
19 size_t count = nbytes;
20 const char *ptr = buffer;
21 int bytes;
22 unsigned long flags;
23 u_char buf[256];
24 if (synth == NULL)
25 return -ENODEV;
26 while (count > 0) {
27 bytes = min_t(size_t, count, sizeof(buf));
28 if (copy_from_user(buf, ptr, bytes))
29 return -EFAULT;
30 count -= bytes;
31 ptr += bytes;
32 spk_lock(flags);
33 synth_write(buf, bytes);
34 spk_unlock(flags);
35 }
36 return (ssize_t) nbytes;
37}
38
39static ssize_t speakup_file_read(struct file *fp, char *buf, size_t nbytes, loff_t *ppos)
40{
41 return 0;
42}
43
44static int speakup_file_open(struct inode *ip, struct file *fp)
45{
46 if (synth == NULL)
47 return -ENODEV;
48 if (xchg(&dev_opened, 1))
49 return -EBUSY;
50 return 0;
51}
52
53static int speakup_file_release(struct inode *ip, struct file *fp)
54{
55 dev_opened = 0;
56 return 0;
57}
58
59static struct file_operations synth_fops = {
60 .read = speakup_file_read,
61 .write = speakup_file_write,
62 .open = speakup_file_open,
63 .release = speakup_file_release,
64};
65
66static struct miscdevice synth_device = {
67 .minor = SYNTH_MINOR,
68 .name = "synth",
69 .fops = &synth_fops,
70};
71
72void speakup_register_devsynth(void)
73{
74 if (misc_registered != 0)
75 return;
76/* zero it so if register fails, deregister will not ref invalid ptrs */
77 if (misc_register(&synth_device))
78 pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
79 else {
80 pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n", MISC_MAJOR, SYNTH_MINOR);
81 misc_registered = 1;
82 }
83}
84
85void speakup_unregister_devsynth(void)
86{
87 if (!misc_registered)
88 return;
89 pr_info("speakup: unregistering synth device /dev/synth\n");
90 misc_deregister(&synth_device);
91 misc_registered = 0;
92}
diff --git a/drivers/staging/speakup/fakekey.c b/drivers/staging/speakup/fakekey.c
new file mode 100644
index 00000000000..adb93f21c0d
--- /dev/null
+++ b/drivers/staging/speakup/fakekey.c
@@ -0,0 +1,105 @@
1/* fakekey.c
2 * Functions for simulating keypresses.
3 *
4 * Copyright (C) 2010 the Speakup Team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <linux/types.h>
21#include <linux/slab.h>
22#include <linux/preempt.h>
23#include <linux/percpu.h>
24#include <linux/input.h>
25
26#include "speakup.h"
27
28#define PRESSED 1
29#define RELEASED 0
30
31DEFINE_PER_CPU(bool, reporting_keystroke);
32
33static struct input_dev *virt_keyboard;
34
35int speakup_add_virtual_keyboard(void)
36{
37 int err;
38
39 virt_keyboard = input_allocate_device();
40
41 if (!virt_keyboard)
42 return -ENOMEM;
43
44 virt_keyboard->name = "Speakup";
45 virt_keyboard->id.bustype = BUS_VIRTUAL;
46 virt_keyboard->phys = "speakup/input0";
47 virt_keyboard->dev.parent = NULL;
48
49 __set_bit(EV_KEY, virt_keyboard->evbit);
50 __set_bit(KEY_DOWN, virt_keyboard->keybit);
51
52 err = input_register_device(virt_keyboard);
53 if (err) {
54 input_free_device(virt_keyboard);
55 virt_keyboard = NULL;
56 }
57
58 return err;
59}
60
61void speakup_remove_virtual_keyboard(void)
62{
63 if (virt_keyboard != NULL) {
64 input_unregister_device(virt_keyboard);
65 input_free_device(virt_keyboard);
66 virt_keyboard = NULL;
67 }
68}
69
70/*
71 * Send a simulated down-arrow to the application.
72 */
73void speakup_fake_down_arrow(void)
74{
75 unsigned long flags;
76
77 /* disable keyboard interrupts */
78 local_irq_save(flags);
79 /* don't change CPU */
80 preempt_disable();
81
82 __get_cpu_var(reporting_keystroke) = true;
83 input_report_key(virt_keyboard, KEY_DOWN, PRESSED);
84 input_report_key(virt_keyboard, KEY_DOWN, RELEASED);
85 __get_cpu_var(reporting_keystroke) = false;
86
87 /* reenable preemption */
88 preempt_enable();
89 /* reenable keyboard interrupts */
90 local_irq_restore(flags);
91}
92
93/*
94 * Are we handling a simulated keypress on the current CPU?
95 * Returns a boolean.
96 */
97bool speakup_fake_key_pressed(void)
98{
99 bool is_pressed;
100
101 is_pressed = get_cpu_var(reporting_keystroke);
102 put_cpu_var(reporting_keystroke);
103
104 return is_pressed;
105}
diff --git a/drivers/staging/speakup/i18n.c b/drivers/staging/speakup/i18n.c
new file mode 100644
index 00000000000..4d12d0ae3bc
--- /dev/null
+++ b/drivers/staging/speakup/i18n.c
@@ -0,0 +1,622 @@
1/* Internationalization implementation. Includes definitions of English
2 * string arrays, and the i18n pointer. */
3
4#include <linux/slab.h> /* For kmalloc. */
5#include <linux/ctype.h>
6#include <linux/module.h>
7#include <linux/string.h>
8#include "speakup.h"
9#include "spk_priv.h"
10
11static char *speakup_msgs[MSG_LAST_INDEX];
12static char *speakup_default_msgs [MSG_LAST_INDEX] = {
13 [MSG_BLANK] = "blank",
14 [MSG_IAM_ALIVE] = "I'm aLive!",
15 [MSG_YOU_KILLED_SPEAKUP] = "You killed speakup!",
16 [MSG_HEY_THATS_BETTER] = "hey. That's better!",
17 [MSG_YOU_TURNED_ME_OFF] = "You turned me off!",
18 [MSG_PARKED] = "parked!",
19 [MSG_UNPARKED] = "unparked!",
20 [MSG_MARK] = "mark",
21 [MSG_CUT] = "cut",
22 [MSG_MARK_CLEARED] = "mark, cleared",
23 [MSG_PASTE] = "paste",
24 [MSG_BRIGHT] = "bright",
25 [MSG_ON_BLINKING] = "on blinking",
26 [MSG_OFF] = "off",
27 [MSG_ON] = "on",
28 [MSG_NO_WINDOW] = "no window",
29 [MSG_CURSORING_OFF] = "cursoring off",
30 [MSG_CURSORING_ON] = "cursoring on",
31 [MSG_HIGHLIGHT_TRACKING] = "highlight tracking",
32 [MSG_READ_WINDOW] = "read windo",
33 [MSG_READ_ALL] = "read all",
34 [MSG_EDIT_DONE] = "edit done",
35 [MSG_WINDOW_ALREADY_SET] = "window already set, clear then reset",
36 [MSG_END_BEFORE_START] = "error end before start",
37 [MSG_WINDOW_CLEARED] = "window cleared",
38 [MSG_WINDOW_SILENCED] = "window silenced",
39 [MSG_WINDOW_SILENCE_DISABLED] = "window silence disabled",
40 [MSG_ERROR] = "error",
41 [MSG_GOTO_CANCELED] = "goto canceled",
42 [MSG_GOTO] = "go to?",
43 [MSG_LEAVING_HELP] = "leaving help",
44 [MSG_IS_UNASSIGNED] = "is unassigned",
45 [MSG_HELP_INFO] = "press space to leav help, cursor up or down to scroll, or a letter to go to commands in list",
46 [MSG_EDGE_TOP] = "top,",
47 [MSG_EDGE_BOTTOM] = "bottom,",
48 [MSG_EDGE_LEFT] = "left,",
49 [MSG_EDGE_RIGHT] = "right,",
50 [MSG_NUMBER] = "number",
51 [MSG_SPACE] = "space",
52 [MSG_START] = "start",
53 [MSG_END] = "end",
54 [MSG_CTRL] = "control-",
55 [MSG_DISJUNCTION] = "or",
56
57/* Messages with embedded format specifiers. */
58 [MSG_POS_INFO] = "line %ld, col %ld, t t y %d",
59 [MSG_CHAR_INFO] = "hex %02x, decimal %d",
60 [MSG_REPEAT_DESC] = "times %d .",
61 [MSG_REPEAT_DESC2] = "repeated %d .",
62 [MSG_WINDOW_LINE] = "window is line %d",
63 [MSG_WINDOW_BOUNDARY] = "%s at line %d, column %d",
64 [MSG_EDIT_PROMPT] = "edit %s, press space when done",
65 [MSG_NO_COMMAND] = "no commands for %c",
66 [MSG_KEYDESC] = "is %s",
67
68 /* Control keys. */
69 /* Most of these duplicate the entries in state names. */
70 [MSG_CTL_SHIFT] = "shift",
71 [MSG_CTL_ALTGR] = "altgr",
72 [MSG_CTL_CONTROL] = "control",
73 [MSG_CTL_ALT] = "ault",
74 [MSG_CTL_LSHIFT] = "l shift",
75 [MSG_CTL_SPEAKUP] = "speakup",
76 [MSG_CTL_LCONTROL] = "l control",
77 [MSG_CTL_RCONTROL] = "r control",
78 [MSG_CTL_CAPSSHIFT] = "caps shift",
79
80 /* Color names. */
81 [MSG_COLOR_BLACK] = "black",
82 [MSG_COLOR_BLUE] = "blue",
83 [MSG_COLOR_GREEN] = "green",
84 [MSG_COLOR_CYAN] = "cyan",
85 [MSG_COLOR_RED] = "red",
86 [MSG_COLOR_MAGENTA] = "magenta",
87 [MSG_COLOR_YELLOW] = "yellow",
88 [MSG_COLOR_WHITE] = "white",
89 [MSG_COLOR_GREY] = "grey",
90
91 /* Names of key states. */
92 [MSG_STATE_DOUBLE] = "double",
93 [MSG_STATE_SPEAKUP] = "speakup",
94 [MSG_STATE_ALT] = "alt",
95 [MSG_STATE_CONTROL] = "ctrl",
96 [MSG_STATE_ALTGR] = "altgr",
97 [MSG_STATE_SHIFT] = "shift",
98
99 /* Key names. */
100 [MSG_KEYNAME_ESC] = "escape",
101 [MSG_KEYNAME_1] = "1",
102 [MSG_KEYNAME_2] = "2",
103 [MSG_KEYNAME_3] = "3",
104 [MSG_KEYNAME_4] = "4",
105 [MSG_KEYNAME_5] = "5",
106 [MSG_KEYNAME_6] = "6",
107 [MSG_KEYNAME_7] = "7",
108 [MSG_KEYNAME_8] = "8",
109 [MSG_KEYNAME_9] = "9",
110 [MSG_KEYNAME_0] = "0",
111 [MSG_KEYNAME_DASH] = "minus",
112 [MSG_KEYNAME_EQUAL] = "equal",
113 [MSG_KEYNAME_BS] = "back space",
114 [MSG_KEYNAME_TAB] = "tab",
115 [MSG_KEYNAME_Q] = "q",
116 [MSG_KEYNAME_W] = "w",
117 [MSG_KEYNAME_E] = "e",
118 [MSG_KEYNAME_R] = "r",
119 [MSG_KEYNAME_T] = "t",
120 [MSG_KEYNAME_Y] = "y",
121 [MSG_KEYNAME_U] = "u",
122 [MSG_KEYNAME_I] = "i",
123 [MSG_KEYNAME_O] = "o",
124 [MSG_KEYNAME_P] = "p",
125 [MSG_KEYNAME_LEFTBRACE] = "left brace",
126 [MSG_KEYNAME_RIGHTBRACE] = "right brace",
127 [MSG_KEYNAME_ENTER] = "enter",
128 [MSG_KEYNAME_LEFTCTRL] = "left control",
129 [MSG_KEYNAME_A] = "a",
130 [MSG_KEYNAME_S] = "s",
131 [MSG_KEYNAME_D] = "d",
132 [MSG_KEYNAME_F] = "f",
133 [MSG_KEYNAME_G] = "g",
134 [MSG_KEYNAME_H] = "h",
135 [MSG_KEYNAME_J] = "j",
136 [MSG_KEYNAME_K] = "k",
137 [MSG_KEYNAME_L] = "l",
138 [MSG_KEYNAME_SEMICOLON] = "semicolon",
139 [MSG_KEYNAME_SINGLEQUOTE] = "apostrophe",
140 [MSG_KEYNAME_GRAVE] = "accent",
141 [MSG_KEYNAME_LEFTSHFT] = "left shift",
142 [MSG_KEYNAME_BACKSLASH] = "back slash",
143 [MSG_KEYNAME_Z] = "z",
144 [MSG_KEYNAME_X] = "x",
145 [MSG_KEYNAME_C] = "c",
146 [MSG_KEYNAME_V] = "v",
147 [MSG_KEYNAME_B] = "b",
148 [MSG_KEYNAME_N] = "n",
149 [MSG_KEYNAME_M] = "m",
150 [MSG_KEYNAME_COMMA] = "comma",
151 [MSG_KEYNAME_DOT] = "dot",
152 [MSG_KEYNAME_SLASH] = "slash",
153 [MSG_KEYNAME_RIGHTSHFT] = "right shift",
154 [MSG_KEYNAME_KPSTAR] = "keypad asterisk",
155 [MSG_KEYNAME_LEFTALT] = "left alt",
156 [MSG_KEYNAME_SPACE] = "space",
157 [MSG_KEYNAME_CAPSLOCK] = "caps lock",
158 [MSG_KEYNAME_F1] = "f1",
159 [MSG_KEYNAME_F2] = "f2",
160 [MSG_KEYNAME_F3] = "f3",
161 [MSG_KEYNAME_F4] = "f4",
162 [MSG_KEYNAME_F5] = "f5",
163 [MSG_KEYNAME_F6] = "f6",
164 [MSG_KEYNAME_F7] = "f7",
165 [MSG_KEYNAME_F8] = "f8",
166 [MSG_KEYNAME_F9] = "f9",
167 [MSG_KEYNAME_F10] = "f10",
168 [MSG_KEYNAME_NUMLOCK] = "num lock",
169 [MSG_KEYNAME_SCROLLLOCK] = "scroll lock",
170 [MSG_KEYNAME_KP7] = "keypad 7",
171 [MSG_KEYNAME_KP8] = "keypad 8",
172 [MSG_KEYNAME_KP9] = "keypad 9",
173 [MSG_KEYNAME_KPMINUS] = "keypad minus",
174 [MSG_KEYNAME_KP4] = "keypad 4",
175 [MSG_KEYNAME_KP5] = "keypad 5",
176 [MSG_KEYNAME_KP6] = "keypad 6",
177 [MSG_KEYNAME_KPPLUS] = "keypad plus",
178 [MSG_KEYNAME_KP1] = "keypad 1",
179 [MSG_KEYNAME_KP2] = "keypad 2",
180 [MSG_KEYNAME_KP3] = "keypad 3",
181 [MSG_KEYNAME_KP0] = "keypad 0",
182 [MSG_KEYNAME_KPDOT] = "keypad dot",
183 [MSG_KEYNAME_103RD] = "103rd",
184 [MSG_KEYNAME_F13] = "f13",
185 [MSG_KEYNAME_102ND] = "102nd",
186 [MSG_KEYNAME_F11] = "f11",
187 [MSG_KEYNAME_F12] = "f12",
188 [MSG_KEYNAME_F14] = "f14",
189 [MSG_KEYNAME_F15] = "f15",
190 [MSG_KEYNAME_F16] = "f16",
191 [MSG_KEYNAME_F17] = "f17",
192 [MSG_KEYNAME_F18] = "f18",
193 [MSG_KEYNAME_F19] = "f19",
194 [MSG_KEYNAME_F20] = "f20",
195 [MSG_KEYNAME_KPENTER] = "keypad enter",
196 [MSG_KEYNAME_RIGHTCTRL] = "right control",
197 [MSG_KEYNAME_KPSLASH] = "keypad slash",
198 [MSG_KEYNAME_SYSRQ] = "sysrq",
199 [MSG_KEYNAME_RIGHTALT] = "right alt",
200 [MSG_KEYNAME_LF] = "line feed",
201 [MSG_KEYNAME_HOME] = "home",
202 [MSG_KEYNAME_UP] = "up",
203 [MSG_KEYNAME_PGUP] = "page up",
204 [MSG_KEYNAME_LEFT] = "left",
205 [MSG_KEYNAME_RIGHT] = "right",
206 [MSG_KEYNAME_END] = "end",
207 [MSG_KEYNAME_DOWN] = "down",
208 [MSG_KEYNAME_PGDN] = "page down",
209 [MSG_KEYNAME_INS] = "insert",
210 [MSG_KEYNAME_DEL] = "delete",
211 [MSG_KEYNAME_MACRO] = "macro",
212 [MSG_KEYNAME_MUTE] = "mute",
213 [MSG_KEYNAME_VOLDOWN] = "volume down",
214 [MSG_KEYNAME_VOLUP] = "volume up",
215 [MSG_KEYNAME_POWER] = "power",
216 [MSG_KEYNAME_KPEQUAL] = "keypad equal",
217 [MSG_KEYNAME_KPPLUSDASH] = "keypad plusminus",
218 [MSG_KEYNAME_PAUSE] = "pause",
219 [MSG_KEYNAME_F21] = "f21",
220 [MSG_KEYNAME_F22] = "f22",
221 [MSG_KEYNAME_F23] = "f23",
222 [MSG_KEYNAME_F24] = "f24",
223 [MSG_KEYNAME_KPCOMMA] = "keypad comma",
224 [MSG_KEYNAME_LEFTMETA] = "left meta",
225 [MSG_KEYNAME_RIGHTMETA] = "right meta",
226 [MSG_KEYNAME_COMPOSE] = "compose",
227 [MSG_KEYNAME_STOP] = "stop",
228 [MSG_KEYNAME_AGAIN] = "again",
229 [MSG_KEYNAME_PROPS] = "props",
230 [MSG_KEYNAME_UNDO] = "undo",
231 [MSG_KEYNAME_FRONT] = "front",
232 [MSG_KEYNAME_COPY] = "copy",
233 [MSG_KEYNAME_OPEN] = "open",
234 [MSG_KEYNAME_PASTE] = "paste",
235 [MSG_KEYNAME_FIND] = "find",
236 [MSG_KEYNAME_CUT] = "cut",
237 [MSG_KEYNAME_HELP] = "help",
238 [MSG_KEYNAME_MENU] = "menu",
239 [MSG_KEYNAME_CALC] = "calc",
240 [MSG_KEYNAME_SETUP] = "setup",
241 [MSG_KEYNAME_SLEEP] = "sleep",
242 [MSG_KEYNAME_WAKEUP] = "wakeup",
243 [MSG_KEYNAME_FILE] = "file",
244 [MSG_KEYNAME_SENDFILE] = "send file",
245 [MSG_KEYNAME_DELFILE] = "delete file",
246 [MSG_KEYNAME_XFER] = "transfer",
247 [MSG_KEYNAME_PROG1] = "prog1",
248 [MSG_KEYNAME_PROG2] = "prog2",
249 [MSG_KEYNAME_WWW] = "www",
250 [MSG_KEYNAME_MSDOS] = "msdos",
251 [MSG_KEYNAME_COFFEE] = "coffee",
252 [MSG_KEYNAME_DIRECTION] = "direction",
253 [MSG_KEYNAME_CYCLEWINDOWS] = "cycle windows",
254 [MSG_KEYNAME_MAIL] = "mail",
255 [MSG_KEYNAME_BOOKMARKS] = "bookmarks",
256 [MSG_KEYNAME_COMPUTER] = "computer",
257 [MSG_KEYNAME_BACK] = "back",
258 [MSG_KEYNAME_FORWARD] = "forward",
259 [MSG_KEYNAME_CLOSECD] = "close cd",
260 [MSG_KEYNAME_EJECTCD] = "eject cd",
261 [MSG_KEYNAME_EJECTCLOSE] = "eject close cd",
262 [MSG_KEYNAME_NEXTSONG] = "next song",
263 [MSG_KEYNAME_PLAYPAUSE] = "play pause",
264 [MSG_KEYNAME_PREVSONG] = "previous song",
265 [MSG_KEYNAME_STOPCD] = "stop cd",
266 [MSG_KEYNAME_RECORD] = "record",
267 [MSG_KEYNAME_REWIND] = "rewind",
268 [MSG_KEYNAME_PHONE] = "phone",
269 [MSG_KEYNAME_ISO] = "iso",
270 [MSG_KEYNAME_CONFIG] = "config",
271 [MSG_KEYNAME_HOMEPG] = "home page",
272 [MSG_KEYNAME_REFRESH] = "refresh",
273 [MSG_KEYNAME_EXIT] = "exit",
274 [MSG_KEYNAME_MOVE] = "move",
275 [MSG_KEYNAME_EDIT] = "edit",
276 [MSG_KEYNAME_SCROLLUP] = "scroll up",
277 [MSG_KEYNAME_SCROLLDN] = "scroll down",
278 [MSG_KEYNAME_KPLEFTPAR] = "keypad left paren",
279 [MSG_KEYNAME_KPRIGHTPAR] = "keypad right paren",
280
281 /* Function names. */
282 [MSG_FUNCNAME_ATTRIB_BLEEP_DEC] = "attribute bleep decrement",
283 [MSG_FUNCNAME_ATTRIB_BLEEP_INC] = "attribute bleep increment",
284 [MSG_FUNCNAME_BLEEPS_DEC] = "bleeps decrement",
285 [MSG_FUNCNAME_BLEEPS_INC] = "bleeps increment",
286 [MSG_FUNCNAME_CHAR_FIRST] = "character, first",
287 [MSG_FUNCNAME_CHAR_LAST] = "character, last",
288 [MSG_FUNCNAME_CHAR_CURRENT] = "character, say current",
289 [MSG_FUNCNAME_CHAR_HEX_AND_DEC] = "character, say hex and decimal",
290 [MSG_FUNCNAME_CHAR_NEXT] = "character, say next",
291 [MSG_FUNCNAME_CHAR_PHONETIC] = "character, say phonetic",
292 [MSG_FUNCNAME_CHAR_PREVIOUS] = "character, say previous",
293 [MSG_FUNCNAME_CURSOR_PARK] = "cursor park",
294 [MSG_FUNCNAME_CUT] = "cut",
295 [MSG_FUNCNAME_EDIT_DELIM] = "edit delimiters",
296 [MSG_FUNCNAME_EDIT_EXNUM] = "edit exnum",
297 [MSG_FUNCNAME_EDIT_MOST] = "edit most",
298 [MSG_FUNCNAME_EDIT_REPEATS] = "edit repeats",
299 [MSG_FUNCNAME_EDIT_SOME] = "edit some",
300 [MSG_FUNCNAME_GOTO] = "go to",
301 [MSG_FUNCNAME_GOTO_BOTTOM] = "go to bottom edge",
302 [MSG_FUNCNAME_GOTO_LEFT] = "go to left edge",
303 [MSG_FUNCNAME_GOTO_RIGHT] = "go to right edge",
304 [MSG_FUNCNAME_GOTO_TOP] = "go to top edge",
305 [MSG_FUNCNAME_HELP] = "help",
306 [MSG_FUNCNAME_LINE_SAY_CURRENT] = "line, say current",
307 [MSG_FUNCNAME_LINE_SAY_NEXT] = "line, say next",
308 [MSG_FUNCNAME_LINE_SAY_PREVIOUS] = "line, say previous",
309 [MSG_FUNCNAME_LINE_SAY_WITH_INDENT] = "line, say with indent",
310 [MSG_FUNCNAME_PASTE] = "paste",
311 [MSG_FUNCNAME_PITCH_DEC] = "pitch decrement",
312 [MSG_FUNCNAME_PITCH_INC] = "pitch increment",
313 [MSG_FUNCNAME_PUNC_DEC] = "punctuation decrement",
314 [MSG_FUNCNAME_PUNC_INC] = "punctuation increment",
315 [MSG_FUNCNAME_PUNC_LEVEL_DEC] = "punc level decrement",
316 [MSG_FUNCNAME_PUNC_LEVEL_INC] = "punc level increment",
317 [MSG_FUNCNAME_QUIET] = "quiet",
318 [MSG_FUNCNAME_RATE_DEC] = "rate decrement",
319 [MSG_FUNCNAME_RATE_INC] = "rate increment",
320 [MSG_FUNCNAME_READING_PUNC_DEC] = "reading punctuation decrement",
321 [MSG_FUNCNAME_READING_PUNC_INC] = "reading punctuation increment",
322 [MSG_FUNCNAME_SAY_ATTRIBUTES] = "say attributes",
323 [MSG_FUNCNAME_SAY_FROM_LEFT] = "say from left",
324 [MSG_FUNCNAME_SAY_FROM_TOP] = "say from top",
325 [MSG_FUNCNAME_SAY_POSITION] = "say position",
326 [MSG_FUNCNAME_SAY_SCREEN] = "say screen",
327 [MSG_FUNCNAME_SAY_TO_BOTTOM] = "say to bottom",
328 [MSG_FUNCNAME_SAY_TO_RIGHT] = "say to right",
329 [MSG_FUNCNAME_SPEAKUP] = "speakup",
330 [MSG_FUNCNAME_SPEAKUP_LOCK] = "speakup lock",
331 [MSG_FUNCNAME_SPEAKUP_OFF] = "speakup off",
332 [MSG_FUNCNAME_SPEECH_KILL] = "speech kill",
333 [MSG_FUNCNAME_SPELL_DELAY_DEC] = "spell delay decrement",
334 [MSG_FUNCNAME_SPELL_DELAY_INC] = "spell delay increment",
335 [MSG_FUNCNAME_SPELL_WORD] = "spell word",
336 [MSG_FUNCNAME_SPELL_WORD_PHONETICALLY] = "spell word phoneticly",
337 [MSG_FUNCNAME_TONE_DEC] = "tone decrement",
338 [MSG_FUNCNAME_TONE_INC] = "tone increment",
339 [MSG_FUNCNAME_VOICE_DEC] = "voice decrement",
340 [MSG_FUNCNAME_VOICE_INC] = "voice increment",
341 [MSG_FUNCNAME_VOLUME_DEC] = "volume decrement",
342 [MSG_FUNCNAME_VOLUME_INC] = "volume increment",
343 [MSG_FUNCNAME_WINDOW_CLEAR] = "window, clear",
344 [MSG_FUNCNAME_WINDOW_SAY] = "window, say",
345 [MSG_FUNCNAME_WINDOW_SET] = "window, set",
346 [MSG_FUNCNAME_WINDOW_SILENCE] = "window, silence",
347 [MSG_FUNCNAME_WORD_SAY_CURRENT] = "word, say current",
348 [MSG_FUNCNAME_WORD_SAY_NEXT] = "word, say next",
349 [MSG_FUNCNAME_WORD_SAY_PREVIOUS] = "word, say previous",
350};
351
352static struct msg_group_t all_groups [] = {
353 {
354 .name = "ctl_keys",
355 .start = MSG_CTL_START,
356 .end = MSG_CTL_END,
357 },
358 {
359 .name = "colors",
360 .start = MSG_COLORS_START,
361 .end = MSG_COLORS_END,
362 },
363 {
364 .name = "formatted",
365 .start = MSG_FORMATTED_START,
366 .end = MSG_FORMATTED_END,
367 },
368 {
369 .name = "function_names",
370 .start = MSG_FUNCNAMES_START,
371 .end = MSG_FUNCNAMES_END,
372 },
373 {
374 .name = "key_names",
375 .start = MSG_KEYNAMES_START,
376 .end = MSG_KEYNAMES_END,
377 },
378 {
379 .name = "announcements",
380 .start = MSG_ANNOUNCEMENTS_START,
381 .end = MSG_ANNOUNCEMENTS_END,
382 },
383 {
384 .name = "states",
385 .start = MSG_STATES_START,
386 .end = MSG_STATES_END,
387 },
388};
389
390static const int num_groups = sizeof(all_groups) / sizeof(struct msg_group_t);
391
392char *msg_get(enum msg_index_t index)
393{
394 char *ch;
395
396 ch = speakup_msgs[index];
397 return ch;
398}
399
400/*
401 * Function: next_specifier
402 * Finds the start of the next format specifier in the argument string.
403 * Return value: pointer to start of format
404 * specifier, or NULL if no specifier exists.
405*/
406static char *next_specifier(char *input)
407{
408 int found = 0;
409 char *next_percent = input;
410
411 while ((next_percent != NULL) && !found) {
412 next_percent = strchr(next_percent, '%');
413 if (next_percent != NULL) {
414 while ((next_percent[0] == '%')
415 && (next_percent[1] == '%'))
416 next_percent += 2; /* Advance over doubled percent signs. */
417 if (*next_percent == '%')
418 found = 1;
419 else if (*next_percent == '\0')
420 next_percent = NULL;
421 }
422 }
423
424 return next_percent;
425}
426
427/* Skip over 0 or more flags. */
428static char *skip_flags(char *input)
429{
430 while ((*input != '\0') && strchr(" 0+-#", *input))
431 input++;
432 return input;
433}
434
435/* Skip over width.precision, if it exists. */
436static char *skip_width(char *input)
437{
438 while (isdigit(*input))
439 input++;
440 if (*input == '.') {
441 input++;
442 while (isdigit(*input))
443 input++;
444 }
445 return input;
446}
447
448/*
449 * Skip past the end of the conversion part.
450 * Note that this code only accepts a handful of conversion specifiers:
451 * c d s x and ld. Not accidental; these are exactly the ones used in
452 * the default group of formatted messages.
453*/
454static char *skip_conversion(char *input)
455{
456 if ((input[0] == 'l') && (input[1] == 'd'))
457 input += 2;
458 else if ((*input != '\0') && strchr("cdsx", *input))
459 input++;
460 return input;
461}
462
463/*
464 * Function: find_specifier_end
465 * Return a pointer to the end of the format specifier.
466*/
467static char *find_specifier_end(char *input)
468{
469 input++; /* Advance over %. */
470 input = skip_flags(input);
471 input = skip_width(input);
472 input = skip_conversion(input);
473 return input;
474}
475
476/*
477 * Function: compare_specifiers
478 * Compare the format specifiers pointed to by *input1 and *input2.
479 * Return 1 if they are the same, 0 otherwise. Advance *input1 and *input2
480 * so that they point to the character following the end of the specifier.
481*/
482static int compare_specifiers(char **input1, char **input2)
483{
484 int same = 0;
485 char *end1 = find_specifier_end(*input1);
486 char *end2 = find_specifier_end(*input2);
487 size_t length1 = end1 - *input1;
488 size_t length2 = end2 - *input2;
489
490 if((length1 == length2) && !memcmp(*input1, *input2, length1))
491 same = 1;
492
493 *input1 = end1;
494 *input2 = end2;
495 return same;
496}
497
498/*
499 * Function: fmt_validate
500 * Check that two format strings contain the same number of format specifiers,
501 * and that the order of specifiers is the same in both strings.
502 * Return 1 if the condition holds, 0 if it doesn't.
503*/
504static int fmt_validate(char *template, char *user)
505{
506 int valid = 1;
507 int still_comparing = 1;
508 char *template_ptr = template;
509 char *user_ptr = user;
510
511 while (still_comparing && valid) {
512 template_ptr = next_specifier(template_ptr);
513 user_ptr = next_specifier(user_ptr);
514 if (template_ptr && user_ptr) {
515/* Both have at least one more specifier. */
516 valid = compare_specifiers(&template_ptr, &user_ptr);
517 } else {
518/* No more format specifiers in one or both of the strings. */
519 still_comparing = 0;
520 if (template_ptr || user_ptr)
521 valid = 0; /* One has more specifiers than the other. */
522 }
523 }
524 return valid;
525}
526
527/*
528 * Function: msg_set
529 * Description: Add a user-supplied message to the user_messages array.
530 * The message text is copied to a memory area allocated with kmalloc.
531 * If the function fails, then user_messages is untouched.
532 * Arguments:
533 * - index: a message number, as found in i18n.h.
534 * - text: text of message. Not NUL-terminated.
535 * - length: number of bytes in text.
536 * Failure conditions:
537 * -EINVAL - Invalid format specifiers in formatted message or illegal index.
538 * -ENOMEM - Unable to allocate memory.
539*/
540ssize_t msg_set(enum msg_index_t index, char *text, size_t length)
541{
542 int rc = 0;
543 char *newstr = NULL;
544 unsigned long flags;
545
546 if ((index >= MSG_FIRST_INDEX) && (index < MSG_LAST_INDEX)) {
547 newstr = kmalloc(length + 1, GFP_KERNEL);
548 if (newstr) {
549 memcpy(newstr, text, length);
550 newstr[length] = '\0';
551 if ((index >= MSG_FORMATTED_START && index <= MSG_FORMATTED_END)
552 && ! fmt_validate(speakup_default_msgs[index], newstr)) {
553 return -EINVAL;
554 }
555 spk_lock(flags);
556 if (speakup_msgs[index] != speakup_default_msgs[index])
557 kfree(speakup_msgs[index]);
558 speakup_msgs[index] = newstr;
559 spk_unlock(flags);
560 } else {
561 rc = -ENOMEM;
562 }
563 } else {
564 rc = -EINVAL;
565 }
566 return rc;
567}
568
569/*
570 * Find a message group, given its name. Return a pointer to the structure
571 * if found, or NULL otherwise.
572*/
573struct msg_group_t *find_msg_group(const char *group_name)
574{
575 struct msg_group_t *group = NULL;
576 int i;
577
578 for (i = 0; i < num_groups; i++) {
579 if (!strcmp(all_groups[i].name, group_name)) {
580 group = &all_groups[i];
581 break;
582 }
583 }
584 return group;
585}
586
587void reset_msg_group(struct msg_group_t *group)
588{
589 unsigned long flags;
590 enum msg_index_t i;
591
592 spk_lock(flags);
593
594 for(i = group->start; i <= group->end; i++) {
595 if (speakup_msgs[i] != speakup_default_msgs[i])
596 kfree(speakup_msgs[i]);
597 speakup_msgs[i] = speakup_default_msgs[i];
598 }
599 spk_unlock(flags);
600}
601
602/* Called at initialization time, to establish default messages. */
603void initialize_msgs(void)
604{
605 memcpy(speakup_msgs, speakup_default_msgs, sizeof(speakup_default_msgs));
606}
607
608/* Free user-supplied strings when module is unloaded: */
609void free_user_msgs(void)
610{
611 enum msg_index_t index;
612 unsigned long flags;
613
614 spk_lock(flags);
615 for(index = MSG_FIRST_INDEX; index < MSG_LAST_INDEX; index++) {
616 if (speakup_msgs[index] != speakup_default_msgs[index]) {
617 kfree(speakup_msgs[index]);
618 speakup_msgs[index] = speakup_default_msgs[index];
619 }
620 }
621 spk_unlock(flags);
622}
diff --git a/drivers/staging/speakup/i18n.h b/drivers/staging/speakup/i18n.h
new file mode 100644
index 00000000000..65caa801077
--- /dev/null
+++ b/drivers/staging/speakup/i18n.h
@@ -0,0 +1,228 @@
1#ifndef I18N_H
2#define I18N_H
3/* Internationalization declarations */
4
5enum msg_index_t {
6 MSG_FIRST_INDEX ,
7 MSG_ANNOUNCEMENTS_START = MSG_FIRST_INDEX,
8 MSG_BLANK = MSG_ANNOUNCEMENTS_START,
9 MSG_IAM_ALIVE,
10 MSG_YOU_KILLED_SPEAKUP,
11 MSG_HEY_THATS_BETTER,
12 MSG_YOU_TURNED_ME_OFF,
13 MSG_PARKED,
14 MSG_UNPARKED,
15 MSG_MARK,
16 MSG_CUT,
17 MSG_MARK_CLEARED,
18 MSG_PASTE,
19 MSG_BRIGHT,
20 MSG_ON_BLINKING,
21 MSG_STATUS_START,
22 MSG_OFF = MSG_STATUS_START,
23 MSG_ON,
24 MSG_NO_WINDOW,
25 MSG_CURSOR_MSGS_START,
26 MSG_CURSORING_OFF = MSG_CURSOR_MSGS_START,
27 MSG_CURSORING_ON,
28 MSG_HIGHLIGHT_TRACKING,
29 MSG_READ_WINDOW,
30 MSG_READ_ALL,
31 MSG_EDIT_DONE,
32 MSG_WINDOW_ALREADY_SET,
33 MSG_END_BEFORE_START,
34 MSG_WINDOW_CLEARED,
35 MSG_WINDOW_SILENCED,
36 MSG_WINDOW_SILENCE_DISABLED,
37 MSG_ERROR,
38 MSG_GOTO_CANCELED,
39 MSG_GOTO,
40 MSG_LEAVING_HELP,
41 MSG_IS_UNASSIGNED,
42 MSG_HELP_INFO,
43 MSG_EDGE_MSGS_START,
44 MSG_EDGE_TOP = MSG_EDGE_MSGS_START,
45 MSG_EDGE_BOTTOM,
46 MSG_EDGE_LEFT,
47 MSG_EDGE_RIGHT,
48 MSG_NUMBER,
49 MSG_SPACE,
50 MSG_START, /* A little confusing, given our convention. */
51 MSG_END, /* A little confusing, given our convention. */
52 MSG_CTRL,
53
54/* A message containing the single word "or". */
55 MSG_DISJUNCTION,
56 MSG_ANNOUNCEMENTS_END = MSG_DISJUNCTION,
57
58/* Messages with format specifiers. */
59 MSG_FORMATTED_START,
60 MSG_POS_INFO = MSG_FORMATTED_START,
61 MSG_CHAR_INFO,
62 MSG_REPEAT_DESC,
63 MSG_REPEAT_DESC2,
64 MSG_WINDOW_LINE,
65 MSG_WINDOW_BOUNDARY,
66 MSG_EDIT_PROMPT,
67 MSG_NO_COMMAND,
68 MSG_KEYDESC,
69 MSG_FORMATTED_END = MSG_KEYDESC,
70
71 /* Control keys. */
72 MSG_CTL_START,
73 MSG_CTL_SHIFT = MSG_CTL_START,
74 MSG_CTL_ALTGR,
75 MSG_CTL_CONTROL,
76 MSG_CTL_ALT,
77 MSG_CTL_LSHIFT,
78 MSG_CTL_SPEAKUP,
79 MSG_CTL_LCONTROL,
80 MSG_CTL_RCONTROL,
81 MSG_CTL_CAPSSHIFT,
82 MSG_CTL_END = MSG_CTL_CAPSSHIFT,
83
84 /* Colors. */
85 MSG_COLORS_START,
86 MSG_COLOR_BLACK = MSG_COLORS_START,
87 MSG_COLOR_BLUE,
88 MSG_COLOR_GREEN,
89 MSG_COLOR_CYAN,
90 MSG_COLOR_RED,
91 MSG_COLOR_MAGENTA,
92 MSG_COLOR_YELLOW,
93 MSG_COLOR_WHITE,
94 MSG_COLOR_GREY,
95 MSG_COLORS_END = MSG_COLOR_GREY,
96
97 MSG_STATES_START,
98 MSG_STATE_DOUBLE = MSG_STATES_START,
99 MSG_STATE_SPEAKUP,
100 MSG_STATE_ALT,
101 MSG_STATE_CONTROL,
102 MSG_STATE_ALTGR,
103 MSG_STATE_SHIFT,
104 MSG_STATES_END = MSG_STATE_SHIFT,
105
106 MSG_KEYNAMES_START,
107 MSG_KEYNAME_ESC = MSG_KEYNAMES_START,
108 MSG_KEYNAME_1, MSG_KEYNAME_2, MSG_KEYNAME_3, MSG_KEYNAME_4,
109 MSG_KEYNAME_5, MSG_KEYNAME_6, MSG_KEYNAME_7, MSG_KEYNAME_8, MSG_KEYNAME_9,
110 MSG_KEYNAME_0, MSG_KEYNAME_DASH, MSG_KEYNAME_EQUAL, MSG_KEYNAME_BS,
111 MSG_KEYNAME_TAB,
112 MSG_KEYNAME_Q, MSG_KEYNAME_W, MSG_KEYNAME_E, MSG_KEYNAME_R, MSG_KEYNAME_T,
113 MSG_KEYNAME_Y, MSG_KEYNAME_U, MSG_KEYNAME_I, MSG_KEYNAME_O, MSG_KEYNAME_P,
114 MSG_KEYNAME_LEFTBRACE, MSG_KEYNAME_RIGHTBRACE, MSG_KEYNAME_ENTER,
115 MSG_KEYNAME_LEFTCTRL, MSG_KEYNAME_A,
116 MSG_KEYNAME_S, MSG_KEYNAME_D, MSG_KEYNAME_F, MSG_KEYNAME_G, MSG_KEYNAME_H,
117 MSG_KEYNAME_J, MSG_KEYNAME_K, MSG_KEYNAME_L, MSG_KEYNAME_SEMICOLON,
118 MSG_KEYNAME_SINGLEQUOTE, MSG_KEYNAME_GRAVE,
119 MSG_KEYNAME_LEFTSHFT, MSG_KEYNAME_BACKSLASH, MSG_KEYNAME_Z, MSG_KEYNAME_X,
120 MSG_KEYNAME_C, MSG_KEYNAME_V, MSG_KEYNAME_B, MSG_KEYNAME_N, MSG_KEYNAME_M,
121 MSG_KEYNAME_COMMA, MSG_KEYNAME_DOT, MSG_KEYNAME_SLASH, MSG_KEYNAME_RIGHTSHFT,
122 MSG_KEYNAME_KPSTAR,
123 MSG_KEYNAME_LEFTALT, MSG_KEYNAME_SPACE, MSG_KEYNAME_CAPSLOCK,
124 MSG_KEYNAME_F1, MSG_KEYNAME_F2,
125 MSG_KEYNAME_F3, MSG_KEYNAME_F4, MSG_KEYNAME_F5, MSG_KEYNAME_F6,
126 MSG_KEYNAME_F7,
127 MSG_KEYNAME_F8, MSG_KEYNAME_F9, MSG_KEYNAME_F10, MSG_KEYNAME_NUMLOCK,
128 MSG_KEYNAME_SCROLLLOCK,
129 MSG_KEYNAME_KP7, MSG_KEYNAME_KP8, MSG_KEYNAME_KP9, MSG_KEYNAME_KPMINUS,
130 MSG_KEYNAME_KP4,
131 MSG_KEYNAME_KP5, MSG_KEYNAME_KP6, MSG_KEYNAME_KPPLUS, MSG_KEYNAME_KP1,
132 MSG_KEYNAME_KP2,
133 MSG_KEYNAME_KP3, MSG_KEYNAME_KP0, MSG_KEYNAME_KPDOT, MSG_KEYNAME_103RD,
134 MSG_KEYNAME_F13,
135 MSG_KEYNAME_102ND, MSG_KEYNAME_F11, MSG_KEYNAME_F12, MSG_KEYNAME_F14,
136 MSG_KEYNAME_F15,
137 MSG_KEYNAME_F16, MSG_KEYNAME_F17, MSG_KEYNAME_F18, MSG_KEYNAME_F19,
138 MSG_KEYNAME_F20,
139 MSG_KEYNAME_KPENTER, MSG_KEYNAME_RIGHTCTRL, MSG_KEYNAME_KPSLASH,
140 MSG_KEYNAME_SYSRQ, MSG_KEYNAME_RIGHTALT,
141 MSG_KEYNAME_LF, MSG_KEYNAME_HOME, MSG_KEYNAME_UP, MSG_KEYNAME_PGUP,
142 MSG_KEYNAME_LEFT,
143 MSG_KEYNAME_RIGHT, MSG_KEYNAME_END, MSG_KEYNAME_DOWN, MSG_KEYNAME_PGDN,
144 MSG_KEYNAME_INS,
145 MSG_KEYNAME_DEL, MSG_KEYNAME_MACRO, MSG_KEYNAME_MUTE,
146 MSG_KEYNAME_VOLDOWN, MSG_KEYNAME_VOLUP,
147 MSG_KEYNAME_POWER, MSG_KEYNAME_KPEQUAL, MSG_KEYNAME_KPPLUSDASH, MSG_KEYNAME_PAUSE, MSG_KEYNAME_F21,
148 MSG_KEYNAME_F22, MSG_KEYNAME_F23, MSG_KEYNAME_F24, MSG_KEYNAME_KPCOMMA, MSG_KEYNAME_LEFTMETA,
149 MSG_KEYNAME_RIGHTMETA, MSG_KEYNAME_COMPOSE, MSG_KEYNAME_STOP,
150 MSG_KEYNAME_AGAIN, MSG_KEYNAME_PROPS,
151 MSG_KEYNAME_UNDO, MSG_KEYNAME_FRONT, MSG_KEYNAME_COPY, MSG_KEYNAME_OPEN,
152 MSG_KEYNAME_PASTE,
153 MSG_KEYNAME_FIND, MSG_KEYNAME_CUT, MSG_KEYNAME_HELP, MSG_KEYNAME_MENU,
154 MSG_KEYNAME_CALC,
155 MSG_KEYNAME_SETUP, MSG_KEYNAME_SLEEP, MSG_KEYNAME_WAKEUP,
156 MSG_KEYNAME_FILE, MSG_KEYNAME_SENDFILE,
157 MSG_KEYNAME_DELFILE, MSG_KEYNAME_XFER, MSG_KEYNAME_PROG1,
158 MSG_KEYNAME_PROG2, MSG_KEYNAME_WWW,
159 MSG_KEYNAME_MSDOS, MSG_KEYNAME_COFFEE, MSG_KEYNAME_DIRECTION,
160 MSG_KEYNAME_CYCLEWINDOWS, MSG_KEYNAME_MAIL,
161 MSG_KEYNAME_BOOKMARKS, MSG_KEYNAME_COMPUTER, MSG_KEYNAME_BACK,
162 MSG_KEYNAME_FORWARD, MSG_KEYNAME_CLOSECD,
163 MSG_KEYNAME_EJECTCD, MSG_KEYNAME_EJECTCLOSE, MSG_KEYNAME_NEXTSONG,
164 MSG_KEYNAME_PLAYPAUSE, MSG_KEYNAME_PREVSONG,
165 MSG_KEYNAME_STOPCD, MSG_KEYNAME_RECORD, MSG_KEYNAME_REWIND,
166 MSG_KEYNAME_PHONE, MSG_KEYNAME_ISO,
167 MSG_KEYNAME_CONFIG, MSG_KEYNAME_HOMEPG, MSG_KEYNAME_REFRESH,
168 MSG_KEYNAME_EXIT, MSG_KEYNAME_MOVE,
169 MSG_KEYNAME_EDIT, MSG_KEYNAME_SCROLLUP, MSG_KEYNAME_SCROLLDN,
170 MSG_KEYNAME_KPLEFTPAR, MSG_KEYNAME_KPRIGHTPAR,
171 MSG_KEYNAMES_END = MSG_KEYNAME_KPRIGHTPAR,
172
173 MSG_FUNCNAMES_START,
174 MSG_FUNCNAME_ATTRIB_BLEEP_DEC = MSG_FUNCNAMES_START,
175 MSG_FUNCNAME_ATTRIB_BLEEP_INC,
176 MSG_FUNCNAME_BLEEPS_DEC, MSG_FUNCNAME_BLEEPS_INC,
177 MSG_FUNCNAME_CHAR_FIRST, MSG_FUNCNAME_CHAR_LAST,
178 MSG_FUNCNAME_CHAR_CURRENT, MSG_FUNCNAME_CHAR_HEX_AND_DEC,
179 MSG_FUNCNAME_CHAR_NEXT,
180 MSG_FUNCNAME_CHAR_PHONETIC, MSG_FUNCNAME_CHAR_PREVIOUS,
181 MSG_FUNCNAME_CURSOR_PARK, MSG_FUNCNAME_CUT,
182 MSG_FUNCNAME_EDIT_DELIM, MSG_FUNCNAME_EDIT_EXNUM,
183 MSG_FUNCNAME_EDIT_MOST, MSG_FUNCNAME_EDIT_REPEATS, MSG_FUNCNAME_EDIT_SOME,
184 MSG_FUNCNAME_GOTO, MSG_FUNCNAME_GOTO_BOTTOM, MSG_FUNCNAME_GOTO_LEFT,
185 MSG_FUNCNAME_GOTO_RIGHT, MSG_FUNCNAME_GOTO_TOP, MSG_FUNCNAME_HELP,
186 MSG_FUNCNAME_LINE_SAY_CURRENT, MSG_FUNCNAME_LINE_SAY_NEXT,
187 MSG_FUNCNAME_LINE_SAY_PREVIOUS, MSG_FUNCNAME_LINE_SAY_WITH_INDENT,
188 MSG_FUNCNAME_PASTE, MSG_FUNCNAME_PITCH_DEC, MSG_FUNCNAME_PITCH_INC,
189 MSG_FUNCNAME_PUNC_DEC, MSG_FUNCNAME_PUNC_INC,
190 MSG_FUNCNAME_PUNC_LEVEL_DEC, MSG_FUNCNAME_PUNC_LEVEL_INC,
191 MSG_FUNCNAME_QUIET,
192 MSG_FUNCNAME_RATE_DEC, MSG_FUNCNAME_RATE_INC,
193 MSG_FUNCNAME_READING_PUNC_DEC, MSG_FUNCNAME_READING_PUNC_INC,
194 MSG_FUNCNAME_SAY_ATTRIBUTES,
195 MSG_FUNCNAME_SAY_FROM_LEFT, MSG_FUNCNAME_SAY_FROM_TOP,
196 MSG_FUNCNAME_SAY_POSITION, MSG_FUNCNAME_SAY_SCREEN,
197 MSG_FUNCNAME_SAY_TO_BOTTOM, MSG_FUNCNAME_SAY_TO_RIGHT,
198 MSG_FUNCNAME_SPEAKUP, MSG_FUNCNAME_SPEAKUP_LOCK,
199 MSG_FUNCNAME_SPEAKUP_OFF, MSG_FUNCNAME_SPEECH_KILL,
200 MSG_FUNCNAME_SPELL_DELAY_DEC, MSG_FUNCNAME_SPELL_DELAY_INC,
201 MSG_FUNCNAME_SPELL_WORD, MSG_FUNCNAME_SPELL_WORD_PHONETICALLY,
202 MSG_FUNCNAME_TONE_DEC, MSG_FUNCNAME_TONE_INC,
203 MSG_FUNCNAME_VOICE_DEC, MSG_FUNCNAME_VOICE_INC,
204 MSG_FUNCNAME_VOLUME_DEC, MSG_FUNCNAME_VOLUME_INC,
205 MSG_FUNCNAME_WINDOW_CLEAR, MSG_FUNCNAME_WINDOW_SAY,
206 MSG_FUNCNAME_WINDOW_SET, MSG_FUNCNAME_WINDOW_SILENCE,
207 MSG_FUNCNAME_WORD_SAY_CURRENT, MSG_FUNCNAME_WORD_SAY_NEXT,
208 MSG_FUNCNAME_WORD_SAY_PREVIOUS,
209 MSG_FUNCNAMES_END = MSG_FUNCNAME_WORD_SAY_PREVIOUS,
210
211 /* all valid indices must be above this */
212 MSG_LAST_INDEX
213};
214
215struct msg_group_t {
216 char *name;
217 enum msg_index_t start;
218 enum msg_index_t end;
219};
220
221extern char *msg_get(enum msg_index_t index);
222extern ssize_t msg_set(enum msg_index_t index, char *text, size_t length);
223extern struct msg_group_t *find_msg_group(const char *group_name);
224extern void reset_msg_group(struct msg_group_t *group);
225extern void initialize_msgs(void);
226extern void free_user_msgs(void);
227
228#endif
diff --git a/drivers/staging/speakup/keyhelp.c b/drivers/staging/speakup/keyhelp.c
new file mode 100644
index 00000000000..81c627cfb3a
--- /dev/null
+++ b/drivers/staging/speakup/keyhelp.c
@@ -0,0 +1,212 @@
1/* speakup_keyhelp.c
2 help module for speakup
3
4 written by David Borowski.
5
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
23#include <linux/keyboard.h>
24#include "spk_priv.h"
25#include "speakup.h"
26
27#define MAXFUNCS 130
28#define MAXKEYS 256
29static const int num_key_names = MSG_KEYNAMES_END - MSG_KEYNAMES_START + 1;
30static u_short key_offsets[MAXFUNCS], key_data[MAXKEYS];
31static u_short masks[] = { 32, 16, 8, 4, 2, 1 };
32
33static short letter_offsets[26] =
34{ -1, -1, -1, -1, -1, -1, -1, -1,
35 -1, -1, -1, -1, -1, -1, -1, -1,
36 -1, -1, -1, -1, -1, -1, -1, -1,
37 -1, -1 };
38
39static u_char funcvals[] = {
40 ATTRIB_BLEEP_DEC, ATTRIB_BLEEP_INC, BLEEPS_DEC, BLEEPS_INC,
41 SAY_FIRST_CHAR, SAY_LAST_CHAR, SAY_CHAR, SAY_CHAR_NUM,
42 SAY_NEXT_CHAR, SAY_PHONETIC_CHAR, SAY_PREV_CHAR, SPEAKUP_PARKED,
43 SPEAKUP_CUT, EDIT_DELIM, EDIT_EXNUM, EDIT_MOST,
44 EDIT_REPEAT, EDIT_SOME, SPEAKUP_GOTO, BOTTOM_EDGE,
45 LEFT_EDGE, RIGHT_EDGE, TOP_EDGE, SPEAKUP_HELP,
46 SAY_LINE, SAY_NEXT_LINE, SAY_PREV_LINE, SAY_LINE_INDENT,
47 SPEAKUP_PASTE, PITCH_DEC, PITCH_INC, PUNCT_DEC,
48 PUNCT_INC, PUNC_LEVEL_DEC, PUNC_LEVEL_INC, SPEAKUP_QUIET,
49 RATE_DEC, RATE_INC, READING_PUNC_DEC, READING_PUNC_INC,
50 SAY_ATTRIBUTES, SAY_FROM_LEFT, SAY_FROM_TOP, SAY_POSITION,
51 SAY_SCREEN, SAY_TO_BOTTOM, SAY_TO_RIGHT, SPK_KEY,
52 SPK_LOCK, SPEAKUP_OFF, SPEECH_KILL, SPELL_DELAY_DEC,
53 SPELL_DELAY_INC, SPELL_WORD, SPELL_PHONETIC, TONE_DEC,
54 TONE_INC, VOICE_DEC, VOICE_INC, VOL_DEC,
55 VOL_INC, CLEAR_WIN, SAY_WIN, SET_WIN,
56 ENABLE_WIN, SAY_WORD, SAY_NEXT_WORD, SAY_PREV_WORD, 0
57};
58
59static u_char *state_tbl;
60static int cur_item, nstates;
61
62static void build_key_data(void)
63{
64 u_char *kp, counters[MAXFUNCS], ch, ch1;
65 u_short *p_key = key_data, key;
66 int i, offset = 1;
67 nstates = (int)(state_tbl[-1]);
68 memset(counters, 0, sizeof(counters));
69 memset(key_offsets, 0, sizeof(key_offsets));
70 kp = state_tbl + nstates + 1;
71 while (*kp++) {
72 /* count occurrances of each function */
73 for (i = 0; i < nstates; i++, kp++) {
74 if (!*kp)
75 continue;
76 if ((state_tbl[i]&16) != 0 && *kp == SPK_KEY)
77 continue;
78 counters[*kp]++;
79 }
80 }
81 for (i = 0; i < MAXFUNCS; i++) {
82 if (counters[i] == 0)
83 continue;
84 key_offsets[i] = offset;
85 offset += (counters[i]+1);
86 if (offset >= MAXKEYS)
87 break;
88 }
89/* leave counters set so high keycodes come first.
90 this is done so num pad and other extended keys maps are spoken before
91 the alpha with speakup type mapping. */
92 kp = state_tbl + nstates + 1;
93 while ((ch = *kp++)) {
94 for (i = 0; i < nstates; i++) {
95 ch1 = *kp++;
96 if (!ch1)
97 continue;
98 if ((state_tbl[i]&16) != 0 && ch1 == SPK_KEY)
99 continue;
100 key = (state_tbl[i] << 8) + ch;
101 counters[ch1]--;
102 offset = key_offsets[ch1];
103 if (!offset)
104 continue;
105 p_key = key_data + offset + counters[ch1];
106 *p_key = key;
107 }
108 }
109}
110
111static void say_key(int key)
112{
113 int i, state = key >> 8;
114 key &= 0xff;
115 for (i = 0; i < 6; i++) {
116 if (state & masks[i])
117 synth_printf(" %s", msg_get(MSG_STATES_START + i));
118 }
119 if ((key > 0) && (key <= num_key_names))
120 synth_printf(" %s\n", msg_get(MSG_KEYNAMES_START + (key - 1)));
121}
122
123static int help_init(void)
124{
125 char start = SPACE;
126 int i;
127 int num_funcs = MSG_FUNCNAMES_END - MSG_FUNCNAMES_START + 1;
128state_tbl = our_keys[0]+SHIFT_TBL_SIZE+2;
129 for (i = 0; i < num_funcs; i++) {
130 char *cur_funcname = msg_get(MSG_FUNCNAMES_START + i);
131 if (start == *cur_funcname)
132 continue;
133 start = *cur_funcname;
134 letter_offsets[(start&31)-1] = i;
135 }
136 return 0;
137}
138
139int handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key)
140{
141 int i, n;
142 char *name;
143 u_char func, *kp;
144 u_short *p_keys, val;
145 if (letter_offsets[0] == -1)
146 help_init();
147 if (type == KT_LATIN) {
148 if (ch == SPACE) {
149 special_handler = NULL;
150 synth_printf("%s\n", msg_get(MSG_LEAVING_HELP));
151 return 1;
152 }
153 ch |= 32; /* lower case */
154 if (ch < 'a' || ch > 'z')
155 return -1;
156 if (letter_offsets[ch-'a'] == -1) {
157 synth_printf(msg_get(MSG_NO_COMMAND), ch);
158 synth_printf("\n");
159 return 1;
160 }
161 cur_item = letter_offsets[ch-'a'];
162 } else if (type == KT_CUR) {
163 if (ch == 0 && (cur_item + 1) <= MSG_FUNCNAMES_END)
164 cur_item++;
165 else if (ch == 3 && cur_item > 0)
166 cur_item--;
167 else
168 return -1;
169 } else if (type == KT_SPKUP && ch == SPEAKUP_HELP && !special_handler) {
170 special_handler = handle_help;
171 synth_printf("%s\n", msg_get(MSG_HELP_INFO));
172 build_key_data(); /* rebuild each time in case new mapping */
173 return 1;
174 } else {
175 name = NULL;
176 if ((type != KT_SPKUP) && (key > 0) && (key <= num_key_names)) {
177 synth_printf("%s\n", msg_get(MSG_KEYNAMES_START + key-1));
178 return 1;
179 }
180 for (i = 0; funcvals[i] != 0 && !name; i++) {
181 if (ch == funcvals[i])
182 name = msg_get(MSG_FUNCNAMES_START + i);
183 }
184 if (!name)
185 return -1;
186 kp = our_keys[key]+1;
187 for (i = 0; i < nstates; i++) {
188 if (ch == kp[i])
189 break;
190 }
191 key += (state_tbl[i] << 8);
192 say_key(key);
193 synth_printf(msg_get(MSG_KEYDESC), name);
194 synth_printf("\n");
195 return 1;
196 }
197 name = msg_get(MSG_FUNCNAMES_START + cur_item);
198 func = funcvals[cur_item];
199 synth_printf("%s", name);
200 if (key_offsets[func] == 0) {
201 synth_printf(" %s\n", msg_get(MSG_IS_UNASSIGNED));
202 return 1;
203 }
204 p_keys = key_data + key_offsets[func];
205 for (n = 0; p_keys[n]; n++) {
206 val = p_keys[n];
207 if (n > 0)
208 synth_printf("%s ", msg_get(MSG_DISJUNCTION));
209 say_key(val);
210 }
211 return 1;
212}
diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c
new file mode 100644
index 00000000000..1cd456670fc
--- /dev/null
+++ b/drivers/staging/speakup/kobjects.c
@@ -0,0 +1,1007 @@
1/*
2 * Speakup kobject implementation
3 *
4 * Copyright (C) 2009 William Hubbs
5 *
6 * This code is based on kobject-example.c, which came with linux 2.6.x.
7 *
8 * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
9 * Copyright (C) 2007 Novell Inc.
10 *
11 * Released under the GPL version 2 only.
12 *
13 */
14#include <linux/slab.h> /* For kmalloc. */
15#include <linux/kernel.h>
16#include <linux/kobject.h>
17#include <linux/string.h>
18#include <linux/sysfs.h>
19#include <linux/ctype.h>
20
21#include "speakup.h"
22#include "spk_priv.h"
23
24/*
25 * This is called when a user reads the characters or chartab sys file.
26 */
27static ssize_t chars_chartab_show(struct kobject *kobj,
28 struct kobj_attribute *attr, char *buf)
29{
30 int i;
31 int len = 0;
32 char *cp;
33 char *buf_pointer = buf;
34 size_t bufsize = PAGE_SIZE;
35 unsigned long flags;
36
37 spk_lock(flags);
38 *buf_pointer = '\0';
39 for (i = 0; i < 256; i++) {
40 if (bufsize <= 1)
41 break;
42 if (strcmp("characters", attr->attr.name) == 0) {
43 len = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
44 i, characters[i]);
45 } else { /* show chartab entry */
46 if (IS_TYPE(i, B_CTL))
47 cp = "B_CTL";
48 else if (IS_TYPE(i, WDLM))
49 cp = "WDLM";
50 else if (IS_TYPE(i, A_PUNC))
51 cp = "A_PUNC";
52 else if (IS_TYPE(i, PUNC))
53 cp = "PUNC";
54 else if (IS_TYPE(i, NUM))
55 cp = "NUM";
56 else if (IS_TYPE(i, A_CAP))
57 cp = "A_CAP";
58 else if (IS_TYPE(i, ALPHA))
59 cp = "ALPHA";
60 else if (IS_TYPE(i, B_CAPSYM))
61 cp = "B_CAPSYM";
62 else if (IS_TYPE(i, B_SYM))
63 cp = "B_SYM";
64 else
65 cp = "0";
66 len =
67 scnprintf(buf_pointer, bufsize, "%d\t%s\n", i, cp);
68 }
69 bufsize -= len;
70 buf_pointer += len;
71 }
72 spk_unlock(flags);
73 return buf_pointer - buf;
74}
75
76/*
77 * Print informational messages or warnings after updating
78 * character descriptions or chartab entries.
79 */
80static void report_char_chartab_status(int reset, int received, int used,
81 int rejected, int do_characters)
82{
83 char *object_type[] = {
84 "character class entries",
85 "character descriptions",
86 };
87 int len;
88 char buf[80];
89
90 if (reset) {
91 pr_info("%s reset to defaults\n", object_type[do_characters]);
92 } else if (received ) {
93 len = snprintf(buf, sizeof(buf),
94 " updated %d of %d %s\n",
95 used, received, object_type[do_characters]);
96 if (rejected)
97 snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
98 " with %d reject%s\n",
99 rejected, rejected > 1 ? "s" : "");
100 printk(buf);
101 }
102}
103
104/*
105 * This is called when a user changes the characters or chartab parameters.
106 */
107static ssize_t chars_chartab_store(struct kobject *kobj,
108 struct kobj_attribute *attr, const char *buf, size_t count)
109{
110 char *cp = (char *) buf;
111 char *end = cp + count; /* the null at the end of the buffer */
112 char *linefeed = NULL;
113 char keyword[MAX_DESC_LEN + 1];
114 char *outptr = NULL; /* Will hold keyword or desc. */
115 char *temp = NULL;
116 char *desc = NULL;
117 ssize_t retval = count;
118 unsigned long flags;
119 unsigned long index = 0;
120 int charclass = 0;
121 int received = 0;
122 int used = 0;
123 int rejected = 0;
124 int reset = 0;
125 int do_characters = !strcmp(attr->attr.name, "characters");
126 size_t desc_length = 0;
127 int i;
128
129 spk_lock(flags);
130 while (cp < end) {
131
132 while ((cp < end) && (*cp == ' ' || *cp == '\t'))
133 cp++;
134
135 if (cp == end)
136 break;
137 if ((*cp == '\n') || strchr("dDrR", *cp)) {
138 reset = 1;
139 break;
140 }
141 received++;
142
143 linefeed = strchr(cp, '\n');
144 if (!linefeed) {
145 rejected++;
146 break;
147 }
148
149 if (! isdigit(*cp)) {
150 rejected++;
151 cp = linefeed + 1;
152 continue;
153 }
154
155 index = simple_strtoul(cp, &temp, 10);
156 if (index > 255) {
157 rejected++;
158 cp = linefeed + 1;
159 continue;
160 }
161
162 while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
163 temp++;
164
165 desc_length = linefeed - temp;
166 if (desc_length > MAX_DESC_LEN) {
167 rejected++;
168 cp = linefeed + 1;
169 continue;
170 }
171 if (do_characters) {
172 desc = kmalloc(desc_length + 1, GFP_ATOMIC);
173 if (! desc) {
174 retval = -ENOMEM;
175 reset = 1; /* just reset on error. */
176 break;
177 }
178 outptr = desc;
179 } else {
180 outptr = keyword;
181 }
182
183 for (i = 0; i < desc_length; i++)
184 outptr[i] = temp[i];
185 outptr[desc_length] = '\0';
186
187 if (do_characters) {
188 if (characters[index] != default_chars[index])
189 kfree(characters[index]);
190 characters[index] = desc;
191 used++;
192 } else {
193 charclass = chartab_get_value(keyword);
194 if (charclass == 0) {
195 rejected++;
196 cp = linefeed + 1;
197 continue;
198 }
199 if (charclass != spk_chartab[index]) {
200 spk_chartab[index] = charclass;
201 used++;
202 }
203 }
204 cp = linefeed + 1;
205 }
206
207 if (reset) {
208 if (do_characters)
209 reset_default_chars();
210 else
211 reset_default_chartab();
212 }
213
214 spk_unlock(flags);
215 report_char_chartab_status(reset, received, used, rejected, do_characters);
216 return retval;
217}
218
219/*
220 * This is called when a user reads the keymap parameter.
221 */
222static ssize_t keymap_show(struct kobject *kobj, struct kobj_attribute *attr,
223 char *buf)
224{
225 char *cp = buf;
226 int i;
227 int n;
228 int num_keys;
229 int nstates;
230 u_char *cp1;
231 u_char ch;
232 unsigned long flags;
233 spk_lock(flags);
234 cp1 = key_buf + SHIFT_TBL_SIZE;
235 num_keys = (int)(*cp1);
236 nstates = (int)cp1[1];
237 cp += sprintf(cp, "%d, %d, %d,\n", KEY_MAP_VER, num_keys, nstates);
238 cp1 += 2; /* now pointing at shift states */
239/* dump num_keys+1 as first row is shift states + flags,
240 each subsequent row is key + states */
241 for (n = 0; n <= num_keys; n++) {
242 for (i = 0; i <= nstates; i++) {
243 ch = *cp1++;
244 cp += sprintf(cp, "%d,", (int)ch);
245 *cp++ = (i < nstates) ? SPACE : '\n';
246 }
247 }
248 cp += sprintf(cp, "0, %d\n", KEY_MAP_VER);
249 spk_unlock(flags);
250 return (int)(cp-buf);
251}
252
253/*
254 * This is called when a user changes the keymap parameter.
255 */
256static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr,
257 const char *buf, size_t count)
258{
259 int i;
260 ssize_t ret = count;
261 char *in_buff = NULL;
262 char *cp;
263 u_char *cp1;
264 unsigned long flags;
265
266 spk_lock(flags);
267 in_buff = kmalloc(count + 1, GFP_ATOMIC);
268 if (! in_buff) {
269 spk_unlock(flags);
270 return -ENOMEM;
271 }
272 memcpy(in_buff, buf, count + 1);
273 if (strchr("dDrR", *in_buff)) {
274 set_key_info(key_defaults, key_buf);
275 pr_info("keymap set to default values\n");
276 kfree(in_buff);
277 spk_unlock(flags);
278 return count;
279 }
280 if (in_buff[count - 1] == '\n')
281 in_buff[count - 1] = '\0';
282 cp = in_buff;
283 cp1 = (u_char *)in_buff;
284 for (i = 0; i < 3; i++) {
285 cp = s2uchar(cp, cp1);
286 cp1++;
287 }
288 i = (int)cp1[-2]+1;
289 i *= (int)cp1[-1]+1;
290 i += 2; /* 0 and last map ver */
291 if (cp1[-3] != KEY_MAP_VER || cp1[-1] > 10 ||
292 i+SHIFT_TBL_SIZE+4 >= sizeof(key_buf)) {
293 pr_warn("i %d %d %d %d\n", i,
294 (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
295 kfree(in_buff);
296 spk_unlock(flags);
297 return -EINVAL;
298 }
299 while (--i >= 0) {
300 cp = s2uchar(cp, cp1);
301 cp1++;
302 if (!(*cp))
303 break;
304 }
305 if (i != 0 || cp1[-1] != KEY_MAP_VER || cp1[-2] != 0) {
306 ret = -EINVAL;
307 pr_warn("end %d %d %d %d\n", i,
308 (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
309 } else {
310 if (set_key_info(in_buff, key_buf)) {
311 set_key_info(key_defaults, key_buf);
312 ret = -EINVAL;
313 pr_warn("set key failed\n");
314 }
315 }
316 kfree(in_buff);
317 spk_unlock(flags);
318 return ret;
319}
320
321/*
322 * This is called when a user changes the value of the silent parameter.
323 */
324static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr,
325 const char *buf, size_t count)
326{
327 int len;
328 struct vc_data *vc = vc_cons[fg_console].d;
329 char ch = 0;
330 char shut;
331 unsigned long flags;
332
333 len = strlen(buf);
334 if (len > 0 || len < 3) {
335 ch = buf[0];
336 if (ch == '\n')
337 ch = '0';
338 }
339 if (ch < '0' || ch > '7') {
340 pr_warn("silent value '%c' not in range (0,7)\n", ch);
341 return -EINVAL;
342 }
343 spk_lock(flags);
344 if (ch&2) {
345 shut = 1;
346 do_flush();
347 } else {
348 shut = 0;
349 }
350 if (ch&4)
351 shut |= 0x40;
352 if (ch&1)
353 spk_shut_up |= shut;
354 else
355 spk_shut_up &= ~shut;
356 spk_unlock(flags);
357 return count;
358}
359
360/*
361 * This is called when a user reads the synth setting.
362 */
363static ssize_t synth_show(struct kobject *kobj, struct kobj_attribute *attr,
364 char *buf)
365{
366 int rv;
367
368 if (synth == NULL)
369 rv = sprintf(buf, "%s\n", "none");
370 else
371 rv = sprintf(buf, "%s\n", synth->name);
372 return rv;
373}
374
375/*
376 * This is called when a user requests to change synthesizers.
377 */
378static ssize_t synth_store(struct kobject *kobj, struct kobj_attribute *attr,
379 const char *buf, size_t count)
380{
381 int len;
382 char new_synth_name[10];
383
384 len = strlen(buf);
385 if (len < 2 || len > 9)
386 return -EINVAL;
387 strncpy(new_synth_name, buf, len);
388 if (new_synth_name[len - 1] == '\n')
389 len--;
390 new_synth_name[len] = '\0';
391 strlwr(new_synth_name);
392 if ((synth != NULL) && (!strcmp(new_synth_name, synth->name))) {
393 pr_warn("%s already in use\n", new_synth_name);
394 } else if (synth_init(new_synth_name) != 0) {
395 pr_warn("failed to init synth %s\n", new_synth_name);
396 return -ENODEV;
397 }
398 return count;
399}
400
401/*
402 * This is called when text is sent to the synth via the synth_direct file.
403 */
404static ssize_t synth_direct_store(struct kobject *kobj, struct kobj_attribute *attr,
405 const char *buf, size_t count)
406{
407 u_char tmp[256];
408 int len;
409 int bytes;
410 const char *ptr = buf;
411
412 if (! synth)
413 return -EPERM;
414
415 len = strlen(buf);
416 while (len > 0) {
417 bytes = min_t(size_t, len, 250);
418 strncpy(tmp, ptr, bytes);
419 tmp[bytes] = '\0';
420 xlate(tmp);
421 synth_printf("%s", tmp);
422 ptr += bytes;
423 len -= bytes;
424 }
425 return count;
426}
427
428/*
429 * This function is called when a user reads the version.
430 */
431static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr,
432 char *buf)
433{
434 char *cp;
435
436 cp = buf;
437 cp += sprintf(cp, "Speakup version %s\n", SPEAKUP_VERSION);
438 if (synth)
439 cp += sprintf(cp, "%s synthesizer driver version %s\n",
440 synth->name, synth->version);
441 return cp - buf;
442}
443
444/*
445 * This is called when a user reads the punctuation settings.
446 */
447static ssize_t punc_show(struct kobject *kobj, struct kobj_attribute *attr,
448 char *buf)
449{
450 int i;
451 char *cp = buf;
452 struct st_var_header *p_header;
453 struct punc_var_t *var;
454 struct st_bits_data *pb;
455 short mask;
456 unsigned long flags;
457
458 p_header = var_header_by_name(attr->attr.name);
459 if (p_header == NULL) {
460 pr_warn("p_header is null, attr->attr.name is %s\n", attr->attr.name);
461 return -EINVAL;
462 }
463
464 var = get_punc_var(p_header->var_id);
465 if (var == NULL) {
466 pr_warn("var is null, p_header->var_id is %i\n",
467 p_header->var_id);
468 return -EINVAL;
469 }
470
471 spk_lock(flags);
472 pb = (struct st_bits_data *) &punc_info[var->value];
473 mask = pb->mask;
474 for (i = 33; i < 128; i++) {
475 if (!(spk_chartab[i]&mask))
476 continue;
477 *cp++ = (char)i;
478 }
479 spk_unlock(flags);
480 return cp-buf;
481}
482
483/*
484 * This is called when a user changes the punctuation settings.
485 */
486static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr,
487 const char *buf, size_t count)
488{
489 int x;
490 struct st_var_header *p_header;
491 struct punc_var_t *var;
492 char punc_buf[100];
493 unsigned long flags;
494
495 x = strlen(buf);
496 if (x < 1 || x > 99)
497 return -EINVAL;
498
499 p_header = var_header_by_name(attr->attr.name);
500 if (p_header == NULL) {
501 pr_warn("p_header is null, attr->attr.name is %s\n", attr->attr.name);
502 return -EINVAL;
503 }
504
505 var = get_punc_var(p_header->var_id);
506 if (var == NULL) {
507 pr_warn("var is null, p_header->var_id is %i\n",
508 p_header->var_id);
509 return -EINVAL;
510 }
511
512 strncpy(punc_buf, buf, x);
513
514 while (x && punc_buf[x - 1] == '\n')
515 x--;
516 punc_buf[x] = '\0';
517
518 spk_lock(flags);
519
520 if (*punc_buf == 'd' || *punc_buf == 'r')
521 x = set_mask_bits(0, var->value, 3);
522 else
523 x = set_mask_bits(punc_buf, var->value, 3);
524
525 spk_unlock(flags);
526 return count;
527}
528
529/*
530 * This function is called when a user reads one of the variable parameters.
531 */
532ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
533 char *buf)
534{
535 int rv = 0;
536 struct st_var_header *param;
537 struct var_t *var;
538 char *cp1;
539 char *cp;
540 char ch;
541 unsigned long flags;
542
543 param = var_header_by_name(attr->attr.name);
544 if (param == NULL)
545 return -EINVAL;
546
547 spk_lock(flags);
548 var = (struct var_t *) param->data;
549 switch (param->var_type) {
550 case VAR_NUM:
551 case VAR_TIME:
552 if (var)
553 rv = sprintf(buf, "%i\n", var->u.n.value);
554 else
555 rv = sprintf(buf, "0\n");
556 break;
557 case VAR_STRING:
558 if (var) {
559 cp1 = buf;
560 *cp1++ = '"';
561 for (cp = (char *)param->p_val; (ch = *cp); cp++) {
562 if (ch >= ' ' && ch < '~')
563 *cp1++ = ch;
564 else
565 cp1 += sprintf(cp1, "\\""x%02x", ch);
566 }
567 *cp1++ = '"';
568 *cp1++ = '\n';
569 *cp1 = '\0';
570 rv = cp1-buf;
571 } else {
572 rv = sprintf(buf, "\"\"\n");
573 }
574 break;
575 default:
576 rv = sprintf(buf, "Bad parameter %s, type %i\n",
577 param->name, param->var_type);
578 break;
579 }
580 spk_unlock(flags);
581 return rv;
582}
583EXPORT_SYMBOL_GPL(spk_var_show);
584
585/*
586 * This function is called when a user echos a value to one of the
587 * variable parameters.
588 */
589ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
590 const char *buf, size_t count)
591{
592 struct st_var_header *param;
593 int ret;
594 int len;
595 char *cp;
596 struct var_t *var_data;
597 int value;
598 unsigned long flags;
599
600 param = var_header_by_name(attr->attr.name);
601 if (param == NULL)
602 return -EINVAL;
603 if (param->data == NULL)
604 return 0;
605 ret = 0;
606 cp = xlate((char *) buf);
607
608 spk_lock(flags);
609 switch (param->var_type) {
610 case VAR_NUM:
611 case VAR_TIME:
612 if (*cp == 'd' || *cp == 'r' || *cp == '\0')
613 len = E_DEFAULT;
614 else if (*cp == '+' || *cp == '-')
615 len = E_INC;
616 else
617 len = E_SET;
618 speakup_s2i(cp, &value);
619 ret = set_num_var(value, param, len);
620 if (ret == E_RANGE) {
621 var_data = param->data;
622 pr_warn("value for %s out of range, expect %d to %d\n",
623 attr->attr.name,
624 var_data->u.n.low, var_data->u.n.high);
625 }
626 break;
627 case VAR_STRING:
628 len = strlen(buf);
629 if ((len >= 1) && (buf[len - 1] == '\n'))
630 --len;
631 if ((len >= 2) && (buf[0] == '"') && (buf[len - 1] == '"')) {
632 ++buf;
633 len -= 2;
634 }
635 cp = (char *) buf;
636 cp[len] = '\0';
637 ret = set_string_var(buf, param, len);
638 if (ret == E_TOOLONG)
639 pr_warn("value too long for %s\n",
640 attr->attr.name);
641 break;
642 default:
643 pr_warn("%s unknown type %d\n",
644 param->name, (int)param->var_type);
645 break;
646 }
647 /*
648 * If voice was just changed, we might need to reset our default
649 * pitch and volume.
650 */
651 if (strcmp(attr->attr.name, "voice") == 0) {
652 if (synth && synth->default_pitch) {
653 param = var_header_by_name("pitch");
654 if (param) {
655 set_num_var(synth->default_pitch[value], param, E_NEW_DEFAULT);
656 set_num_var(0, param, E_DEFAULT);
657 }
658 }
659 if (synth && synth->default_vol) {
660 param = var_header_by_name("vol");
661 if (param) {
662 set_num_var(synth->default_vol[value], param, E_NEW_DEFAULT);
663 set_num_var(0, param, E_DEFAULT);
664 }
665 }
666 }
667 spk_unlock(flags);
668
669 if (ret == SET_DEFAULT)
670 pr_info("%s reset to default value\n", attr->attr.name);
671 return count;
672}
673EXPORT_SYMBOL_GPL(spk_var_store);
674
675/*
676 * Functions for reading and writing lists of i18n messages. Incomplete.
677 */
678
679static ssize_t message_show_helper(char *buf, enum msg_index_t first,
680 enum msg_index_t last)
681{
682 size_t bufsize = PAGE_SIZE;
683 char *buf_pointer = buf;
684 int printed;
685 enum msg_index_t cursor;
686 int index = 0;
687 *buf_pointer = '\0'; /* buf_pointer always looking at a NUL byte. */
688
689 for (cursor = first; cursor <= last; cursor++, index++) {
690 if (bufsize <= 1)
691 break;
692 printed = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
693 index, msg_get(cursor));
694 buf_pointer += printed;
695 bufsize -= printed;
696 }
697
698 return buf_pointer - buf;
699}
700
701static void report_msg_status(int reset, int received, int used,
702 int rejected, char *groupname)
703{
704 int len;
705 char buf[160];
706
707 if (reset) {
708 pr_info("i18n messages from group %s reset to defaults\n",
709 groupname);
710 } else if (received ) {
711 len = snprintf(buf, sizeof(buf),
712 " updated %d of %d i18n messages from group %s\n",
713 used, received, groupname);
714 if (rejected)
715 snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
716 " with %d reject%s\n",
717 rejected, rejected > 1 ? "s" : "");
718 printk(buf);
719 }
720}
721
722static ssize_t message_store_helper(const char *buf, size_t count,
723 struct msg_group_t *group)
724{
725 char *cp = (char *) buf;
726 char *end = cp + count;
727 char *linefeed = NULL;
728 char *temp = NULL;
729 ssize_t msg_stored = 0;
730 ssize_t retval = count;
731 size_t desc_length = 0;
732 unsigned long index = 0;
733 int received = 0;
734 int used = 0;
735 int rejected = 0;
736 int reset = 0;
737 enum msg_index_t firstmessage = group->start;
738 enum msg_index_t lastmessage = group->end;
739 enum msg_index_t curmessage;
740
741 while (cp < end) {
742
743 while ((cp < end) && (*cp == ' ' || *cp == '\t'))
744 cp++;
745
746 if (cp == end)
747 break;
748 if (strchr("dDrR", *cp)) {
749 reset = 1;
750 break;
751 }
752 received++;
753
754 linefeed = strchr(cp, '\n');
755 if (!linefeed) {
756 rejected++;
757 break;
758 }
759
760 if (! isdigit(*cp)) {
761 rejected++;
762 cp = linefeed + 1;
763 continue;
764 }
765
766 index = simple_strtoul(cp, &temp, 10);
767
768 while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
769 temp++;
770
771 desc_length = linefeed - temp;
772 curmessage = firstmessage + index;
773
774 /*
775 * Note the check (curmessage < firstmessage). It is not
776 * redundant. Suppose that the user gave us an index
777 * equal to ULONG_MAX - 1. If firstmessage > 1, then
778 * firstmessage + index < firstmessage!
779 */
780
781 if ((curmessage < firstmessage) || (curmessage > lastmessage)) {
782 rejected++;
783 cp = linefeed + 1;
784 continue;
785 }
786
787 msg_stored = msg_set(curmessage, temp, desc_length);
788 if (msg_stored < 0) {
789 retval = msg_stored;
790 if (msg_stored == -ENOMEM)
791 reset = 1;
792 break;
793 } else {
794 used++;
795 }
796
797 cp = linefeed + 1;
798 }
799
800 if (reset)
801 reset_msg_group(group);
802
803 report_msg_status(reset, received, used, rejected, group->name);
804 return retval;
805}
806
807static ssize_t message_show(struct kobject *kobj,
808 struct kobj_attribute *attr, char *buf)
809{
810 ssize_t retval = 0;
811 struct msg_group_t *group = find_msg_group(attr->attr.name);
812 unsigned long flags;
813
814 BUG_ON(! group);
815 spk_lock(flags);
816 retval = message_show_helper(buf, group->start, group->end);
817 spk_unlock(flags);
818 return retval;
819}
820
821static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr,
822 const char *buf, size_t count)
823{
824 ssize_t retval = 0;
825 struct msg_group_t *group = find_msg_group(attr->attr.name);
826
827 BUG_ON(! group);
828 retval = message_store_helper(buf, count, group);
829 return retval;
830}
831
832/*
833 * Declare the attributes.
834 */
835static struct kobj_attribute keymap_attribute =
836 __ATTR(keymap, ROOT_W, keymap_show, keymap_store);
837static struct kobj_attribute silent_attribute =
838 __ATTR(silent, USER_W, NULL, silent_store);
839static struct kobj_attribute synth_attribute =
840 __ATTR(synth, USER_RW, synth_show, synth_store);
841static struct kobj_attribute synth_direct_attribute =
842 __ATTR(synth_direct, USER_W, NULL, synth_direct_store);
843static struct kobj_attribute version_attribute =
844 __ATTR_RO(version);
845
846static struct kobj_attribute delimiters_attribute =
847 __ATTR(delimiters, USER_RW, punc_show, punc_store);
848static struct kobj_attribute ex_num_attribute =
849 __ATTR(ex_num, USER_RW, punc_show, punc_store);
850static struct kobj_attribute punc_all_attribute =
851 __ATTR(punc_all, USER_RW, punc_show, punc_store);
852static struct kobj_attribute punc_most_attribute =
853 __ATTR(punc_most, USER_RW, punc_show, punc_store);
854static struct kobj_attribute punc_some_attribute =
855 __ATTR(punc_some, USER_RW, punc_show, punc_store);
856static struct kobj_attribute repeats_attribute =
857 __ATTR(repeats, USER_RW, punc_show, punc_store);
858
859static struct kobj_attribute attrib_bleep_attribute =
860 __ATTR(attrib_bleep, USER_RW, spk_var_show, spk_var_store);
861static struct kobj_attribute bell_pos_attribute =
862 __ATTR(bell_pos, USER_RW, spk_var_show, spk_var_store);
863static struct kobj_attribute bleep_time_attribute =
864 __ATTR(bleep_time, USER_RW, spk_var_show, spk_var_store);
865static struct kobj_attribute bleeps_attribute =
866 __ATTR(bleeps, USER_RW, spk_var_show, spk_var_store);
867static struct kobj_attribute cursor_time_attribute =
868 __ATTR(cursor_time, USER_RW, spk_var_show, spk_var_store);
869static struct kobj_attribute key_echo_attribute =
870 __ATTR(key_echo, USER_RW, spk_var_show, spk_var_store);
871static struct kobj_attribute no_interrupt_attribute =
872 __ATTR(no_interrupt, USER_RW, spk_var_show, spk_var_store);
873static struct kobj_attribute punc_level_attribute =
874 __ATTR(punc_level, USER_RW, spk_var_show, spk_var_store);
875static struct kobj_attribute reading_punc_attribute =
876 __ATTR(reading_punc, USER_RW, spk_var_show, spk_var_store);
877static struct kobj_attribute say_control_attribute =
878 __ATTR(say_control, USER_RW, spk_var_show, spk_var_store);
879static struct kobj_attribute say_word_ctl_attribute =
880 __ATTR(say_word_ctl, USER_RW, spk_var_show, spk_var_store);
881static struct kobj_attribute spell_delay_attribute =
882 __ATTR(spell_delay, USER_RW, spk_var_show, spk_var_store);
883
884/*
885 * These attributes are i18n related.
886 */
887static struct kobj_attribute announcements_attribute =
888 __ATTR(announcements, USER_RW, message_show, message_store);
889static struct kobj_attribute characters_attribute =
890 __ATTR(characters, USER_RW, chars_chartab_show, chars_chartab_store);
891static struct kobj_attribute chartab_attribute =
892 __ATTR(chartab, USER_RW, chars_chartab_show, chars_chartab_store);
893static struct kobj_attribute ctl_keys_attribute =
894 __ATTR(ctl_keys, USER_RW, message_show, message_store);
895static struct kobj_attribute colors_attribute =
896 __ATTR(colors, USER_RW, message_show, message_store);
897static struct kobj_attribute formatted_attribute =
898 __ATTR(formatted, USER_RW, message_show, message_store);
899static struct kobj_attribute function_names_attribute =
900 __ATTR(function_names, USER_RW, message_show, message_store);
901static struct kobj_attribute key_names_attribute =
902 __ATTR(key_names, USER_RW, message_show, message_store);
903static struct kobj_attribute states_attribute =
904 __ATTR(states, USER_RW, message_show, message_store);
905
906/*
907 * Create groups of attributes so that we can create and destroy them all
908 * at once.
909 */
910static struct attribute *main_attrs[] = {
911 &keymap_attribute.attr,
912 &silent_attribute.attr,
913 &synth_attribute.attr,
914 &synth_direct_attribute.attr,
915 &version_attribute.attr,
916 &delimiters_attribute.attr,
917 &ex_num_attribute.attr,
918 &punc_all_attribute.attr,
919 &punc_most_attribute.attr,
920 &punc_some_attribute.attr,
921 &repeats_attribute.attr,
922 &attrib_bleep_attribute.attr,
923 &bell_pos_attribute.attr,
924 &bleep_time_attribute.attr,
925 &bleeps_attribute.attr,
926 &cursor_time_attribute.attr,
927 &key_echo_attribute.attr,
928 &no_interrupt_attribute.attr,
929 &punc_level_attribute.attr,
930 &reading_punc_attribute.attr,
931 &say_control_attribute.attr,
932 &say_word_ctl_attribute.attr,
933 &spell_delay_attribute.attr,
934 NULL,
935};
936
937static struct attribute *i18n_attrs[] = {
938 &announcements_attribute.attr,
939 &characters_attribute.attr,
940 &chartab_attribute.attr,
941 &ctl_keys_attribute.attr,
942 &colors_attribute.attr,
943 &formatted_attribute.attr,
944 &function_names_attribute.attr,
945 &key_names_attribute.attr,
946 &states_attribute.attr,
947 NULL,
948};
949
950/*
951 * An unnamed attribute group will put all of the attributes directly in
952 * the kobject directory. If we specify a name, a subdirectory will be
953 * created for the attributes with the directory being the name of the
954 * attribute group.
955 */
956static struct attribute_group main_attr_group = {
957 .attrs = main_attrs,
958};
959
960static struct attribute_group i18n_attr_group = {
961 .attrs = i18n_attrs,
962 .name = "i18n",
963};
964
965static struct kobject *accessibility_kobj;
966struct kobject *speakup_kobj;
967
968int speakup_kobj_init(void)
969{
970 int retval;
971
972 /*
973 * Create a simple kobject with the name of "accessibility",
974 * located under /sys/
975 *
976 * As this is a simple directory, no uevent will be sent to
977 * userspace. That is why this function should not be used for
978 * any type of dynamic kobjects, where the name and number are
979 * not known ahead of time.
980 */
981 accessibility_kobj = kobject_create_and_add("accessibility", NULL);
982 if (!accessibility_kobj)
983 return -ENOMEM;
984
985 speakup_kobj = kobject_create_and_add("speakup", accessibility_kobj);
986 if (!speakup_kobj) {
987 kobject_put(accessibility_kobj);
988 return -ENOMEM;
989 }
990
991 /* Create the files associated with this kobject */
992 retval = sysfs_create_group(speakup_kobj, &main_attr_group);
993 if (retval)
994 speakup_kobj_exit();
995
996 retval = sysfs_create_group(speakup_kobj, &i18n_attr_group);
997 if (retval)
998 speakup_kobj_exit();
999
1000 return retval;
1001}
1002
1003void speakup_kobj_exit(void)
1004{
1005 kobject_put(speakup_kobj);
1006 kobject_put(accessibility_kobj);
1007}
diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c
new file mode 100644
index 00000000000..8c549650f21
--- /dev/null
+++ b/drivers/staging/speakup/main.c
@@ -0,0 +1,2304 @@
1/* speakup.c
2 review functions for the speakup screen review package.
3 originally written by: Kirk Reiser and Andy Berdan.
4
5 extensively modified by David Borowski.
6
7 Copyright (C) 1998 Kirk Reiser.
8 Copyright (C) 2003 David Borowski.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23*/
24
25#include <linux/kernel.h>
26#include <linux/version.h>
27#include <linux/vt.h>
28#include <linux/tty.h>
29#include <linux/mm.h> /* __get_free_page() and friends */
30#include <linux/vt_kern.h>
31#include <linux/ctype.h>
32#include <linux/selection.h>
33#include <linux/unistd.h>
34#include <linux/jiffies.h>
35#include <linux/kthread.h>
36#include <linux/keyboard.h> /* for KT_SHIFT */
37#include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
38#include <linux/input.h>
39#include <linux/kmod.h>
40
41#include <linux/bootmem.h> /* for alloc_bootmem */
42
43/* speakup_*_selection */
44#include <linux/module.h>
45#include <linux/sched.h>
46#include <linux/slab.h>
47#include <linux/types.h>
48#include <linux/consolemap.h>
49
50#include <linux/spinlock.h>
51#include <linux/notifier.h>
52
53#include <linux/uaccess.h> /* copy_from|to|user() and others */
54
55#include "spk_priv.h"
56#include "speakup.h"
57
58#define MAX_DELAY msecs_to_jiffies(500)
59#define MINECHOCHAR SPACE
60
61MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
62MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
63MODULE_DESCRIPTION("Speakup console speech");
64MODULE_LICENSE("GPL");
65MODULE_VERSION(SPEAKUP_VERSION);
66
67char *synth_name;
68module_param_named(synth, synth_name, charp, S_IRUGO);
69module_param_named(quiet, quiet_boot, bool, S_IRUGO);
70
71MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
72MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
73
74special_func special_handler;
75
76short pitch_shift, synth_flags;
77static char buf[256];
78int attrib_bleep, bleeps, bleep_time = 10;
79int no_intr, spell_delay;
80int key_echo, say_word_ctl;
81int say_ctrl, bell_pos;
82short punc_mask;
83int punc_level, reading_punc;
84char str_caps_start[MAXVARLEN+1] = "\0", str_caps_stop[MAXVARLEN+1] = "\0";
85const struct st_bits_data punc_info[] = {
86 { "none", "", 0 },
87 { "some", "/$%&@", SOME },
88 { "most", "$%&#()=+*/@^<>|\\", MOST },
89 { "all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC },
90 { "delimiters", "", B_WDLM },
91 { "repeats", "()", CH_RPT },
92 { "extended numeric", "", B_EXNUM },
93 { "symbols", "", B_SYM },
94 { 0, 0 }
95};
96static char mark_cut_flag;
97#define MAX_KEY 160
98u_char *our_keys[MAX_KEY], *shift_table;
99u_char key_buf[600];
100const u_char key_defaults[] = {
101#include "speakupmap.h"
102};
103
104/* Speakup Cursor Track Variables */
105static int cursor_track = 1, prev_cursor_track = 1;
106
107/* cursor track modes, must be ordered same as cursor_msgs */
108enum {
109 CT_Off = 0,
110 CT_On,
111 CT_Highlight,
112 CT_Window,
113 CT_Max
114};
115#define read_all_mode CT_Max
116
117static struct tty_struct *tty;
118
119static void spkup_write(const char *in_buf, int count);
120
121
122static char *phonetic[] = {
123 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
124 "india", "juliett", "keelo", "leema", "mike", "november", "oscar", "papa",
125 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
126 "x ray", "yankee", "zulu"
127};
128
129/* array of 256 char pointers (one for each character description)
130 * initialized to default_chars and user selectable via
131 * /proc/speakup/characters */
132char *characters[256];
133
134char *default_chars[256] = {
135/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
136/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
137/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
138/*024*/ "^x", "^y", "^z", "control", "control", "control", "control", "control",
139/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and", "tick",
140/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash", "dot",
141 "slash",
142/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
143 "eight", "nine",
144/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
145/*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
146/*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
147/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
148/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket", "caret",
149 "line",
150/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
151/*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
152/*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
153/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
154/*127*/ "del", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control",
155/*138*/ "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control", "control",
156/*150*/ "control", "control", "control", "control", "control", "control", "control", "control", "control", "control",
157/*160*/ "nbsp", "inverted bang",
158/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
159/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
160/*172*/ "not", "soft hyphen", "registered", "macron",
161/*176*/ "degrees", "plus or minus", "super two", "super three",
162/*180*/ "acute accent", "micro", "pilcrow", "middle dot",
163/*184*/ "cedilla", "super one", "male ordinal", "double right angle",
164/*188*/ "one quarter", "one half", "three quarters", "inverted question",
165/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT", "A RING",
166/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX", "E OOMLAUT",
167/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH", "N TILDE",
168/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
169/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE", "U CIRCUMFLEX",
170/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
171/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
172/*230*/ "ae", "c cidella", "e grave", "e acute",
173/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute", "i circumflex",
174/*239*/ "i oomlaut", "eth", "n tilde","o grave", "o acute", "o circumflex",
175/*245*/"o tilde", "o oomlaut", "divided by", "o stroke", "u grave", "u acute",
176/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
177};
178
179/* array of 256 u_short (one for each character)
180 * initialized to default_chartab and user selectable via
181 * /sys/module/speakup/parameters/chartab */
182u_short spk_chartab[256];
183
184static u_short default_chartab[256] = {
185 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
186 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
187 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
188 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
189WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
190PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
191NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
192NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
193PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
194A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
195A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
196A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
197PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
198ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
199ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
200ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
201B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-135 */
202B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 136-143 */
203B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 144-151 */
204B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 152-159 */
205WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, B_SYM, /* 160-167 */
206B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
207B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
208B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
209A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
210A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
211A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
212A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
213ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
214ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
215ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
216ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
217};
218
219struct task_struct *speakup_task;
220struct bleep unprocessed_sound;
221static int spk_keydown;
222static u_char spk_lastkey, spk_close_press, keymap_flags;
223static u_char last_keycode, this_speakup_key;
224static u_long last_spk_jiffy;
225
226struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
227
228DEFINE_MUTEX(spk_mutex);
229
230static int keyboard_notifier_call(struct notifier_block *,
231 unsigned long code, void *param);
232
233struct notifier_block keyboard_notifier_block = {
234 .notifier_call = keyboard_notifier_call,
235};
236
237static int vt_notifier_call(struct notifier_block *,
238 unsigned long code, void *param);
239
240struct notifier_block vt_notifier_block = {
241 .notifier_call = vt_notifier_call,
242};
243
244static unsigned char get_attributes(u16 *pos)
245{
246 return (u_char)(scr_readw(pos) >> 8);
247}
248
249static void speakup_date(struct vc_data *vc)
250{
251 spk_x = spk_cx = vc->vc_x;
252 spk_y = spk_cy = vc->vc_y;
253 spk_pos = spk_cp = vc->vc_pos;
254 spk_old_attr = spk_attr;
255 spk_attr = get_attributes((u_short *) spk_pos);
256}
257
258static void bleep(u_short val)
259{
260 static const short vals[] = {
261 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
262 };
263 short freq;
264 int time = bleep_time;
265 freq = vals[val%12];
266 if (val > 11)
267 freq *= (1 << (val/12));
268 unprocessed_sound.freq = freq;
269 unprocessed_sound.jiffies = msecs_to_jiffies(time);
270 unprocessed_sound.active = 1;
271 /* We can only have 1 active sound at a time. */
272}
273
274static void speakup_shut_up(struct vc_data *vc)
275{
276 if (spk_killed)
277 return;
278 spk_shut_up |= 0x01;
279 spk_parked &= 0xfe;
280 speakup_date(vc);
281 if (synth != NULL)
282 do_flush();
283}
284
285static void speech_kill(struct vc_data *vc)
286{
287 char val = synth->is_alive(synth);
288 if (val == 0)
289 return;
290
291 /* re-enables synth, if disabled */
292 if (val == 2 || spk_killed) {
293 /* dead */
294 spk_shut_up &= ~0x40;
295 synth_printf("%s\n", msg_get(MSG_IAM_ALIVE));
296 } else {
297 synth_printf("%s\n", msg_get(MSG_YOU_KILLED_SPEAKUP));
298 spk_shut_up |= 0x40;
299 }
300}
301
302static void speakup_off(struct vc_data *vc)
303{
304 if (spk_shut_up & 0x80) {
305 spk_shut_up &= 0x7f;
306 synth_printf("%s\n", msg_get(MSG_HEY_THATS_BETTER));
307 } else {
308 spk_shut_up |= 0x80;
309 synth_printf("%s\n", msg_get(MSG_YOU_TURNED_ME_OFF));
310 }
311 speakup_date(vc);
312}
313
314static void speakup_parked(struct vc_data *vc)
315{
316 if (spk_parked & 0x80) {
317 spk_parked = 0;
318 synth_printf("%s\n", msg_get(MSG_UNPARKED));
319 } else {
320 spk_parked |= 0x80;
321 synth_printf("%s\n", msg_get(MSG_PARKED));
322 }
323}
324
325static void speakup_cut(struct vc_data *vc)
326{
327 static const char err_buf[] = "set selection failed";
328 int ret;
329
330 if (!mark_cut_flag) {
331 mark_cut_flag = 1;
332 xs = (u_short) spk_x;
333 ys = (u_short) spk_y;
334 spk_sel_cons = vc;
335 synth_printf("%s\n", msg_get(MSG_MARK));
336 return;
337 }
338 xe = (u_short) spk_x;
339 ye = (u_short) spk_y;
340 mark_cut_flag = 0;
341 synth_printf("%s\n", msg_get(MSG_CUT));
342
343 speakup_clear_selection();
344 ret = speakup_set_selection(tty);
345
346 switch (ret) {
347 case 0:
348 break; /* no error */
349 case -EFAULT :
350 pr_warn("%sEFAULT\n", err_buf);
351 break;
352 case -EINVAL :
353 pr_warn("%sEINVAL\n", err_buf);
354 break;
355 case -ENOMEM :
356 pr_warn("%sENOMEM\n", err_buf);
357 break;
358 }
359}
360
361static void speakup_paste(struct vc_data *vc)
362{
363 if (mark_cut_flag) {
364 mark_cut_flag = 0;
365 synth_printf("%s\n", msg_get(MSG_MARK_CLEARED));
366 } else {
367 synth_printf("%s\n", msg_get(MSG_PASTE));
368 speakup_paste_selection(tty);
369 }
370}
371
372static void say_attributes(struct vc_data *vc)
373{
374 int fg = spk_attr & 0x0f;
375 int bg = spk_attr >> 4;
376 if (fg > 8) {
377 synth_printf("%s ", msg_get(MSG_BRIGHT));
378 fg -= 8;
379 }
380 synth_printf("%s", msg_get(MSG_COLORS_START + fg));
381 if (bg > 7) {
382 synth_printf(" %s ", msg_get(MSG_ON_BLINKING));
383 bg -= 8;
384 } else
385 synth_printf(" %s ", msg_get(MSG_ON));
386 synth_printf("%s\n", msg_get(MSG_COLORS_START + bg));
387}
388
389enum {
390 edge_top = 1,
391 edge_bottom,
392 edge_left,
393 edge_right,
394 edge_quiet
395};
396
397static void announce_edge(struct vc_data *vc, int msg_id)
398{
399 if (bleeps & 1)
400 bleep(spk_y);
401 if ((bleeps & 2) && (msg_id < edge_quiet))
402 synth_printf("%s\n", msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
403}
404
405static void speak_char(u_char ch)
406{
407 char *cp = characters[ch];
408 struct var_t *direct = get_var(DIRECT);
409 if (direct && direct->u.n.value) {
410 if (IS_CHAR(ch, B_CAP)) {
411 pitch_shift++;
412 synth_printf("%s", str_caps_start);
413 }
414 synth_printf("%c", ch);
415 if (IS_CHAR(ch, B_CAP))
416 synth_printf("%s", str_caps_stop);
417 return;
418 }
419 if (cp == NULL) {
420 pr_info("speak_char: cp == NULL!\n");
421 return;
422 }
423 synth_buffer_add(SPACE);
424 if (IS_CHAR(ch, B_CAP)) {
425 pitch_shift++;
426 synth_printf("%s", str_caps_start);
427 synth_printf("%s", cp);
428 synth_printf("%s", str_caps_stop);
429 } else {
430 if (*cp == '^') {
431 synth_printf("%s", msg_get(MSG_CTRL));
432 cp++;
433 }
434 synth_printf("%s", cp);
435 }
436 synth_buffer_add(SPACE);
437}
438
439static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
440{
441 u16 ch = ' ';
442 if (vc && pos) {
443 u16 w = scr_readw(pos);
444 u16 c = w & 0xff;
445
446 if (w & vc->vc_hi_font_mask)
447 c |= 0x100;
448
449 ch = inverse_translate(vc, c, 0);
450 *attribs = (w & 0xff00) >> 8;
451 }
452 return ch;
453}
454
455static void say_char(struct vc_data *vc)
456{
457 u_short ch;
458 spk_old_attr = spk_attr;
459 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
460 if (spk_attr != spk_old_attr) {
461 if (attrib_bleep & 1)
462 bleep(spk_y);
463 if (attrib_bleep & 2)
464 say_attributes(vc);
465 }
466 speak_char(ch & 0xff);
467}
468
469static void say_phonetic_char(struct vc_data *vc)
470{
471 u_short ch;
472 spk_old_attr = spk_attr;
473 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
474 if (isascii(ch) && isalpha(ch)) {
475 ch &= 0x1f;
476 synth_printf("%s\n", phonetic[--ch]);
477 } else {
478 if (IS_CHAR(ch, B_NUM))
479 synth_printf("%s ", msg_get(MSG_NUMBER));
480 speak_char(ch);
481 }
482}
483
484static void say_prev_char(struct vc_data *vc)
485{
486 spk_parked |= 0x01;
487 if (spk_x == 0) {
488 announce_edge(vc, edge_left);
489 return;
490 }
491 spk_x--;
492 spk_pos -= 2;
493 say_char(vc);
494}
495
496static void say_next_char(struct vc_data *vc)
497{
498 spk_parked |= 0x01;
499 if (spk_x == vc->vc_cols - 1) {
500 announce_edge(vc, edge_right);
501 return;
502 }
503 spk_x++;
504 spk_pos += 2;
505 say_char(vc);
506}
507
508/* get_word - will first check to see if the character under the
509 reading cursor is a space and if say_word_ctl is true it will
510 return the word space. If say_word_ctl is not set it will check to
511 see if there is a word starting on the next position to the right
512 and return that word if it exists. If it does not exist it will
513 move left to the beginning of any previous word on the line or the
514 beginning off the line whichever comes first.. */
515
516static u_long get_word(struct vc_data *vc)
517{
518 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
519 char ch;
520 u_short attr_ch;
521 u_char temp;
522 spk_old_attr = spk_attr;
523 ch = (char) get_char(vc, (u_short *) tmp_pos, &temp);
524
525/* decided to take out the sayword if on a space (mis-information */
526 if (say_word_ctl && ch == SPACE) {
527 *buf = '\0';
528 synth_printf("%s\n", msg_get(MSG_SPACE));
529 return 0;
530 } else if ((tmpx < vc->vc_cols - 2)
531 && (ch == SPACE || ch == 0 || IS_WDLM(ch))
532 && ((char) get_char(vc, (u_short *) &tmp_pos+1, &temp) > SPACE)) {
533 tmp_pos += 2;
534 tmpx++;
535 } else
536 while (tmpx > 0) {
537 ch = (char) get_char(vc, (u_short *) tmp_pos - 1, &temp);
538 if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
539 && ((char) get_char(vc, (u_short *) tmp_pos, &temp) >
540 SPACE))
541 break;
542 tmp_pos -= 2;
543 tmpx--;
544 }
545 attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
546 buf[cnt++] = attr_ch & 0xff;
547 while (tmpx < vc->vc_cols - 1) {
548 tmp_pos += 2;
549 tmpx++;
550 ch = (char) get_char(vc, (u_short *) tmp_pos, &temp);
551 if ((ch == SPACE) || ch == 0 || (IS_WDLM(buf[cnt-1]) && (ch > SPACE)))
552 break;
553 buf[cnt++] = ch;
554 }
555 buf[cnt] = '\0';
556 return cnt;
557}
558
559static void say_word(struct vc_data *vc)
560{
561 u_long cnt = get_word(vc);
562 u_short saved_punc_mask = punc_mask;
563 if (cnt == 0)
564 return;
565 punc_mask = PUNC;
566 buf[cnt++] = SPACE;
567 spkup_write(buf, cnt);
568 punc_mask = saved_punc_mask;
569}
570
571static void say_prev_word(struct vc_data *vc)
572{
573 u_char temp;
574 char ch;
575 u_short edge_said = 0, last_state = 0, state = 0;
576 spk_parked |= 0x01;
577
578 if (spk_x == 0) {
579 if (spk_y == 0) {
580 announce_edge(vc, edge_top);
581 return;
582 }
583 spk_y--;
584 spk_x = vc->vc_cols;
585 edge_said = edge_quiet;
586 }
587 while (1) {
588 if (spk_x == 0) {
589 if (spk_y == 0) {
590 edge_said = edge_top;
591 break;
592 }
593 if (edge_said != edge_quiet)
594 edge_said = edge_left;
595 if (state > 0)
596 break;
597 spk_y--;
598 spk_x = vc->vc_cols - 1;
599 } else
600 spk_x--;
601 spk_pos -= 2;
602 ch = (char) get_char(vc, (u_short *) spk_pos, &temp);
603 if (ch == SPACE || ch == 0)
604 state = 0;
605 else if (IS_WDLM(ch))
606 state = 1;
607 else
608 state = 2;
609 if (state < last_state) {
610 spk_pos += 2;
611 spk_x++;
612 break;
613 }
614 last_state = state;
615 }
616 if (spk_x == 0 && edge_said == edge_quiet)
617 edge_said = edge_left;
618 if (edge_said > 0 && edge_said < edge_quiet)
619 announce_edge(vc, edge_said);
620 say_word(vc);
621}
622
623static void say_next_word(struct vc_data *vc)
624{
625 u_char temp;
626 char ch;
627 u_short edge_said = 0, last_state = 2, state = 0;
628 spk_parked |= 0x01;
629
630 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
631 announce_edge(vc, edge_bottom);
632 return;
633 }
634 while (1) {
635 ch = (char) get_char(vc, (u_short *) spk_pos, &temp);
636 if (ch == SPACE || ch == 0)
637 state = 0;
638 else if (IS_WDLM(ch))
639 state = 1;
640 else
641 state = 2;
642 if (state > last_state)
643 break;
644 if (spk_x >= vc->vc_cols - 1) {
645 if (spk_y == vc->vc_rows - 1) {
646 edge_said = edge_bottom;
647 break;
648 }
649 state = 0;
650 spk_y++;
651 spk_x = 0;
652 edge_said = edge_right;
653 } else
654 spk_x++;
655 spk_pos += 2;
656 last_state = state;
657 }
658 if (edge_said > 0)
659 announce_edge(vc, edge_said);
660 say_word(vc);
661}
662
663static void spell_word(struct vc_data *vc)
664{
665 static char *delay_str[] = { "", ",", ".", ". .", ". . ." };
666 char *cp = buf, *str_cap = str_caps_stop;
667 char *cp1, *last_cap = str_caps_stop;
668 u_char ch;
669 if (!get_word(vc))
670 return;
671 while ((ch = (u_char) *cp)) {
672 if (cp != buf)
673 synth_printf(" %s ", delay_str[spell_delay]);
674 if (IS_CHAR(ch, B_CAP)) {
675 str_cap = str_caps_start;
676 if (*str_caps_stop)
677 pitch_shift++;
678 else /* synth has no pitch */
679 last_cap = str_caps_stop;
680 } else
681 str_cap = str_caps_stop;
682 if (str_cap != last_cap) {
683 synth_printf("%s", str_cap);
684 last_cap = str_cap;
685 }
686 if (this_speakup_key == SPELL_PHONETIC
687 && (isascii(ch) && isalpha(ch))) {
688 ch &= 31;
689 cp1 = phonetic[--ch];
690 } else {
691 cp1 = characters[ch];
692 if (*cp1 == '^') {
693 synth_printf("%s", msg_get(MSG_CTRL));
694 cp1++;
695 }
696 }
697 synth_printf("%s", cp1);
698 cp++;
699 }
700 if (str_cap != str_caps_stop)
701 synth_printf("%s", str_caps_stop);
702}
703
704static int get_line(struct vc_data *vc)
705{
706 u_long tmp = spk_pos - (spk_x * 2);
707 int i = 0;
708 u_char tmp2;
709
710 spk_old_attr = spk_attr;
711 spk_attr = get_attributes((u_short *) spk_pos);
712 for (i = 0; i < vc->vc_cols; i++) {
713 buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
714 tmp += 2;
715 }
716 for (--i; i >= 0; i--)
717 if (buf[i] != SPACE)
718 break;
719 return ++i;
720}
721
722static void say_line(struct vc_data *vc)
723{
724 int i = get_line(vc);
725 char *cp;
726 u_short saved_punc_mask = punc_mask;
727 if (i == 0) {
728 synth_printf("%s\n", msg_get(MSG_BLANK));
729 return;
730 }
731 buf[i++] = '\n';
732 if (this_speakup_key == SAY_LINE_INDENT) {
733 for (cp = buf; *cp == SPACE; cp++)
734 ;
735 synth_printf("%d, ", (cp - buf) + 1);
736 }
737 punc_mask = punc_masks[reading_punc];
738 spkup_write(buf, i);
739 punc_mask = saved_punc_mask;
740}
741
742static void say_prev_line(struct vc_data *vc)
743{
744 spk_parked |= 0x01;
745 if (spk_y == 0) {
746 announce_edge(vc, edge_top);
747 return;
748 }
749 spk_y--;
750 spk_pos -= vc->vc_size_row;
751 say_line(vc);
752}
753
754static void say_next_line(struct vc_data *vc)
755{
756 spk_parked |= 0x01;
757 if (spk_y == vc->vc_rows - 1) {
758 announce_edge(vc, edge_bottom);
759 return;
760 }
761 spk_y++;
762 spk_pos += vc->vc_size_row;
763 say_line(vc);
764}
765
766static int say_from_to(struct vc_data *vc, u_long from, u_long to,
767 int read_punc)
768{
769 int i = 0;
770 u_char tmp;
771 u_short saved_punc_mask = punc_mask;
772 spk_old_attr = spk_attr;
773 spk_attr = get_attributes((u_short *) from);
774 while (from < to) {
775 buf[i++] = (char) get_char(vc, (u_short *) from, &tmp);
776 from += 2;
777 if (i >= vc->vc_size_row)
778 break;
779 }
780 for (--i; i >= 0; i--)
781 if (buf[i] != SPACE)
782 break;
783 buf[++i] = SPACE;
784 buf[++i] = '\0';
785 if (i < 1)
786 return i;
787 if (read_punc)
788 punc_mask = punc_info[reading_punc].mask;
789 spkup_write(buf, i);
790 if (read_punc)
791 punc_mask = saved_punc_mask;
792 return i - 1;
793}
794
795static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
796 int read_punc)
797{
798 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
799 u_long end = start + (to * 2);
800 start += from * 2;
801 if (say_from_to(vc, start, end, read_punc) <= 0)
802 if (cursor_track != read_all_mode)
803 synth_printf("%s\n", msg_get(MSG_BLANK));
804}
805
806/* Sentence Reading Commands */
807
808void synth_insert_next_index(int);
809
810static int currsentence;
811static int numsentences[2];
812static char *sentbufend[2];
813static char *sentmarks[2][10];
814static int currbuf;
815static int bn;
816static char sentbuf[2][256];
817
818static int say_sentence_num(int num , int prev)
819{
820 bn = currbuf;
821 currsentence = num + 1;
822 if (prev && --bn == -1)
823 bn = 1;
824
825 if (num > numsentences[bn])
826 return 0;
827
828 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
829 return 1;
830}
831
832static int get_sentence_buf(struct vc_data *vc, int read_punc)
833{
834 u_long start, end;
835 int i, bn;
836 u_char tmp;
837
838 currbuf++;
839 if (currbuf == 2)
840 currbuf = 0;
841 bn = currbuf;
842 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
843 end = vc->vc_origin+((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
844
845 numsentences[bn] = 0;
846 sentmarks[bn][0] = &sentbuf[bn][0];
847 i = 0;
848 spk_old_attr = spk_attr;
849 spk_attr = get_attributes((u_short *) start);
850
851 while (start < end) {
852 sentbuf[bn][i] = (char) get_char(vc, (u_short *) start, &tmp);
853 if (i > 0) {
854 if (sentbuf[bn][i] == SPACE && sentbuf[bn][i-1] == '.'
855 && numsentences[bn] < 9) {
856 /* Sentence Marker */
857 numsentences[bn]++;
858 sentmarks[bn][numsentences[bn]] =
859 &sentbuf[bn][i];
860 }
861 }
862 i++;
863 start += 2;
864 if (i >= vc->vc_size_row)
865 break;
866 }
867
868 for (--i; i >= 0; i--)
869 if (sentbuf[bn][i] != SPACE)
870 break;
871
872 if (i < 1)
873 return -1;
874
875 sentbuf[bn][++i] = SPACE;
876 sentbuf[bn][++i] = '\0';
877
878 sentbufend[bn] = &sentbuf[bn][i];
879 return numsentences[bn];
880}
881
882static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
883{
884 u_long start = vc->vc_origin, end;
885 if (from > 0)
886 start += from * vc->vc_size_row;
887 if (to > vc->vc_rows)
888 to = vc->vc_rows;
889 end = vc->vc_origin + (to * vc->vc_size_row);
890 for (from = start; from < end; from = to) {
891 to = from + vc->vc_size_row;
892 say_from_to(vc, from, to, 1);
893 }
894}
895
896static void say_screen(struct vc_data *vc)
897{
898 say_screen_from_to(vc, 0, vc->vc_rows);
899}
900
901static void speakup_win_say(struct vc_data *vc)
902{
903 u_long start, end, from, to;
904 if (win_start < 2) {
905 synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
906 return;
907 }
908 start = vc->vc_origin + (win_top * vc->vc_size_row);
909 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
910 while (start <= end) {
911 from = start + (win_left * 2);
912 to = start + (win_right * 2);
913 say_from_to(vc, from, to, 1);
914 start += vc->vc_size_row;
915 }
916}
917
918static void top_edge(struct vc_data *vc)
919{
920 spk_parked |= 0x01;
921 spk_pos = vc->vc_origin + 2 * spk_x;
922 spk_y = 0;
923 say_line(vc);
924}
925
926static void bottom_edge(struct vc_data *vc)
927{
928 spk_parked |= 0x01;
929 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
930 spk_y = vc->vc_rows - 1;
931 say_line(vc);
932}
933
934static void left_edge(struct vc_data *vc)
935{
936 spk_parked |= 0x01;
937 spk_pos -= spk_x * 2;
938 spk_x = 0;
939 say_char(vc);
940}
941
942static void right_edge(struct vc_data *vc)
943{
944 spk_parked |= 0x01;
945 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
946 spk_x = vc->vc_cols - 1;
947 say_char(vc);
948}
949
950static void say_first_char(struct vc_data *vc)
951{
952 int i, len = get_line(vc);
953 u_char ch;
954 spk_parked |= 0x01;
955 if (len == 0) {
956 synth_printf("%s\n", msg_get(MSG_BLANK));
957 return;
958 }
959 for (i = 0; i < len; i++)
960 if (buf[i] != SPACE)
961 break;
962 ch = buf[i];
963 spk_pos -= (spk_x - i) * 2;
964 spk_x = i;
965 synth_printf("%d, ", ++i);
966 speak_char(ch);
967}
968
969static void say_last_char(struct vc_data *vc)
970{
971 int len = get_line(vc);
972 u_char ch;
973 spk_parked |= 0x01;
974 if (len == 0) {
975 synth_printf("%s\n", msg_get(MSG_BLANK));
976 return;
977 }
978 ch = buf[--len];
979 spk_pos -= (spk_x - len) * 2;
980 spk_x = len;
981 synth_printf("%d, ", ++len);
982 speak_char(ch);
983}
984
985static void say_position(struct vc_data *vc)
986{
987 synth_printf(msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
988 vc->vc_num + 1);
989 synth_printf("\n");
990}
991
992/* Added by brianb */
993static void say_char_num(struct vc_data *vc)
994{
995 u_char tmp;
996 u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
997 ch &= 0xff;
998 synth_printf(msg_get(MSG_CHAR_INFO), ch, ch);
999}
1000
1001/* these are stub functions to keep keyboard.c happy. */
1002
1003static void say_from_top(struct vc_data *vc)
1004{
1005 say_screen_from_to(vc, 0, spk_y);
1006}
1007
1008static void say_to_bottom(struct vc_data *vc)
1009{
1010 say_screen_from_to(vc, spk_y, vc->vc_rows);
1011}
1012
1013static void say_from_left(struct vc_data *vc)
1014{
1015 say_line_from_to(vc, 0, spk_x, 1);
1016}
1017
1018static void say_to_right(struct vc_data *vc)
1019{
1020 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1021}
1022
1023/* end of stub functions. */
1024
1025static void spkup_write(const char *in_buf, int count)
1026{
1027 static int rep_count = 0;
1028 static u_char ch = '\0', old_ch = '\0';
1029 static u_short char_type = 0, last_type = 0;
1030 int in_count = count;
1031 spk_keydown = 0;
1032 while (count--) {
1033 if (cursor_track == read_all_mode) {
1034 /* Insert Sentence Index */
1035 if ((in_buf == sentmarks[bn][currsentence]) &&
1036 (currsentence <= numsentences[bn]))
1037 synth_insert_next_index(currsentence++);
1038 }
1039 ch = (u_char)*in_buf++;
1040 char_type = spk_chartab[ch];
1041 if (ch == old_ch && !(char_type&B_NUM)) {
1042 if (++rep_count > 2)
1043 continue;
1044 } else {
1045 if ((last_type&CH_RPT) && rep_count > 2) {
1046 synth_printf(" ");
1047 synth_printf(msg_get(MSG_REPEAT_DESC), ++rep_count);
1048 synth_printf(" ");
1049 }
1050 rep_count = 0;
1051 }
1052 if (ch == spk_lastkey) {
1053 rep_count = 0;
1054 if (key_echo == 1 && ch >= MINECHOCHAR)
1055 speak_char(ch);
1056 } else if (char_type & B_ALPHA) {
1057 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1058 synth_buffer_add(SPACE);
1059 synth_printf("%c", ch);
1060 } else if (char_type & B_NUM) {
1061 rep_count = 0;
1062 synth_printf("%c", ch);
1063 } else if (char_type&punc_mask) {
1064 speak_char(ch);
1065 char_type &= ~PUNC; /* for dec nospell processing */
1066 } else if (char_type&SYNTH_OK) {
1067/* these are usually puncts like . and , which synth needs for expression.
1068 * suppress multiple to get rid of long pausesand clear repeat count so if
1069 *someone has repeats on you don't get nothing repeated count */
1070 if (ch != old_ch)
1071 synth_printf("%c", ch);
1072 else
1073 rep_count = 0;
1074 } else {
1075/* send space and record position, if next is num overwrite space */
1076 if (old_ch != ch)
1077 synth_buffer_add(SPACE);
1078 else
1079 rep_count = 0;
1080 }
1081 old_ch = ch;
1082 last_type = char_type;
1083 }
1084 spk_lastkey = 0;
1085 if (in_count > 2 && rep_count > 2) {
1086 if (last_type&CH_RPT) {
1087 synth_printf(" ");
1088 synth_printf(msg_get(MSG_REPEAT_DESC2), ++rep_count);
1089 synth_printf(" ");
1090 }
1091 rep_count = 0;
1092 }
1093}
1094
1095static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1096
1097static void read_all_doc(struct vc_data *vc);
1098static void cursor_done(u_long data);
1099static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1100
1101static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1102{
1103 unsigned long flags;
1104 if (synth == NULL || up_flag || spk_killed)
1105 return;
1106 spk_lock(flags);
1107 if (cursor_track == read_all_mode) {
1108 switch (value) {
1109 case KVAL(K_SHIFT):
1110 del_timer(&cursor_timer);
1111 spk_shut_up &= 0xfe;
1112 do_flush();
1113 read_all_doc(vc);
1114 break;
1115 case KVAL(K_CTRL):
1116 del_timer(&cursor_timer);
1117 cursor_track = prev_cursor_track;
1118 spk_shut_up &= 0xfe;
1119 do_flush();
1120 break;
1121 }
1122 } else {
1123 spk_shut_up &= 0xfe;
1124 do_flush();
1125 }
1126 if (say_ctrl && value < NUM_CTL_LABELS)
1127 synth_printf("%s", msg_get(MSG_CTL_START + value));
1128 spk_unlock(flags);
1129}
1130
1131static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1132{
1133 unsigned long flags;
1134 spk_lock(flags);
1135 if (up_flag) {
1136 spk_lastkey = spk_keydown = 0;
1137 spk_unlock(flags);
1138 return;
1139 }
1140 if (synth == NULL || spk_killed) {
1141 spk_unlock(flags);
1142 return;
1143 }
1144 spk_shut_up &= 0xfe;
1145 spk_lastkey = value;
1146 spk_keydown++;
1147 spk_parked &= 0xfe;
1148 if (key_echo == 2 && value >= MINECHOCHAR)
1149 speak_char(value);
1150 spk_unlock(flags);
1151}
1152
1153int set_key_info(const u_char *key_info, u_char *k_buffer)
1154{
1155 int i = 0, states, key_data_len;
1156 const u_char *cp = key_info;
1157 u_char *cp1 = k_buffer;
1158 u_char ch, version, num_keys;
1159 version = *cp++;
1160 if (version != KEY_MAP_VER)
1161 return -1;
1162 num_keys = *cp;
1163 states = (int) cp[1];
1164 key_data_len = (states + 1) * (num_keys + 1);
1165 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(key_buf))
1166 return -2;
1167 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1168 memset(our_keys, 0, sizeof(our_keys));
1169 shift_table = k_buffer;
1170 our_keys[0] = shift_table;
1171 cp1 += SHIFT_TBL_SIZE;
1172 memcpy(cp1, cp, key_data_len + 3);
1173 /* get num_keys, states and data*/
1174 cp1 += 2; /* now pointing at shift states */
1175 for (i = 1; i <= states; i++) {
1176 ch = *cp1++;
1177 if (ch >= SHIFT_TBL_SIZE)
1178 return -3;
1179 shift_table[ch] = i;
1180 }
1181 keymap_flags = *cp1++;
1182 while ((ch = *cp1)) {
1183 if (ch >= MAX_KEY)
1184 return -4;
1185 our_keys[ch] = cp1;
1186 cp1 += states + 1;
1187 }
1188 return 0;
1189}
1190
1191static struct var_t spk_vars[] = {
1192 /* bell must be first to set high limit */
1193 { BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL }},
1194 { SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL }},
1195 { ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL }},
1196 { BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL }},
1197 { BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL }},
1198 { PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL }},
1199 { READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL }},
1200 { CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL }},
1201 { SAY_CONTROL, TOGGLE_0 },
1202 { SAY_WORD_CTL, TOGGLE_0 },
1203 { NO_INTERRUPT, TOGGLE_0 },
1204 { KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL }},
1205 V_LAST_VAR
1206};
1207
1208
1209static void toggle_cursoring(struct vc_data *vc)
1210{
1211 if (cursor_track == read_all_mode)
1212 cursor_track = prev_cursor_track;
1213 if (++cursor_track >= CT_Max)
1214 cursor_track = 0;
1215 synth_printf("%s\n", msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1216}
1217
1218void reset_default_chars(void)
1219{
1220 int i;
1221
1222 /* First, free any non-default */
1223 for (i = 0; i < 256; i++) {
1224 if ((characters[i] != NULL)
1225 && (characters[i] != default_chars[i]))
1226 kfree(characters[i]);
1227 }
1228
1229 memcpy(characters, default_chars, sizeof(default_chars));
1230}
1231
1232void reset_default_chartab(void)
1233{
1234 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1235}
1236
1237static const struct st_bits_data *pb_edit = NULL;
1238
1239static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1240{
1241 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1242 if (type != KT_LATIN || (ch_type&B_NUM) || ch < SPACE)
1243 return -1;
1244 if (ch == SPACE) {
1245 synth_printf("%s\n", msg_get(MSG_EDIT_DONE));
1246 special_handler = NULL;
1247 return 1;
1248 }
1249 if (mask < PUNC && !(ch_type&PUNC))
1250 return -1;
1251 spk_chartab[ch] ^= mask;
1252 speak_char(ch);
1253 synth_printf(" %s\n",
1254 (spk_chartab[ch]&mask) ? msg_get(MSG_ON) : msg_get(MSG_OFF));
1255 return 1;
1256}
1257
1258/* Allocation concurrency is protected by the console semaphore */
1259void speakup_allocate(struct vc_data *vc)
1260{
1261 int vc_num;
1262
1263 vc_num = vc->vc_num;
1264 if (speakup_console[vc_num] == NULL) {
1265 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1266 GFP_ATOMIC);
1267 if (speakup_console[vc_num] == NULL)
1268 return;
1269 speakup_date(vc);
1270 } else if (!spk_parked)
1271 speakup_date(vc);
1272}
1273
1274void speakup_deallocate(struct vc_data *vc)
1275{
1276 int vc_num;
1277
1278 vc_num = vc->vc_num;
1279 if (speakup_console[vc_num] != NULL) {
1280 kfree(speakup_console[vc_num]);
1281 speakup_console[vc_num] = NULL;
1282 }
1283}
1284
1285static u_char is_cursor;
1286static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1287static int cursor_con;
1288
1289static void reset_highlight_buffers(struct vc_data *);
1290
1291static int read_all_key;
1292
1293void reset_index_count(int);
1294void get_index_count(int *, int *);
1295/*int synth_supports_indexing(void); */
1296static void start_read_all_timer(struct vc_data *vc, int command);
1297
1298enum {
1299 RA_NOTHING,
1300 RA_NEXT_SENT,
1301 RA_PREV_LINE,
1302 RA_NEXT_LINE,
1303 RA_PREV_SENT,
1304 RA_DOWN_ARROW,
1305 RA_TIMER,
1306 RA_FIND_NEXT_SENT,
1307 RA_FIND_PREV_SENT,
1308};
1309
1310static void
1311kbd_fakekey2(struct vc_data *vc, int command)
1312{
1313 del_timer(&cursor_timer);
1314 speakup_fake_down_arrow();
1315 start_read_all_timer(vc, command);
1316}
1317
1318static void
1319read_all_doc(struct vc_data *vc)
1320{
1321 if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1322 return;
1323 if (!synth_supports_indexing())
1324 return;
1325 if (cursor_track != read_all_mode)
1326 prev_cursor_track = cursor_track;
1327 cursor_track = read_all_mode;
1328 reset_index_count(0);
1329 if (get_sentence_buf(vc, 0) == -1)
1330 kbd_fakekey2(vc, RA_DOWN_ARROW);
1331 else {
1332 say_sentence_num(0, 0);
1333 synth_insert_next_index(0);
1334 start_read_all_timer(vc, RA_TIMER);
1335 }
1336}
1337
1338static void
1339stop_read_all(struct vc_data *vc)
1340{
1341 del_timer(&cursor_timer);
1342 cursor_track = prev_cursor_track;
1343 spk_shut_up &= 0xfe;
1344 do_flush();
1345}
1346
1347static void
1348start_read_all_timer(struct vc_data *vc, int command)
1349{
1350 struct var_t *cursor_timeout;
1351
1352 cursor_con = vc->vc_num;
1353 read_all_key = command;
1354 cursor_timeout = get_var(CURSOR_TIME);
1355 mod_timer(&cursor_timer, jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1356}
1357
1358static void
1359handle_cursor_read_all(struct vc_data *vc, int command)
1360{
1361 int indcount, sentcount, rv, sn;
1362
1363 switch (command) {
1364 case RA_NEXT_SENT:
1365 /* Get Current Sentence */
1366 get_index_count(&indcount, &sentcount);
1367 /*printk("%d %d ", indcount, sentcount); */
1368 reset_index_count(sentcount+1);
1369 if (indcount == 1) {
1370 if (!say_sentence_num(sentcount+1, 0)) {
1371 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1372 return;
1373 }
1374 synth_insert_next_index(0);
1375 } else {
1376 sn = 0;
1377 if (!say_sentence_num(sentcount+1, 1)) {
1378 sn = 1;
1379 reset_index_count(sn);
1380 } else
1381 synth_insert_next_index(0);
1382 if (!say_sentence_num(sn, 0)) {
1383 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1384 return;
1385 }
1386 synth_insert_next_index(0);
1387 }
1388 start_read_all_timer(vc, RA_TIMER);
1389 break;
1390 case RA_PREV_SENT:
1391 break;
1392 case RA_NEXT_LINE:
1393 read_all_doc(vc);
1394 break;
1395 case RA_PREV_LINE:
1396 break;
1397 case RA_DOWN_ARROW:
1398 if (get_sentence_buf(vc, 0) == -1) {
1399 kbd_fakekey2(vc, RA_DOWN_ARROW);
1400 } else {
1401 say_sentence_num(0, 0);
1402 synth_insert_next_index(0);
1403 start_read_all_timer(vc, RA_TIMER);
1404 }
1405 break;
1406 case RA_FIND_NEXT_SENT:
1407 rv = get_sentence_buf(vc, 0);
1408 if (rv == -1)
1409 read_all_doc(vc);
1410 if (rv == 0)
1411 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1412 else {
1413 say_sentence_num(1, 0);
1414 synth_insert_next_index(0);
1415 start_read_all_timer(vc, RA_TIMER);
1416 }
1417 break;
1418 case RA_FIND_PREV_SENT:
1419 break;
1420 case RA_TIMER:
1421 get_index_count(&indcount, &sentcount);
1422 if (indcount < 2)
1423 kbd_fakekey2(vc, RA_DOWN_ARROW);
1424 else
1425 start_read_all_timer(vc, RA_TIMER);
1426 break;
1427 }
1428}
1429
1430static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1431{
1432 unsigned long flags;
1433 spk_lock(flags);
1434 if (cursor_track == read_all_mode) {
1435 spk_parked &= 0xfe;
1436 if (synth == NULL || up_flag || spk_shut_up) {
1437 spk_unlock(flags);
1438 return NOTIFY_STOP;
1439 }
1440 del_timer(&cursor_timer);
1441 spk_shut_up &= 0xfe;
1442 do_flush();
1443 start_read_all_timer(vc, value+1);
1444 spk_unlock(flags);
1445 return NOTIFY_STOP;
1446 }
1447 spk_unlock(flags);
1448 return NOTIFY_OK;
1449}
1450
1451static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1452{
1453 unsigned long flags;
1454 struct var_t *cursor_timeout;
1455
1456 spk_lock(flags);
1457 spk_parked &= 0xfe;
1458 if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1459 spk_unlock(flags);
1460 return;
1461 }
1462 spk_shut_up &= 0xfe;
1463 if (no_intr)
1464 do_flush();
1465/* the key press flushes if !no_inter but we want to flush on cursor
1466 * moves regardless of no_inter state */
1467 is_cursor = value + 1;
1468 old_cursor_pos = vc->vc_pos;
1469 old_cursor_x = vc->vc_x;
1470 old_cursor_y = vc->vc_y;
1471 speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1472 cursor_con = vc->vc_num;
1473 if (cursor_track == CT_Highlight)
1474 reset_highlight_buffers(vc);
1475 cursor_timeout = get_var(CURSOR_TIME);
1476 mod_timer(&cursor_timer, jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1477 spk_unlock(flags);
1478}
1479
1480static void
1481update_color_buffer(struct vc_data *vc , const char *ic , int len)
1482{
1483 int i, bi, hi;
1484 int vc_num = vc->vc_num;
1485
1486 bi = ((vc->vc_attr & 0x70) >> 4) ;
1487 hi = speakup_console[vc_num]->ht.highsize[bi];
1488
1489 i = 0;
1490 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1491 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1492 speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1493 speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1494 }
1495 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1496 if ((ic[i] > 32) && (ic[i] < 127)) {
1497 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1498 hi++;
1499 } else if ((ic[i] == 32) && (hi != 0)) {
1500 if (speakup_console[vc_num]->ht.highbuf[bi][hi-1] !=
1501 32) {
1502 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1503 ic[i];
1504 hi++;
1505 }
1506 }
1507 i++;
1508 }
1509 speakup_console[vc_num]->ht.highsize[bi] = hi;
1510}
1511
1512static void
1513reset_highlight_buffers(struct vc_data *vc)
1514{
1515 int i;
1516 int vc_num = vc->vc_num;
1517 for (i = 0 ; i < 8 ; i++)
1518 speakup_console[vc_num]->ht.highsize[i] = 0;
1519}
1520
1521static int
1522count_highlight_color(struct vc_data *vc)
1523{
1524 int i, bg;
1525 int cc;
1526 int vc_num = vc->vc_num;
1527 u16 ch;
1528 u16 *start = (u16 *) vc->vc_origin;
1529
1530 for (i = 0; i < 8; i++)
1531 speakup_console[vc_num]->ht.bgcount[i] = 0;
1532
1533 for (i = 0; i < vc->vc_rows; i++) {
1534 u16 *end = start + vc->vc_cols*2;
1535 u16 *ptr;
1536 for (ptr = start; ptr < end; ptr++) {
1537 ch = get_attributes(ptr);
1538 bg = (ch & 0x70) >> 4;
1539 speakup_console[vc_num]->ht.bgcount[bg]++;
1540 }
1541 start += vc->vc_size_row;
1542 }
1543
1544 cc = 0;
1545 for (i = 0; i < 8; i++)
1546 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1547 cc++;
1548 return cc;
1549}
1550
1551static int
1552get_highlight_color(struct vc_data *vc)
1553{
1554 int i, j;
1555 unsigned int cptr[8], tmp;
1556 int vc_num = vc->vc_num;
1557
1558 for (i = 0; i < 8; i++)
1559 cptr[i] = i;
1560
1561 for (i = 0; i < 7; i++)
1562 for (j = i + 1; j < 8; j++)
1563 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1564 speakup_console[vc_num]->ht.bgcount[cptr[j]]) {
1565 tmp = cptr[i];
1566 cptr[i] = cptr[j];
1567 cptr[j] = tmp;
1568 }
1569
1570 for (i = 0; i < 8; i++)
1571 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1572 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1573 return cptr[i];
1574 return -1;
1575}
1576
1577static int
1578speak_highlight(struct vc_data *vc)
1579{
1580 int hc, d;
1581 int vc_num = vc->vc_num;
1582 if (count_highlight_color(vc) == 1)
1583 return 0;
1584 hc = get_highlight_color(vc);
1585 if (hc != -1) {
1586 d = vc->vc_y-speakup_console[vc_num]->ht.cy;
1587 if ((d == 1) || (d == -1))
1588 if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1589 return 0;
1590 spk_parked |= 0x01;
1591 do_flush();
1592 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1593 speakup_console[vc_num]->ht.highsize[hc]);
1594 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1595 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1596 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1597 return 1;
1598 }
1599 return 0;
1600}
1601
1602static void
1603cursor_done(u_long data)
1604{
1605 struct vc_data *vc = vc_cons[cursor_con].d;
1606 unsigned long flags;
1607 del_timer(&cursor_timer);
1608 spk_lock(flags);
1609 if (cursor_con != fg_console) {
1610 is_cursor = 0;
1611 goto out;
1612 }
1613 speakup_date(vc);
1614 if (win_enabled) {
1615 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1616 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1617 spk_keydown = is_cursor = 0;
1618 goto out;
1619 }
1620 }
1621 if (cursor_track == read_all_mode) {
1622 handle_cursor_read_all(vc, read_all_key);
1623 goto out;
1624 }
1625 if (cursor_track == CT_Highlight) {
1626 if (speak_highlight(vc)) {
1627 spk_keydown = is_cursor = 0;
1628 goto out;
1629 }
1630 }
1631 if (cursor_track == CT_Window)
1632 speakup_win_say(vc);
1633 else if (is_cursor == 1 || is_cursor == 4)
1634 say_line_from_to(vc, 0, vc->vc_cols, 0);
1635 else
1636 say_char(vc);
1637 spk_keydown = is_cursor = 0;
1638out:
1639 spk_unlock(flags);
1640}
1641
1642/* called by: vt_notifier_call() */
1643static void speakup_bs(struct vc_data *vc)
1644{
1645 unsigned long flags;
1646 if (!speakup_console[vc->vc_num])
1647 return;
1648 if (!spk_trylock(flags))
1649 /* Speakup output, discard */
1650 return;
1651 if (!spk_parked)
1652 speakup_date(vc);
1653 if (spk_shut_up || synth == NULL) {
1654 spk_unlock(flags);
1655 return;
1656 }
1657 if (vc->vc_num == fg_console && spk_keydown) {
1658 spk_keydown = 0;
1659 if (!is_cursor)
1660 say_char(vc);
1661 }
1662 spk_unlock(flags);
1663}
1664
1665/* called by: vt_notifier_call() */
1666static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1667{
1668 unsigned long flags;
1669 if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1670 return;
1671 if (!spk_trylock(flags))
1672 /* Speakup output, discard */
1673 return;
1674 if (bell_pos && spk_keydown && (vc->vc_x == bell_pos - 1))
1675 bleep(3);
1676 if ((is_cursor) || (cursor_track == read_all_mode)) {
1677 if (cursor_track == CT_Highlight)
1678 update_color_buffer(vc, str, len);
1679 spk_unlock(flags);
1680 return;
1681 }
1682 if (win_enabled) {
1683 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1684 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1685 spk_unlock(flags);
1686 return;
1687 }
1688 }
1689
1690 spkup_write(str, len);
1691 spk_unlock(flags);
1692}
1693
1694void
1695speakup_con_update(struct vc_data *vc)
1696{
1697 unsigned long flags;
1698 if (speakup_console[vc->vc_num] == NULL || spk_parked)
1699 return;
1700 if (!spk_trylock(flags))
1701 /* Speakup output, discard */
1702 return;
1703 speakup_date(vc);
1704 spk_unlock(flags);
1705}
1706
1707static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1708{
1709 unsigned long flags;
1710 int on_off = 2;
1711 char *label;
1712 if (synth == NULL || up_flag || spk_killed)
1713 return;
1714 spk_lock(flags);
1715 spk_shut_up &= 0xfe;
1716 if (no_intr)
1717 do_flush();
1718 switch (value) {
1719 case KVAL(K_CAPS):
1720 label = msg_get(MSG_KEYNAME_CAPSLOCK);
1721 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK));
1722 break;
1723 case KVAL(K_NUM):
1724 label = msg_get(MSG_KEYNAME_NUMLOCK);
1725 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK));
1726 break;
1727 case KVAL(K_HOLD):
1728 label = msg_get(MSG_KEYNAME_SCROLLLOCK);
1729 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_SCROLLOCK));
1730 if (speakup_console[vc->vc_num])
1731 speakup_console[vc->vc_num]->tty_stopped = on_off;
1732 break;
1733 default:
1734 spk_parked &= 0xfe;
1735 spk_unlock(flags);
1736 return;
1737 }
1738 if (on_off < 2)
1739 synth_printf("%s %s\n",
1740 label, msg_get(MSG_STATUS_START + on_off));
1741 spk_unlock(flags);
1742}
1743
1744static int
1745inc_dec_var(u_char value)
1746{
1747 struct st_var_header *p_header;
1748 struct var_t *var_data;
1749 char num_buf[32];
1750 char *cp = num_buf;
1751 char *pn;
1752 int var_id = (int)value - VAR_START;
1753 int how = (var_id&1) ? E_INC : E_DEC;
1754 var_id = var_id/2+FIRST_SET_VAR;
1755 p_header = get_var_header(var_id);
1756 if (p_header == NULL)
1757 return -1;
1758 if (p_header->var_type != VAR_NUM)
1759 return -1;
1760 var_data = p_header->data;
1761 if (set_num_var(1, p_header, how) != 0)
1762 return -1;
1763 if (!spk_close_press) {
1764 for (pn = p_header->name; *pn; pn++) {
1765 if (*pn == '_')
1766 *cp = SPACE;
1767 else
1768 *cp++ = *pn;
1769 }
1770 }
1771 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1772 var_data->u.n.value);
1773 synth_printf("%s", num_buf);
1774 return 0;
1775}
1776
1777static void
1778speakup_win_set(struct vc_data *vc)
1779{
1780 char info[40];
1781 if (win_start > 1) {
1782 synth_printf("%s\n", msg_get(MSG_WINDOW_ALREADY_SET));
1783 return;
1784 }
1785 if (spk_x < win_left || spk_y < win_top) {
1786 synth_printf("%s\n", msg_get(MSG_END_BEFORE_START));
1787 return;
1788 }
1789 if (win_start && spk_x == win_left && spk_y == win_top) {
1790 win_left = 0;
1791 win_right = vc->vc_cols-1;
1792 win_bottom = spk_y;
1793 snprintf(info, sizeof(info), msg_get(MSG_WINDOW_LINE),
1794 (int)win_top+1);
1795 } else {
1796 if (!win_start) {
1797 win_top = spk_y;
1798 win_left = spk_x;
1799 } else {
1800 win_bottom = spk_y;
1801 win_right = spk_x;
1802 }
1803 snprintf(info, sizeof(info), msg_get(MSG_WINDOW_BOUNDARY),
1804 (win_start) ? msg_get(MSG_END) : msg_get(MSG_START),
1805 (int)spk_y+1, (int)spk_x+1);
1806 }
1807 synth_printf("%s\n", info);
1808 win_start++;
1809}
1810
1811static void
1812speakup_win_clear(struct vc_data *vc)
1813{
1814 win_top = win_bottom = 0;
1815 win_left = win_right = 0;
1816 win_start = 0;
1817 synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED));
1818}
1819
1820static void
1821speakup_win_enable(struct vc_data *vc)
1822{
1823 if (win_start < 2) {
1824 synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
1825 return;
1826 }
1827 win_enabled ^= 1;
1828 if (win_enabled)
1829 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED));
1830 else
1831 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED));
1832}
1833
1834static void
1835speakup_bits(struct vc_data *vc)
1836{
1837 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1838 if (special_handler != NULL || val < 1 || val > 6) {
1839 synth_printf("%s\n", msg_get(MSG_ERROR));
1840 return;
1841 }
1842 pb_edit = &punc_info[val];
1843 synth_printf(msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1844 special_handler = edit_bits;
1845}
1846
1847static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1848{
1849 static u_char *goto_buf = "\0\0\0\0\0\0";
1850 static int num = 0;
1851 int maxlen, go_pos;
1852 char *cp;
1853 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1854 goto do_goto;
1855 if (type == KT_LATIN && ch == '\n')
1856 goto do_goto;
1857 if (type != 0)
1858 goto oops;
1859 if (ch == 8) {
1860 if (num == 0)
1861 return -1;
1862 ch = goto_buf[--num];
1863 goto_buf[num] = '\0';
1864 spkup_write(&ch, 1);
1865 return 1;
1866 }
1867 if (ch < '+' || ch > 'y')
1868 goto oops;
1869 goto_buf[num++] = ch;
1870 goto_buf[num] = '\0';
1871 spkup_write(&ch, 1);
1872 maxlen = (*goto_buf >= '0') ? 3 : 4;
1873 if ((ch == '+' || ch == '-') && num == 1)
1874 return 1;
1875 if (ch >= '0' && ch <= '9' && num < maxlen)
1876 return 1;
1877 if (num < maxlen-1 || num > maxlen)
1878 goto oops;
1879 if (ch < 'x' || ch > 'y') {
1880oops:
1881 if (!spk_killed)
1882 synth_printf(" %s\n", msg_get(MSG_GOTO_CANCELED));
1883 goto_buf[num = 0] = '\0';
1884 special_handler = NULL;
1885 return 1;
1886 }
1887 cp = speakup_s2i(goto_buf, &go_pos);
1888 goto_pos = (u_long)go_pos;
1889 if (*cp == 'x') {
1890 if (*goto_buf < '0')
1891 goto_pos += spk_x;
1892 else
1893 goto_pos--;
1894 if (goto_pos < 0)
1895 goto_pos = 0;
1896 if (goto_pos >= vc->vc_cols)
1897 goto_pos = vc->vc_cols-1;
1898 goto_x = 1;
1899 } else {
1900 if (*goto_buf < '0')
1901 goto_pos += spk_y;
1902 else
1903 goto_pos--;
1904 if (goto_pos < 0)
1905 goto_pos = 0;
1906 if (goto_pos >= vc->vc_rows)
1907 goto_pos = vc->vc_rows-1;
1908 goto_x = 0;
1909 }
1910 goto_buf[num = 0] = '\0';
1911do_goto:
1912 special_handler = NULL;
1913 spk_parked |= 0x01;
1914 if (goto_x) {
1915 spk_pos -= spk_x * 2;
1916 spk_x = goto_pos;
1917 spk_pos += goto_pos * 2;
1918 say_word(vc);
1919 } else {
1920 spk_y = goto_pos;
1921 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1922 say_line(vc);
1923 }
1924 return 1;
1925}
1926
1927static void
1928speakup_goto(struct vc_data *vc)
1929{
1930 if (special_handler != NULL) {
1931 synth_printf("%s\n", msg_get(MSG_ERROR));
1932 return;
1933 }
1934 synth_printf("%s\n", msg_get(MSG_GOTO));
1935 special_handler = handle_goto;
1936 return;
1937}
1938
1939static void speakup_help(struct vc_data *vc)
1940{
1941 handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1942}
1943
1944static void
1945do_nothing(struct vc_data *vc)
1946{
1947 return; /* flush done in do_spkup */
1948}
1949static u_char key_speakup, spk_key_locked;
1950
1951static void
1952speakup_lock(struct vc_data *vc)
1953{
1954 if (!spk_key_locked)
1955 spk_key_locked = key_speakup = 16;
1956 else
1957 spk_key_locked = key_speakup = 0;
1958}
1959
1960typedef void(*spkup_hand)(struct vc_data *);
1961spkup_hand spkup_handler[] = {
1962 /* must be ordered same as defines in speakup.h */
1963 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
1964 speakup_cut, speakup_paste, say_first_char, say_last_char,
1965 say_char, say_prev_char, say_next_char,
1966 say_word, say_prev_word, say_next_word,
1967 say_line, say_prev_line, say_next_line,
1968 top_edge, bottom_edge, left_edge, right_edge,
1969 spell_word, spell_word, say_screen,
1970 say_position, say_attributes,
1971 speakup_off, speakup_parked, say_line, /* this is for indent */
1972 say_from_top, say_to_bottom,
1973 say_from_left, say_to_right,
1974 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
1975 speakup_bits, speakup_bits, speakup_bits,
1976 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
1977 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
1978};
1979
1980static void do_spkup(struct vc_data *vc, u_char value)
1981{
1982 if (spk_killed && value != SPEECH_KILL)
1983 return;
1984 spk_keydown = 0;
1985 spk_lastkey = 0;
1986 spk_shut_up &= 0xfe;
1987 this_speakup_key = value;
1988 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
1989 do_flush();
1990 (*spkup_handler[value])(vc);
1991 } else {
1992 if (inc_dec_var(value) < 0)
1993 bleep(9);
1994 }
1995}
1996
1997static const char *pad_chars = "0123456789+-*/\015,.?()";
1998
1999int
2000speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2001 int up_flag)
2002{
2003 unsigned long flags;
2004 int kh;
2005 u_char *key_info;
2006 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2007 u_char shift_info, offset;
2008 int ret = 0;
2009 if (synth == NULL)
2010 return 0;
2011
2012 spk_lock(flags);
2013 tty = vc->vc_tty;
2014 if (type >= 0xf0)
2015 type -= 0xf0;
2016 if (type == KT_PAD &&
2017 (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) {
2018 if (up_flag) {
2019 spk_keydown = 0;
2020 goto out;
2021 }
2022 value = spk_lastkey = pad_chars[value];
2023 spk_keydown++;
2024 spk_parked &= 0xfe;
2025 goto no_map;
2026 }
2027 if (keycode >= MAX_KEY)
2028 goto no_map;
2029 key_info = our_keys[keycode];
2030 if (key_info == 0)
2031 goto no_map;
2032 /* Check valid read all mode keys */
2033 if ((cursor_track == read_all_mode) && (!up_flag)) {
2034 switch (value) {
2035 case KVAL(K_DOWN):
2036 case KVAL(K_UP):
2037 case KVAL(K_LEFT):
2038 case KVAL(K_RIGHT):
2039 case KVAL(K_PGUP):
2040 case KVAL(K_PGDN):
2041 break;
2042 default:
2043 stop_read_all(vc);
2044 break;
2045 }
2046 }
2047 shift_info = (shift_state&0x0f) + key_speakup;
2048 offset = shift_table[shift_info];
2049 if (offset) {
2050 new_key = key_info[offset];
2051 if (new_key) {
2052 ret = 1;
2053 if (new_key == SPK_KEY) {
2054 if (!spk_key_locked)
2055 key_speakup = (up_flag) ? 0 : 16;
2056 if (up_flag || spk_killed)
2057 goto out;
2058 spk_shut_up &= 0xfe;
2059 do_flush();
2060 goto out;
2061 }
2062 if (up_flag)
2063 goto out;
2064 if (last_keycode == keycode &&
2065 last_spk_jiffy+MAX_DELAY > jiffies) {
2066 spk_close_press = 1;
2067 offset = shift_table[shift_info+32];
2068 /* double press? */
2069 if (offset && key_info[offset])
2070 new_key = key_info[offset];
2071 }
2072 last_keycode = keycode;
2073 last_spk_jiffy = jiffies;
2074 type = KT_SPKUP;
2075 value = new_key;
2076 }
2077 }
2078no_map:
2079 if (type == KT_SPKUP && special_handler == NULL) {
2080 do_spkup(vc, new_key);
2081 spk_close_press = 0;
2082 ret = 1;
2083 goto out;
2084 }
2085 if (up_flag || spk_killed || type == KT_SHIFT)
2086 goto out;
2087 spk_shut_up &= 0xfe;
2088 kh = (value == KVAL(K_DOWN))
2089 || (value == KVAL(K_UP))
2090 || (value == KVAL(K_LEFT))
2091 || (value == KVAL(K_RIGHT));
2092 if ((cursor_track != read_all_mode) || !kh)
2093 if (!no_intr)
2094 do_flush();
2095 if (special_handler) {
2096 if (type == KT_SPEC && value == 1) {
2097 value = '\n';
2098 type = KT_LATIN;
2099 } else if (type == KT_LETTER)
2100 type = KT_LATIN;
2101 else if (value == 0x7f)
2102 value = 8; /* make del = backspace */
2103 ret = (*special_handler)(vc, type, value, keycode);
2104 spk_close_press = 0;
2105 if (ret < 0)
2106 bleep(9);
2107 goto out;
2108 }
2109 last_keycode = 0;
2110out:
2111 spk_unlock(flags);
2112 return ret;
2113}
2114
2115static int keyboard_notifier_call(struct notifier_block *nb,
2116 unsigned long code, void *_param)
2117{
2118 struct keyboard_notifier_param *param = _param;
2119 struct vc_data *vc = param->vc;
2120 int up = !param->down;
2121 int ret = NOTIFY_OK;
2122 static int keycode; /* to hold the current keycode */
2123
2124 if (vc->vc_mode == KD_GRAPHICS)
2125 return ret;
2126
2127 /*
2128 * First, determine whether we are handling a fake keypress on
2129 * the current processor. If we are, then return NOTIFY_OK,
2130 * to pass the keystroke up the chain. This prevents us from
2131 * trying to take the Speakup lock while it is held by the
2132 * processor on which the simulated keystroke was generated.
2133 * Also, the simulated keystrokes should be ignored by Speakup.
2134 */
2135
2136 if (speakup_fake_key_pressed())
2137 return ret;
2138
2139 switch (code) {
2140 case KBD_KEYCODE:
2141 /* speakup requires keycode and keysym currently */
2142 keycode = param->value;
2143 break;
2144 case KBD_UNBOUND_KEYCODE:
2145 /* not used yet */
2146 break;
2147 case KBD_UNICODE:
2148 /* not used yet */
2149 break;
2150 case KBD_KEYSYM:
2151 if (speakup_key(vc, param->shift, keycode, param->value, up))
2152 ret = NOTIFY_STOP;
2153 else
2154 if (KTYP(param->value) == KT_CUR)
2155 ret = pre_handle_cursor(vc,
2156 KVAL(param->value), up);
2157 break;
2158 case KBD_POST_KEYSYM: {
2159 unsigned char type = KTYP(param->value) - 0xf0;
2160 unsigned char val = KVAL(param->value);
2161 switch (type) {
2162 case KT_SHIFT:
2163 do_handle_shift(vc, val, up);
2164 break;
2165 case KT_LATIN:
2166 case KT_LETTER:
2167 do_handle_latin(vc, val, up);
2168 break;
2169 case KT_CUR:
2170 do_handle_cursor(vc, val, up);
2171 break;
2172 case KT_SPEC:
2173 do_handle_spec(vc, val, up);
2174 break;
2175 }
2176 break;
2177 }
2178 }
2179 return ret;
2180}
2181
2182static int vt_notifier_call(struct notifier_block *nb,
2183 unsigned long code, void *_param)
2184{
2185 struct vt_notifier_param *param = _param;
2186 struct vc_data *vc = param->vc;
2187 switch (code) {
2188 case VT_ALLOCATE:
2189 if (vc->vc_mode == KD_TEXT)
2190 speakup_allocate(vc);
2191 break;
2192 case VT_DEALLOCATE:
2193 speakup_deallocate(vc);
2194 break;
2195 case VT_WRITE:
2196 if (param->c == '\b')
2197 speakup_bs(vc);
2198 else
2199 if (param->c < 0x100) {
2200 char d = param->c;
2201 speakup_con_write(vc, &d, 1);
2202 }
2203 break;
2204 case VT_UPDATE:
2205 speakup_con_update(vc);
2206 break;
2207 }
2208 return NOTIFY_OK;
2209}
2210
2211/* called by: module_exit() */
2212static void __exit speakup_exit(void)
2213{
2214 int i;
2215
2216 free_user_msgs();
2217 unregister_keyboard_notifier(&keyboard_notifier_block);
2218 unregister_vt_notifier(&vt_notifier_block);
2219 speakup_unregister_devsynth();
2220 del_timer(&cursor_timer);
2221
2222 kthread_stop(speakup_task);
2223 speakup_task = NULL;
2224 mutex_lock(&spk_mutex);
2225 synth_release();
2226 mutex_unlock(&spk_mutex);
2227
2228 for (i = 0; i < MAXVARS; i++)
2229 speakup_unregister_var(i);
2230
2231 for (i = 0; i < 256; i++) {
2232 if (characters[i] != default_chars[i])
2233 kfree(characters[i]);
2234 }
2235 for (i = 0; speakup_console[i]; i++)
2236 kfree(speakup_console[i]);
2237 speakup_kobj_exit();
2238 speakup_remove_virtual_keyboard();
2239}
2240
2241/* call by: module_init() */
2242static int __init speakup_init(void)
2243{
2244 int i;
2245 int err;
2246 struct st_spk_t *first_console;
2247 struct vc_data *vc = vc_cons[fg_console].d;
2248 struct var_t *var;
2249
2250 err = speakup_add_virtual_keyboard();
2251 if (err)
2252 return err;
2253
2254 initialize_msgs(); /* Initialize arrays for i18n. */
2255 first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2256 if (!first_console)
2257 return -ENOMEM;
2258 if (speakup_kobj_init() < 0)
2259 return -ENOMEM;
2260
2261 reset_default_chars();
2262 reset_default_chartab();
2263
2264 speakup_console[vc->vc_num] = first_console;
2265 speakup_date(vc);
2266 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2267
2268 strlwr(synth_name);
2269 spk_vars[0].u.n.high = vc->vc_cols;
2270 for (var = spk_vars; var->var_id !=MAXVARS; var++)
2271 speakup_register_var(var);
2272 for (var = synth_time_vars; (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2273 speakup_register_var(var);
2274 for (i = 1; punc_info[i].mask != 0; i++)
2275 set_mask_bits(0, i, 2);
2276
2277 set_key_info(key_defaults, key_buf);
2278 if (quiet_boot)
2279 spk_shut_up |= 0x01;
2280
2281 for (i = 0; i < MAX_NR_CONSOLES; i++)
2282 if (vc_cons[i].d)
2283 speakup_allocate(vc_cons[i].d);
2284
2285 pr_warn("synth name on entry is: %s\n", synth_name);
2286 synth_init(synth_name);
2287 speakup_register_devsynth();
2288
2289 register_keyboard_notifier(&keyboard_notifier_block);
2290 register_vt_notifier(&vt_notifier_block);
2291
2292 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2293 set_user_nice(speakup_task, 10);
2294 if ( ! IS_ERR(speakup_task))
2295 wake_up_process(speakup_task);
2296 else
2297 return -ENOMEM;
2298 return 0;
2299}
2300
2301
2302module_init(speakup_init);
2303module_exit(speakup_exit);
2304
diff --git a/drivers/staging/speakup/selection.c b/drivers/staging/speakup/selection.c
new file mode 100644
index 00000000000..1b865ff00bc
--- /dev/null
+++ b/drivers/staging/speakup/selection.c
@@ -0,0 +1,155 @@
1#include <linux/slab.h> /* for kmalloc */
2#include <linux/consolemap.h>
3#include <linux/interrupt.h>
4#include <linux/sched.h>
5#include <linux/selection.h>
6
7#include "speakup.h"
8
9/* ------ cut and paste ----- */
10/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
11#define ishardspace(c) ((c) == ' ')
12
13unsigned short xs, ys, xe, ye; /* our region points */
14
15/* Variables for selection control. */
16/* must not be disallocated */
17struct vc_data *spk_sel_cons;
18/* cleared by clear_selection */
19static int sel_start = -1;
20static int sel_end;
21static int sel_buffer_lth;
22static char *sel_buffer;
23
24static unsigned char sel_pos(int n)
25{
26 return inverse_translate(spk_sel_cons, screen_glyph(spk_sel_cons, n), 0);
27}
28
29void speakup_clear_selection(void)
30{
31 sel_start = -1;
32}
33
34/* does screen address p correspond to character at LH/RH edge of screen? */
35static int atedge(const int p, int size_row)
36{
37 return (!(p % size_row) || !((p + 2) % size_row));
38}
39
40/* constrain v such that v <= u */
41static unsigned short limit(const unsigned short v, const unsigned short u)
42{
43 return (v > u) ? u : v;
44}
45
46int speakup_set_selection(struct tty_struct *tty)
47{
48 int new_sel_start, new_sel_end;
49 char *bp, *obp;
50 int i, ps, pe;
51 struct vc_data *vc = vc_cons[fg_console].d;
52
53 xs = limit(xs, vc->vc_cols - 1);
54 ys = limit(ys, vc->vc_rows - 1);
55 xe = limit(xe, vc->vc_cols - 1);
56 ye = limit(ye, vc->vc_rows - 1);
57 ps = ys * vc->vc_size_row + (xs << 1);
58 pe = ye * vc->vc_size_row + (xe << 1);
59
60 if (ps > pe) {
61 /* make sel_start <= sel_end */
62 int tmp = ps;
63 ps = pe;
64 pe = tmp;
65 }
66
67 if (spk_sel_cons != vc_cons[fg_console].d) {
68 speakup_clear_selection();
69 spk_sel_cons = vc_cons[fg_console].d;
70 printk(KERN_WARNING
71 "Selection: mark console not the same as cut\n");
72 return -EINVAL;
73 }
74
75 new_sel_start = ps;
76 new_sel_end = pe;
77
78 /* select to end of line if on trailing space */
79 if (new_sel_end > new_sel_start &&
80 !atedge(new_sel_end, vc->vc_size_row) &&
81 ishardspace(sel_pos(new_sel_end))) {
82 for (pe = new_sel_end + 2; ; pe += 2)
83 if (!ishardspace(sel_pos(pe)) ||
84 atedge(pe, vc->vc_size_row))
85 break;
86 if (ishardspace(sel_pos(pe)))
87 new_sel_end = pe;
88 }
89 if ((new_sel_start == sel_start) && (new_sel_end == sel_end))
90 return 0; /* no action required */
91
92 sel_start = new_sel_start;
93 sel_end = new_sel_end;
94 /* Allocate a new buffer before freeing the old one ... */
95 bp = kmalloc((sel_end-sel_start)/2+1, GFP_ATOMIC);
96 if (!bp) {
97 printk(KERN_WARNING "selection: kmalloc() failed\n");
98 speakup_clear_selection();
99 return -ENOMEM;
100 }
101 kfree(sel_buffer);
102 sel_buffer = bp;
103
104 obp = bp;
105 for (i = sel_start; i <= sel_end; i += 2) {
106 *bp = sel_pos(i);
107 if (!ishardspace(*bp++))
108 obp = bp;
109 if (!((i + 2) % vc->vc_size_row)) {
110 /* strip trailing blanks from line and add newline,
111 unless non-space at end of line. */
112 if (obp != bp) {
113 bp = obp;
114 *bp++ = '\r';
115 }
116 obp = bp;
117 }
118 }
119 sel_buffer_lth = bp - sel_buffer;
120 return 0;
121}
122
123/* TODO: move to some helper thread, probably. That'd fix having to check for
124 * in_atomic(). */
125int speakup_paste_selection(struct tty_struct *tty)
126{
127 struct vc_data *vc = (struct vc_data *) tty->driver_data;
128 int pasted = 0, count;
129 DECLARE_WAITQUEUE(wait, current);
130 add_wait_queue(&vc->paste_wait, &wait);
131 while (sel_buffer && sel_buffer_lth > pasted) {
132 set_current_state(TASK_INTERRUPTIBLE);
133 if (test_bit(TTY_THROTTLED, &tty->flags)) {
134 if (in_atomic())
135 /* can't be performed in an interrupt handler, abort */
136 break;
137 schedule();
138 continue;
139 }
140 count = sel_buffer_lth - pasted;
141 count = min_t(int, count, tty->receive_room);
142#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
143 tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, 0, count);
144#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
145 tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted, 0, count);
146#else
147 tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count);
148#endif
149 pasted += count;
150 }
151 remove_wait_queue(&vc->paste_wait, &wait);
152 current->state = TASK_RUNNING;
153 return 0;
154}
155
diff --git a/drivers/staging/speakup/serialio.c b/drivers/staging/speakup/serialio.c
new file mode 100644
index 00000000000..f64eb364533
--- /dev/null
+++ b/drivers/staging/speakup/serialio.c
@@ -0,0 +1,212 @@
1#include <linux/interrupt.h>
2#include <linux/ioport.h>
3
4#include "spk_types.h"
5#include "speakup.h"
6#include "spk_priv.h"
7#include "serialio.h"
8
9static void start_serial_interrupt(int irq);
10
11static struct serial_state rs_table[] = {
12 SERIAL_PORT_DFNS
13};
14static struct serial_state *serstate;
15static int timeouts;
16
17struct serial_state *spk_serial_init(int index)
18{
19 int baud = 9600, quot = 0;
20 unsigned int cval = 0;
21 int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
22 struct serial_state *ser = NULL;
23 int err;
24
25 ser = rs_table + index;
26 /* Divisor, bytesize and parity */
27 quot = ser->baud_base / baud;
28 cval = cflag & (CSIZE | CSTOPB);
29#if defined(__powerpc__) || defined(__alpha__)
30 cval >>= 8;
31#else /* !__powerpc__ && !__alpha__ */
32 cval >>= 4;
33#endif /* !__powerpc__ && !__alpha__ */
34 if (cflag & PARENB)
35 cval |= UART_LCR_PARITY;
36 if (!(cflag & PARODD))
37 cval |= UART_LCR_EPAR;
38 if (synth_request_region(ser->port, 8)) {
39 /* try to take it back. */
40 printk("Ports not available, trying to steal them\n");
41 __release_region(&ioport_resource, ser->port, 8);
42 err = synth_request_region(ser->port, 8);
43 if (err) {
44 pr_warn("Unable to allocate port at %x, errno %i", ser->port, err);
45 return NULL;
46 }
47 }
48
49 /* Disable UART interrupts, set DTR and RTS high
50 * and set speed. */
51 outb(cval | UART_LCR_DLAB, ser->port + UART_LCR); /* set DLAB */
52 outb(quot & 0xff, ser->port + UART_DLL); /* LS of divisor */
53 outb(quot >> 8, ser->port + UART_DLM); /* MS of divisor */
54 outb(cval, ser->port + UART_LCR); /* reset DLAB */
55
56 /* Turn off Interrupts */
57 outb(0, ser->port + UART_IER);
58 outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
59
60 /* If we read 0xff from the LSR, there is no UART here. */
61 if (inb(ser->port + UART_LSR) == 0xff) {
62 synth_release_region(ser->port, 8);
63 serstate = NULL;
64 return NULL;
65 }
66
67 mdelay(1);
68 speakup_info.port_tts = ser->port;
69 serstate = ser;
70
71 start_serial_interrupt(ser->irq);
72
73 return ser;
74}
75
76static irqreturn_t synth_readbuf_handler(int irq, void *dev_id)
77{
78 unsigned long flags;
79/*printk(KERN_ERR "in irq\n"); */
80/*pr_warn("in IRQ\n"); */
81 int c;
82 spk_lock(flags);
83 while (inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR) {
84
85 c = inb_p(speakup_info.port_tts+UART_RX);
86 synth->read_buff_add((u_char) c);
87/*printk(KERN_ERR "c = %d\n", c); */
88/*pr_warn("C = %d\n", c); */
89 }
90 spk_unlock(flags);
91 return IRQ_HANDLED;
92}
93
94static void start_serial_interrupt(int irq)
95{
96 int rv;
97
98 if (synth->read_buff_add == NULL)
99 return;
100
101 rv = request_irq(irq, synth_readbuf_handler, IRQF_SHARED,
102 "serial", (void *) synth_readbuf_handler);
103
104 if (rv)
105 printk(KERN_ERR "Unable to request Speakup serial I R Q\n");
106 /* Set MCR */
107 outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2,
108 speakup_info.port_tts + UART_MCR);
109 /* Turn on Interrupts */
110 outb(UART_IER_MSI|UART_IER_RLSI|UART_IER_RDI,
111 speakup_info.port_tts + UART_IER);
112 inb(speakup_info.port_tts+UART_LSR);
113 inb(speakup_info.port_tts+UART_RX);
114 inb(speakup_info.port_tts+UART_IIR);
115 inb(speakup_info.port_tts+UART_MSR);
116 outb(1, speakup_info.port_tts + UART_FCR); /* Turn FIFO On */
117}
118
119void stop_serial_interrupt(void)
120{
121 if (speakup_info.port_tts == 0)
122 return;
123
124 if (synth->read_buff_add == NULL)
125 return;
126
127 /* Turn off interrupts */
128 outb(0, speakup_info.port_tts+UART_IER);
129 /* Free IRQ */
130 free_irq(serstate->irq, (void *) synth_readbuf_handler);
131}
132
133int wait_for_xmitr(void)
134{
135 int tmout = SPK_XMITR_TIMEOUT;
136 if ((synth->alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) {
137 pr_warn("%s: too many timeouts, deactivating speakup\n", synth->long_name);
138 synth->alive = 0;
139 /* No synth any more, so nobody will restart TTYs, and we thus
140 * need to do it ourselves. Now that there is no synth we can
141 * let application flood anyway */
142 speakup_start_ttys();
143 timeouts = 0;
144 return 0;
145 }
146 while (spk_serial_tx_busy()) {
147 if (--tmout == 0) {
148 pr_warn("%s: timed out (tx busy)\n", synth->long_name);
149 timeouts++;
150 return 0;
151 }
152 udelay(1);
153 }
154 tmout = SPK_CTS_TIMEOUT;
155 while (!((inb_p(speakup_info.port_tts + UART_MSR)) & UART_MSR_CTS)) {
156 /* CTS */
157 if (--tmout == 0) {
158 // pr_warn("%s: timed out (cts)\n", synth->long_name);
159 timeouts++;
160 return 0;
161 }
162 udelay(1);
163 }
164 timeouts = 0;
165 return 1;
166}
167
168unsigned char spk_serial_in(void)
169{
170 int tmout = SPK_SERIAL_TIMEOUT;
171
172 while (!(inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR)) {
173 if (--tmout == 0) {
174 pr_warn("time out while waiting for input.\n");
175 return 0xff;
176 }
177 udelay(1);
178 }
179 return inb_p(speakup_info.port_tts + UART_RX);
180}
181EXPORT_SYMBOL_GPL(spk_serial_in);
182
183unsigned char spk_serial_in_nowait(void)
184{
185 unsigned char lsr;
186
187 lsr = inb_p(speakup_info.port_tts + UART_LSR);
188 if (!(lsr & UART_LSR_DR))
189 return 0;
190 return inb_p(speakup_info.port_tts + UART_RX);
191}
192EXPORT_SYMBOL_GPL(spk_serial_in_nowait);
193
194int spk_serial_out(const char ch)
195{
196 if (synth->alive && wait_for_xmitr()) {
197 outb_p(ch, speakup_info.port_tts);
198 return 1;
199 }
200 return 0;
201}
202EXPORT_SYMBOL_GPL(spk_serial_out);
203
204void spk_serial_release(void)
205{
206 if (speakup_info.port_tts == 0)
207 return;
208 synth_release_region(speakup_info.port_tts, 8);
209 speakup_info.port_tts = 0;
210}
211EXPORT_SYMBOL_GPL(spk_serial_release);
212
diff --git a/drivers/staging/speakup/serialio.h b/drivers/staging/speakup/serialio.h
new file mode 100644
index 00000000000..d785b1f6a3b
--- /dev/null
+++ b/drivers/staging/speakup/serialio.h
@@ -0,0 +1,55 @@
1#ifndef _SPEAKUP_SERIAL_H
2#define _SPEAKUP_SERIAL_H
3
4#include <linux/serial.h> /* for rs_table, serial constants &
5 serial_uart_config */
6#include <linux/serial_reg.h> /* for more serial constants */
7#include <linux/serialP.h> /* for struct serial_state */
8#ifndef __sparc__
9#include <asm/serial.h>
10#endif
11
12/* countdown values for serial timeouts in us */
13#define SPK_SERIAL_TIMEOUT 100000
14/* countdown values transmitter/dsr timeouts in us */
15#define SPK_XMITR_TIMEOUT 100000
16/* countdown values cts timeouts in us */
17#define SPK_CTS_TIMEOUT 100000
18/* check ttyS0 ... ttyS3 */
19#define SPK_LO_TTY 0
20#define SPK_HI_TTY 3
21/* # of timeouts permitted before disable */
22#define NUM_DISABLE_TIMEOUTS 3
23/* buffer timeout in ms */
24#define SPK_TIMEOUT 100
25#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
26
27#define spk_serial_tx_busy() ((inb(speakup_info.port_tts + UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
28
29/* 2.6.22 doesn't have them any more, hardcode it for now (these values should
30 * be fine for 99% cases) */
31#ifndef BASE_BAUD
32#define BASE_BAUD (1843200 / 16)
33#endif
34#ifndef STD_COM_FLAGS
35#ifdef CONFIG_SERIAL_DETECT_IRQ
36#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
37#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
38#else
39#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
40#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
41#endif
42#endif
43#ifndef SERIAL_PORT_DFNS
44#define SERIAL_PORT_DFNS \
45 /* UART CLK PORT IRQ FLAGS */ \
46 { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
47 { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
48 { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
49 { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
50#endif
51#ifndef IRQF_SHARED
52#define IRQF_SHARED SA_SHIRQ
53#endif
54
55#endif
diff --git a/drivers/staging/speakup/speakup.h b/drivers/staging/speakup/speakup.h
new file mode 100644
index 00000000000..e6f3dfe38b9
--- /dev/null
+++ b/drivers/staging/speakup/speakup.h
@@ -0,0 +1,127 @@
1#ifndef _SPEAKUP_H
2#define _SPEAKUP_H
3#include <linux/version.h>
4
5#include "spk_types.h"
6#include "i18n.h"
7
8#define SPEAKUP_VERSION "3.1.6"
9#define KEY_MAP_VER 119
10#define SHIFT_TBL_SIZE 64
11#define MAX_DESC_LEN 72
12
13/* proc permissions */
14#define USER_R (S_IFREG|S_IRUGO)
15#define USER_W (S_IFREG|S_IWUGO)
16#define USER_RW (S_IFREG|S_IRUGO|S_IWUGO)
17#define ROOT_W (S_IFREG|S_IRUGO|S_IWUSR)
18
19#define TOGGLE_0 .u.n = {NULL, 0, 0, 1, 0, 0, NULL }
20#define TOGGLE_1 .u.n = {NULL, 1, 0, 1, 0, 0, NULL }
21#define MAXVARLEN 15
22
23#define SYNTH_OK 0x0001
24#define B_ALPHA 0x0002
25#define ALPHA 0x0003
26#define B_CAP 0x0004
27#define A_CAP 0x0007
28#define B_NUM 0x0008
29#define NUM 0x0009
30#define ALPHANUM (B_ALPHA|B_NUM)
31#define SOME 0x0010
32#define MOST 0x0020
33#define PUNC 0x0040
34#define A_PUNC 0x0041
35#define B_WDLM 0x0080
36#define WDLM 0x0081
37#define B_EXNUM 0x0100
38#define CH_RPT 0x0200
39#define B_CTL 0x0400
40#define A_CTL (B_CTL+SYNTH_OK)
41#define B_SYM 0x0800
42#define B_CAPSYM (B_CAP|B_SYM)
43
44#define IS_WDLM(x) (spk_chartab[((u_char)x)]&B_WDLM)
45#define IS_CHAR(x, type) (spk_chartab[((u_char)x)]&type)
46#define IS_TYPE(x, type) ((spk_chartab[((u_char)x)]&type) == type)
47
48#define SET_DEFAULT -4
49#define E_RANGE -3
50#define E_TOOLONG -2
51#define E_UNDEF -1
52
53extern int speakup_thread(void *data);
54extern void reset_default_chars(void);
55extern void reset_default_chartab(void);
56extern void synth_start(void);
57extern int set_key_info(const u_char *key_info, u_char *k_buffer);
58extern char *strlwr(char *s);
59extern char *speakup_s2i(char *start, int *dest);
60extern char *s2uchar(char *start, char *dest);
61extern char *xlate(char *s);
62extern int speakup_kobj_init(void);
63extern void speakup_kobj_exit(void);
64extern int chartab_get_value(char *keyword);
65extern void speakup_register_var(struct var_t *var);
66extern void speakup_unregister_var(enum var_id_t var_id);
67extern struct st_var_header *get_var_header(enum var_id_t var_id);
68extern struct st_var_header *var_header_by_name(const char *name);
69extern struct punc_var_t *get_punc_var(enum var_id_t var_id);
70extern int set_num_var(int val, struct st_var_header *var, int how);
71extern int set_string_var(const char *page, struct st_var_header *var, int len);
72extern int set_mask_bits(const char *input, const int which, const int how);
73extern special_func special_handler;
74extern int handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key);
75extern int synth_init(char *name);
76extern void synth_release(void);
77
78extern void do_flush(void);
79extern void speakup_start_ttys(void);
80extern void synth_buffer_add(char ch);
81extern void synth_buffer_clear(void);
82extern void speakup_clear_selection(void);
83extern int speakup_set_selection(struct tty_struct *tty);
84extern int speakup_paste_selection(struct tty_struct *tty);
85extern void speakup_register_devsynth(void);
86extern void speakup_unregister_devsynth(void);
87extern void synth_write(const char *buf, size_t count);
88extern int synth_supports_indexing(void);
89
90extern struct vc_data *spk_sel_cons;
91extern unsigned short xs, ys, xe, ye; /* our region points */
92
93extern wait_queue_head_t speakup_event;
94extern struct kobject *speakup_kobj;
95extern struct task_struct *speakup_task;
96extern const u_char key_defaults[];
97
98/* Protect speakup synthesizer list */
99extern struct mutex spk_mutex;
100extern struct st_spk_t *speakup_console[];
101extern struct spk_synth *synth;
102extern char pitch_buff[];
103extern u_char *our_keys[];
104extern short punc_masks[];
105extern char str_caps_start[], str_caps_stop[];
106extern const struct st_bits_data punc_info[];
107extern u_char key_buf[600];
108extern char *characters[];
109extern char *default_chars[];
110extern u_short spk_chartab[];
111extern int no_intr, say_ctrl, say_word_ctl, punc_level;
112extern int reading_punc, attrib_bleep, bleeps;
113extern int bleep_time, bell_pos;
114extern int spell_delay, key_echo;
115extern short punc_mask;
116extern short pitch_shift, synth_flags;
117extern int quiet_boot;
118extern char *synth_name;
119extern struct bleep unprocessed_sound;
120
121/* Prototypes from fakekey.c. */
122int speakup_add_virtual_keyboard(void);
123void speakup_remove_virtual_keyboard(void);
124void speakup_fake_down_arrow(void);
125bool speakup_fake_key_pressed(void);
126
127#endif
diff --git a/drivers/staging/speakup/speakup_acnt.h b/drivers/staging/speakup/speakup_acnt.h
new file mode 100644
index 00000000000..2d883654ffc
--- /dev/null
+++ b/drivers/staging/speakup/speakup_acnt.h
@@ -0,0 +1,16 @@
1/* speakup_acntpc.h - header file for speakups Accent-PC driver. */
2
3#define SYNTH_IO_EXTENT 0x02
4
5#define SYNTH_CLEAR 0x18 /* stops speech */
6
7 /* Port Status Flags */
8#define SYNTH_READABLE 0x01 /* mask for bit which is nonzero if a
9 byte can be read from the data port */
10#define SYNTH_WRITABLE 0x02 /* mask for RDY bit, which when set to
11 1, indicates the data port is ready
12 to accept a byte of data. */
13#define SYNTH_QUIET 'S' /* synth is not speaking */
14#define SYNTH_FULL 'F' /* synth is full. */
15#define SYNTH_ALMOST_EMPTY 'M' /* synth has les than 2 seconds of text left */
16#define SYNTH_SPEAKING 's' /* synth is speaking and has a fare way to go */
diff --git a/drivers/staging/speakup/speakup_acntpc.c b/drivers/staging/speakup/speakup_acntpc.c
new file mode 100644
index 00000000000..d2660e213be
--- /dev/null
+++ b/drivers/staging/speakup/speakup_acntpc.c
@@ -0,0 +1,327 @@
1/*
2 * 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 * this code is specificly written as a driver for the speakup screenreview
23 * package and is not a general device driver.
24 * This driver is for the Aicom Acent PC internal synthesizer.
25 */
26
27#include <linux/jiffies.h>
28#include <linux/sched.h>
29#include <linux/timer.h>
30#include <linux/kthread.h>
31
32#include "spk_priv.h"
33#include "serialio.h"
34#include "speakup.h"
35#include "speakup_acnt.h" /* local header file for Accent values */
36
37#define DRV_VERSION "2.10"
38#define synth_readable() (inb_p(synth_port_control) & SYNTH_READABLE)
39#define synth_writable() (inb_p(synth_port_control) & SYNTH_WRITABLE)
40#define synth_full() (inb_p(speakup_info.port_tts + UART_RX) == 'F')
41#define PROCSPEECH '\r'
42
43static int synth_probe(struct spk_synth *synth);
44static void accent_release(void);
45static const char *synth_immediate(struct spk_synth *synth, const char *buf);
46static void do_catch_up(struct spk_synth *synth);
47static void synth_flush(struct spk_synth *synth);
48
49static int synth_port_control;
50static int port_forced;
51static unsigned int synth_portlist[] = { 0x2a8, 0 };
52
53static struct var_t vars[] = {
54 { CAPS_START, .u.s = {"\033P8" }},
55 { CAPS_STOP, .u.s = {"\033P5" }},
56 { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" }},
57 { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL }},
58 { VOL, .u.n = {"\033A%d", 5, 0, 9, 0, 0, NULL }},
59 { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL }},
60 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
61 V_LAST_VAR
62};
63
64/*
65 * These attributes will appear in /sys/accessibility/speakup/acntpc.
66 */
67static struct kobj_attribute caps_start_attribute =
68 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
69static struct kobj_attribute caps_stop_attribute =
70 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
71static struct kobj_attribute pitch_attribute =
72 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
73static struct kobj_attribute rate_attribute =
74 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
75static struct kobj_attribute tone_attribute =
76 __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
77static struct kobj_attribute vol_attribute =
78 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
79
80static struct kobj_attribute delay_time_attribute =
81 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
82static struct kobj_attribute direct_attribute =
83 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
84static struct kobj_attribute full_time_attribute =
85 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
86static struct kobj_attribute jiffy_delta_attribute =
87 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
88static struct kobj_attribute trigger_time_attribute =
89 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
90
91/*
92 * Create a group of attributes so that we can create and destroy them all
93 * at once.
94 */
95static struct attribute *synth_attrs[] = {
96 &caps_start_attribute.attr,
97 &caps_stop_attribute.attr,
98 &pitch_attribute.attr,
99 &rate_attribute.attr,
100 &tone_attribute.attr,
101 &vol_attribute.attr,
102 &delay_time_attribute.attr,
103 &direct_attribute.attr,
104 &full_time_attribute.attr,
105 &jiffy_delta_attribute.attr,
106 &trigger_time_attribute.attr,
107 NULL, /* need to NULL terminate the list of attributes */
108};
109
110static struct spk_synth synth_acntpc = {
111 .name = "acntpc",
112 .version = DRV_VERSION,
113 .long_name = "Accent PC",
114 .init = "\033=X \033Oi\033T2\033=M\033N1\n",
115 .procspeech = PROCSPEECH,
116 .clear = SYNTH_CLEAR,
117 .delay = 500,
118 .trigger = 50,
119 .jiffies = 50,
120 .full = 1000,
121 .startup = SYNTH_START,
122 .checkval = SYNTH_CHECK,
123 .vars = vars,
124 .probe = synth_probe,
125 .release = accent_release,
126 .synth_immediate = synth_immediate,
127 .catch_up = do_catch_up,
128 .flush = synth_flush,
129 .is_alive = spk_synth_is_alive_nop,
130 .synth_adjust = NULL,
131 .read_buff_add = NULL,
132 .get_index = NULL,
133 .indexing = {
134 .command = NULL,
135 .lowindex = 0,
136 .highindex = 0,
137 .currindex = 0,
138 },
139 .attributes = {
140 .attrs = synth_attrs,
141 .name = "acntpc",
142 },
143};
144
145static const char *synth_immediate(struct spk_synth *synth, const char *buf)
146{
147 u_char ch;
148 while ((ch = *buf)) {
149 int timeout = SPK_XMITR_TIMEOUT;
150 if (ch == '\n')
151 ch = PROCSPEECH;
152 if (synth_full())
153 return buf;
154 while (synth_writable()) {
155 if (!--timeout)
156 return buf;
157 udelay(1);
158 }
159 outb_p(ch, speakup_info.port_tts);
160 buf++;
161 }
162 return 0;
163}
164
165static void do_catch_up(struct spk_synth *synth)
166{
167 u_char ch;
168 unsigned long flags;
169 unsigned long jiff_max;
170 int timeout;
171 int delay_time_val;
172 int jiffy_delta_val;
173 int full_time_val;
174 struct var_t *delay_time;
175 struct var_t *full_time;
176 struct var_t *jiffy_delta;
177
178 jiffy_delta = get_var(JIFFY);
179 delay_time = get_var(DELAY);
180 full_time = get_var(FULL);
181
182 spk_lock(flags);
183 jiffy_delta_val = jiffy_delta->u.n.value;
184 spk_unlock(flags);
185
186 jiff_max = jiffies + jiffy_delta_val;
187 while (!kthread_should_stop()) {
188 spk_lock(flags);
189 if (speakup_info.flushing) {
190 speakup_info.flushing = 0;
191 spk_unlock(flags);
192 synth->flush(synth);
193 continue;
194 }
195 if (synth_buffer_empty()) {
196 spk_unlock(flags);
197 break;
198 }
199 set_current_state(TASK_INTERRUPTIBLE);
200 full_time_val = full_time->u.n.value;
201 spk_unlock(flags);
202 if (synth_full()) {
203 schedule_timeout(msecs_to_jiffies(full_time_val));
204 continue;
205 }
206 set_current_state(TASK_RUNNING);
207 timeout = SPK_XMITR_TIMEOUT;
208 while (synth_writable()) {
209 if (!--timeout)
210 break;
211 udelay(1);
212 }
213 spk_lock(flags);
214 ch = synth_buffer_getc();
215 spk_unlock(flags);
216 if (ch == '\n')
217 ch = PROCSPEECH;
218 outb_p(ch, speakup_info.port_tts);
219 if (jiffies >= jiff_max && ch == SPACE) {
220 timeout = SPK_XMITR_TIMEOUT;
221 while (synth_writable()) {
222 if (!--timeout)
223 break;
224 udelay(1);
225 }
226 outb_p(PROCSPEECH, speakup_info.port_tts);
227 spk_lock(flags);
228 jiffy_delta_val = jiffy_delta->u.n.value;
229 delay_time_val = delay_time->u.n.value;
230 spk_unlock(flags);
231 schedule_timeout(msecs_to_jiffies(delay_time_val));
232 jiff_max = jiffies+jiffy_delta_val;
233 }
234 }
235 timeout = SPK_XMITR_TIMEOUT;
236 while (synth_writable()) {
237 if (!--timeout)
238 break;
239 udelay(1);
240 }
241 outb_p(PROCSPEECH, speakup_info.port_tts);
242}
243
244static void synth_flush(struct spk_synth *synth)
245{
246 outb_p(SYNTH_CLEAR, speakup_info.port_tts);
247}
248
249static int synth_probe(struct spk_synth *synth)
250{
251 unsigned int port_val = 0;
252 int i = 0;
253 pr_info("Probing for %s.\n", synth->long_name);
254 if (port_forced) {
255 speakup_info.port_tts = port_forced;
256 pr_info("probe forced to %x by kernel command line\n",
257 speakup_info.port_tts);
258 if (synth_request_region(speakup_info.port_tts-1,
259 SYNTH_IO_EXTENT)) {
260 pr_warn("sorry, port already reserved\n");
261 return -EBUSY;
262 }
263 port_val = inw(speakup_info.port_tts-1);
264 synth_port_control = speakup_info.port_tts-1;
265 } else {
266 for (i = 0; synth_portlist[i]; i++) {
267 if (synth_request_region(synth_portlist[i],
268 SYNTH_IO_EXTENT)) {
269 pr_warn("request_region: failed with 0x%x, %d\n",
270 synth_portlist[i], SYNTH_IO_EXTENT);
271 continue;
272 }
273 port_val = inw(synth_portlist[i]) & 0xfffc;
274 if (port_val == 0x53fc) {
275 /* 'S' and out&input bits */
276 synth_port_control = synth_portlist[i];
277 speakup_info.port_tts = synth_port_control+1;
278 break;
279 }
280 }
281 }
282 port_val &= 0xfffc;
283 if (port_val != 0x53fc) {
284 /* 'S' and out&input bits */
285 pr_info("%s: not found\n", synth->long_name);
286 synth_release_region(synth_port_control, SYNTH_IO_EXTENT);
287 synth_port_control = 0;
288 return -ENODEV;
289 }
290 pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name,
291 synth_port_control, synth_port_control+SYNTH_IO_EXTENT-1,
292 synth->version);
293 synth->alive = 1;
294 return 0;
295}
296
297static void accent_release(void)
298{
299 if (speakup_info.port_tts)
300 synth_release_region(speakup_info.port_tts-1, SYNTH_IO_EXTENT);
301 speakup_info.port_tts = 0;
302}
303
304module_param_named(port, port_forced, int, S_IRUGO);
305module_param_named(start, synth_acntpc.startup, short, S_IRUGO);
306
307MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
308MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
309
310static int __init acntpc_init(void)
311{
312 return synth_add(&synth_acntpc);
313}
314
315static void __exit acntpc_exit(void)
316{
317 synth_remove(&synth_acntpc);
318}
319
320module_init(acntpc_init);
321module_exit(acntpc_exit);
322MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
323MODULE_AUTHOR("David Borowski");
324MODULE_DESCRIPTION("Speakup support for Accent PC synthesizer");
325MODULE_LICENSE("GPL");
326MODULE_VERSION(DRV_VERSION);
327
diff --git a/drivers/staging/speakup/speakup_acntsa.c b/drivers/staging/speakup/speakup_acntsa.c
new file mode 100644
index 00000000000..0418c9df947
--- /dev/null
+++ b/drivers/staging/speakup/speakup_acntsa.c
@@ -0,0 +1,164 @@
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 * this code is specificly written as a driver for the speakup screenreview
23 * package and is not a general device driver.
24 */
25
26#include "spk_priv.h"
27#include "speakup.h"
28#include "speakup_acnt.h" /* local header file for Accent values */
29
30#define DRV_VERSION "2.11"
31#define synth_full() (inb_p(speakup_info.port_tts + UART_RX) == 'F')
32#define PROCSPEECH '\r'
33
34static int synth_probe(struct spk_synth *synth);
35
36static struct var_t vars[] = {
37 { CAPS_START, .u.s = {"\033P8" }},
38 { CAPS_STOP, .u.s = {"\033P5" }},
39 { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" }},
40 { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL }},
41 { VOL, .u.n = {"\033A%d", 9, 0, 9, 0, 0, NULL }},
42 { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL }},
43 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
44 V_LAST_VAR
45};
46
47/*
48 * These attributes will appear in /sys/accessibility/speakup/acntsa.
49 */
50static struct kobj_attribute caps_start_attribute =
51 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
52static struct kobj_attribute caps_stop_attribute =
53 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
54static struct kobj_attribute pitch_attribute =
55 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
56static struct kobj_attribute rate_attribute =
57 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
58static struct kobj_attribute tone_attribute =
59 __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
60static struct kobj_attribute vol_attribute =
61 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
62
63static struct kobj_attribute delay_time_attribute =
64 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
65static struct kobj_attribute direct_attribute =
66 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
67static struct kobj_attribute full_time_attribute =
68 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
69static struct kobj_attribute jiffy_delta_attribute =
70 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
71static struct kobj_attribute trigger_time_attribute =
72 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
73
74/*
75 * Create a group of attributes so that we can create and destroy them all
76 * at once.
77 */
78static struct attribute *synth_attrs[] = {
79 &caps_start_attribute.attr,
80 &caps_stop_attribute.attr,
81 &pitch_attribute.attr,
82 &rate_attribute.attr,
83 &tone_attribute.attr,
84 &vol_attribute.attr,
85 &delay_time_attribute.attr,
86 &direct_attribute.attr,
87 &full_time_attribute.attr,
88 &jiffy_delta_attribute.attr,
89 &trigger_time_attribute.attr,
90 NULL, /* need to NULL terminate the list of attributes */
91};
92
93static struct spk_synth synth_acntsa = {
94 .name = "acntsa",
95 .version = DRV_VERSION,
96 .long_name = "Accent-SA",
97 .init = "\033T2\033=M\033Oi\033N1\n",
98 .procspeech = PROCSPEECH,
99 .clear = SYNTH_CLEAR,
100 .delay = 400,
101 .trigger = 50,
102 .jiffies = 30,
103 .full = 40000,
104 .startup = SYNTH_START,
105 .checkval = SYNTH_CHECK,
106 .vars = vars,
107 .probe = synth_probe,
108 .release = spk_serial_release,
109 .synth_immediate = spk_synth_immediate,
110 .catch_up = spk_do_catch_up,
111 .flush = spk_synth_flush,
112 .is_alive = spk_synth_is_alive_restart,
113 .synth_adjust = NULL,
114 .read_buff_add = NULL,
115 .get_index = NULL,
116 .indexing = {
117 .command = NULL,
118 .lowindex = 0,
119 .highindex = 0,
120 .currindex = 0,
121 },
122 .attributes = {
123 .attrs = synth_attrs,
124 .name = "acntsa",
125 },
126};
127
128static int synth_probe(struct spk_synth *synth)
129{
130 int failed;
131
132 failed = serial_synth_probe(synth);
133 if (failed == 0) {
134 spk_synth_immediate(synth, "\033=R\r");
135 mdelay(100);
136 }
137 synth->alive = !failed;
138 return failed;
139}
140
141module_param_named(ser, synth_acntsa.ser, int, S_IRUGO);
142module_param_named(start, synth_acntsa.startup, short, S_IRUGO);
143
144MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
145MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
146
147static int __init acntsa_init(void)
148{
149 return synth_add(&synth_acntsa);
150}
151
152static void __exit acntsa_exit(void)
153{
154 synth_remove(&synth_acntsa);
155}
156
157module_init(acntsa_init);
158module_exit(acntsa_exit);
159MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
160MODULE_AUTHOR("David Borowski");
161MODULE_DESCRIPTION("Speakup support for Accent SA synthesizer");
162MODULE_LICENSE("GPL");
163MODULE_VERSION(DRV_VERSION);
164
diff --git a/drivers/staging/speakup/speakup_apollo.c b/drivers/staging/speakup/speakup_apollo.c
new file mode 100644
index 00000000000..502c0324ad2
--- /dev/null
+++ b/drivers/staging/speakup/speakup_apollo.c
@@ -0,0 +1,225 @@
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 * this code is specificly written as a driver for the speakup screenreview
23 * package and is 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.21"
35#define SYNTH_CLEAR 0x18
36#define PROCSPEECH '\r'
37
38static void do_catch_up(struct spk_synth *synth);
39
40static struct var_t vars[] = {
41 { CAPS_START, .u.s = {"cap, " }},
42 { CAPS_STOP, .u.s = {"" }},
43 { RATE, .u.n = {"@W%d", 6, 1, 9, 0, 0, NULL }},
44 { PITCH, .u.n = {"@F%x", 10, 0, 15, 0, 0, NULL }},
45 { VOL, .u.n = {"@A%x", 10, 0, 15, 0, 0, NULL }},
46 { VOICE, .u.n = {"@V%d", 1, 1, 6, 0, 0, NULL }},
47 { LANG, .u.n = {"@=%d,", 1, 1, 4, 0, 0, NULL }},
48 { 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 */
55static struct kobj_attribute caps_start_attribute =
56 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
57static struct kobj_attribute caps_stop_attribute =
58 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
59static struct kobj_attribute lang_attribute =
60 __ATTR(lang, USER_RW, spk_var_show, spk_var_store);
61static struct kobj_attribute pitch_attribute =
62 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
63static struct kobj_attribute rate_attribute =
64 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
65static struct kobj_attribute voice_attribute =
66 __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
67static struct kobj_attribute vol_attribute =
68 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
69
70static struct kobj_attribute delay_time_attribute =
71 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
72static struct kobj_attribute direct_attribute =
73 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
74static struct kobj_attribute full_time_attribute =
75 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
76static struct kobj_attribute jiffy_delta_attribute =
77 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
78static struct kobj_attribute trigger_time_attribute =
79 __ATTR(trigger_time, ROOT_W, 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 */
85static 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
101static 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 .startup = SYNTH_START,
113 .checkval = SYNTH_CHECK,
114 .vars = vars,
115 .probe = serial_synth_probe,
116 .release = spk_serial_release,
117 .synth_immediate = spk_synth_immediate,
118 .catch_up = do_catch_up,
119 .flush = spk_synth_flush,
120 .is_alive = spk_synth_is_alive_restart,
121 .synth_adjust = NULL,
122 .read_buff_add = NULL,
123 .get_index = NULL,
124 .indexing = {
125 .command = NULL,
126 .lowindex = 0,
127 .highindex = 0,
128 .currindex = 0,
129 },
130 .attributes = {
131 .attrs = synth_attrs,
132 .name = "apollo",
133 },
134};
135
136static void do_catch_up(struct spk_synth *synth)
137{
138 u_char ch;
139 unsigned long flags;
140 unsigned long jiff_max;
141 struct var_t *jiffy_delta;
142 struct var_t *delay_time;
143 struct var_t *full_time;
144 int full_time_val = 0;
145 int delay_time_val = 0;
146 int jiffy_delta_val = 0;
147
148 jiffy_delta = get_var(JIFFY);
149 delay_time = get_var(DELAY);
150 full_time = get_var(FULL);
151 spk_lock(flags);
152 jiffy_delta_val = jiffy_delta->u.n.value;
153 spk_unlock(flags);
154 jiff_max = jiffies + jiffy_delta_val;
155
156 while (!kthread_should_stop()) {
157 spk_lock(flags);
158 jiffy_delta_val = jiffy_delta->u.n.value;
159 full_time_val = full_time->u.n.value;
160 delay_time_val = delay_time->u.n.value;
161 if (speakup_info.flushing) {
162 speakup_info.flushing = 0;
163 spk_unlock(flags);
164 synth->flush(synth);
165 continue;
166 }
167 if (synth_buffer_empty()) {
168 spk_unlock(flags);
169 break;
170 }
171 ch = synth_buffer_peek();
172 set_current_state(TASK_INTERRUPTIBLE);
173 full_time_val = full_time->u.n.value;
174 spk_unlock(flags);
175 if (!spk_serial_out(ch)) {
176 outb(UART_MCR_DTR, speakup_info.port_tts + UART_MCR);
177 outb(UART_MCR_DTR | UART_MCR_RTS,
178 speakup_info.port_tts + UART_MCR);
179 schedule_timeout(msecs_to_jiffies(full_time_val));
180 continue;
181 }
182 if ((jiffies >= jiff_max) && (ch == SPACE)) {
183 spk_lock(flags);
184 jiffy_delta_val = jiffy_delta->u.n.value;
185 full_time_val = full_time->u.n.value;
186 delay_time_val = delay_time->u.n.value;
187 spk_unlock(flags);
188 if (spk_serial_out(synth->procspeech))
189 schedule_timeout(msecs_to_jiffies(delay_time_val));
190 else
191 schedule_timeout(msecs_to_jiffies(full_time_val));
192 jiff_max = jiffies + jiffy_delta_val;
193 }
194 set_current_state(TASK_RUNNING);
195 spk_lock(flags);
196 synth_buffer_getc();
197 spk_unlock(flags);
198 }
199 spk_serial_out(PROCSPEECH);
200}
201
202module_param_named(ser, synth_apollo.ser, int, S_IRUGO);
203module_param_named(start, synth_apollo.startup, short, S_IRUGO);
204
205MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
206MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
207
208static int __init apollo_init(void)
209{
210 return synth_add(&synth_apollo);
211}
212
213static void __exit apollo_exit(void)
214{
215 synth_remove(&synth_apollo);
216}
217
218module_init(apollo_init);
219module_exit(apollo_exit);
220MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
221MODULE_AUTHOR("David Borowski");
222MODULE_DESCRIPTION("Speakup support for Apollo II synthesizer");
223MODULE_LICENSE("GPL");
224MODULE_VERSION(DRV_VERSION);
225
diff --git a/drivers/staging/speakup/speakup_audptr.c b/drivers/staging/speakup/speakup_audptr.c
new file mode 100644
index 00000000000..a194b6f2b5a
--- /dev/null
+++ b/drivers/staging/speakup/speakup_audptr.c
@@ -0,0 +1,195 @@
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 "spk_priv.h"
26#include "speakup.h"
27#include "serialio.h"
28
29#define DRV_VERSION "2.11"
30#define SYNTH_CLEAR 0x18 /* flush synth buffer */
31#define PROCSPEECH '\r' /* start synth processing speech char */
32
33static int synth_probe(struct spk_synth *synth);
34static void synth_flush(struct spk_synth *synth);
35
36static struct var_t vars[] = {
37 { CAPS_START, .u.s = {"\x05[f99]" }},
38 { CAPS_STOP, .u.s = {"\x05[f80]" }},
39 { RATE, .u.n = {"\x05[r%d]", 10, 0, 20, 100, -10, NULL }},
40 { PITCH, .u.n = {"\x05[f%d]", 80, 39, 4500, 0, 0, NULL }},
41 { VOL, .u.n = {"\x05[g%d]", 21, 0, 40, 0, 0, NULL }},
42 { TONE, .u.n = {"\x05[s%d]", 9, 0, 63, 0, 0, 0 }},
43 { PUNCT, .u.n = {"\x05[A%c]", 0, 0, 3, 0, 0, "nmsa" }},
44 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
45 V_LAST_VAR
46};
47
48/*
49 * These attributes will appear in /sys/accessibility/speakup/audptr.
50 */
51static struct kobj_attribute caps_start_attribute =
52 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
53static struct kobj_attribute caps_stop_attribute =
54 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
55static struct kobj_attribute pitch_attribute =
56 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
57static struct kobj_attribute punct_attribute =
58 __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
59static struct kobj_attribute rate_attribute =
60 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
61static struct kobj_attribute tone_attribute =
62 __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
63static struct kobj_attribute vol_attribute =
64 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
65
66static struct kobj_attribute delay_time_attribute =
67 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
68static struct kobj_attribute direct_attribute =
69 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
70static struct kobj_attribute full_time_attribute =
71 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
72static struct kobj_attribute jiffy_delta_attribute =
73 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
74static struct kobj_attribute trigger_time_attribute =
75 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
76
77/*
78 * Create a group of attributes so that we can create and destroy them all
79 * at once.
80 */
81static struct attribute *synth_attrs[] = {
82 &caps_start_attribute.attr,
83 &caps_stop_attribute.attr,
84 &pitch_attribute.attr,
85 &punct_attribute.attr,
86 &rate_attribute.attr,
87 &tone_attribute.attr,
88 &vol_attribute.attr,
89 &delay_time_attribute.attr,
90 &direct_attribute.attr,
91 &full_time_attribute.attr,
92 &jiffy_delta_attribute.attr,
93 &trigger_time_attribute.attr,
94 NULL, /* need to NULL terminate the list of attributes */
95};
96
97static struct spk_synth synth_audptr = {
98 .name = "audptr",
99 .version = DRV_VERSION,
100 .long_name = "Audapter",
101 .init = "\x05[D1]\x05[Ol]",
102 .procspeech = PROCSPEECH,
103 .clear = SYNTH_CLEAR,
104 .delay = 400,
105 .trigger = 50,
106 .jiffies = 30,
107 .full = 18000,
108 .startup = SYNTH_START,
109 .checkval = SYNTH_CHECK,
110 .vars = vars,
111 .probe = synth_probe,
112 .release = spk_serial_release,
113 .synth_immediate = spk_synth_immediate,
114 .catch_up = spk_do_catch_up,
115 .flush = synth_flush,
116 .is_alive = spk_synth_is_alive_restart,
117 .synth_adjust = NULL,
118 .read_buff_add = NULL,
119 .get_index = NULL,
120 .indexing = {
121 .command = NULL,
122 .lowindex = 0,
123 .highindex = 0,
124 .currindex = 0,
125 },
126 .attributes = {
127 .attrs = synth_attrs,
128 .name = "audptr",
129 },
130};
131
132static void synth_flush(struct spk_synth *synth)
133{
134 int timeout = SPK_XMITR_TIMEOUT;
135 while (spk_serial_tx_busy()) {
136 if (!--timeout)
137 break;
138 udelay(1);
139 }
140 outb(SYNTH_CLEAR, speakup_info.port_tts);
141 spk_serial_out(PROCSPEECH);
142}
143
144static void synth_version(struct spk_synth *synth)
145{
146 unsigned char test = 0;
147 char synth_id[40] = "";
148 spk_synth_immediate(synth, "\x05[Q]");
149 synth_id[test] = spk_serial_in();
150 if (synth_id[test] == 'A') {
151 do {
152 /* read version string from synth */
153 synth_id[++test] = spk_serial_in();
154 } while (synth_id[test] != '\n' && test < 32);
155 synth_id[++test] = 0x00;
156 }
157 if (synth_id[0] == 'A')
158 pr_info("%s version: %s", synth->long_name, synth_id);
159}
160
161static int synth_probe(struct spk_synth *synth)
162{
163 int failed = 0;
164
165 failed = serial_synth_probe(synth);
166 if (failed == 0)
167 synth_version(synth);
168 synth->alive = !failed;
169 return 0;
170}
171
172module_param_named(ser, synth_audptr.ser, int, S_IRUGO);
173module_param_named(start, synth_audptr.startup, short, S_IRUGO);
174
175MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
176MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
177
178static int __init audptr_init(void)
179{
180 return synth_add(&synth_audptr);
181}
182
183static void __exit audptr_exit(void)
184{
185 synth_remove(&synth_audptr);
186}
187
188module_init(audptr_init);
189module_exit(audptr_exit);
190MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
191MODULE_AUTHOR("David Borowski");
192MODULE_DESCRIPTION("Speakup support for Audapter synthesizer");
193MODULE_LICENSE("GPL");
194MODULE_VERSION(DRV_VERSION);
195
diff --git a/drivers/staging/speakup/speakup_bns.c b/drivers/staging/speakup/speakup_bns.c
new file mode 100644
index 00000000000..e1b19f7de7c
--- /dev/null
+++ b/drivers/staging/speakup/speakup_bns.c
@@ -0,0 +1,147 @@
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 * this code is specificly written as a driver for the speakup screenreview
23 * package and is not a general device driver.
24 */
25#include "spk_priv.h"
26#include "speakup.h"
27
28#define DRV_VERSION "2.11"
29#define SYNTH_CLEAR 0x18
30#define PROCSPEECH '\r'
31
32static struct var_t vars[] = {
33 { CAPS_START, .u.s = {"\x05\x31\x32P" }},
34 { CAPS_STOP, .u.s = {"\x05\x38P" }},
35 { RATE, .u.n = {"\x05%dE", 8, 1, 16, 0, 0, NULL }},
36 { PITCH, .u.n = {"\x05%dP", 8, 0, 16, 0, 0, NULL }},
37 { VOL, .u.n = {"\x05%dV", 8, 0, 16, 0, 0, NULL }},
38 { TONE, .u.n = {"\x05%dT", 8, 0, 16, 0, 0, NULL }},
39 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
40 V_LAST_VAR
41};
42
43/*
44 * These attributes will appear in /sys/accessibility/speakup/bns.
45 */
46static struct kobj_attribute caps_start_attribute =
47 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
48static struct kobj_attribute caps_stop_attribute =
49 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
50static struct kobj_attribute pitch_attribute =
51 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
52static struct kobj_attribute rate_attribute =
53 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
54static struct kobj_attribute tone_attribute =
55 __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
56static struct kobj_attribute vol_attribute =
57 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
58
59static struct kobj_attribute delay_time_attribute =
60 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
61static struct kobj_attribute direct_attribute =
62 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
63static struct kobj_attribute full_time_attribute =
64 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
65static struct kobj_attribute jiffy_delta_attribute =
66 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
67static struct kobj_attribute trigger_time_attribute =
68 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
69
70/*
71 * Create a group of attributes so that we can create and destroy them all
72 * at once.
73 */
74static struct attribute *synth_attrs[] = {
75 &caps_start_attribute.attr,
76 &caps_stop_attribute.attr,
77 &pitch_attribute.attr,
78 &rate_attribute.attr,
79 &tone_attribute.attr,
80 &vol_attribute.attr,
81 &delay_time_attribute.attr,
82 &direct_attribute.attr,
83 &full_time_attribute.attr,
84 &jiffy_delta_attribute.attr,
85 &trigger_time_attribute.attr,
86 NULL, /* need to NULL terminate the list of attributes */
87};
88
89static struct spk_synth synth_bns = {
90 .name = "bns",
91 .version = DRV_VERSION,
92 .long_name = "Braille 'N Speak",
93 .init = "\x05Z\x05\x43",
94 .procspeech = PROCSPEECH,
95 .clear = SYNTH_CLEAR,
96 .delay = 500,
97 .trigger = 50,
98 .jiffies = 50,
99 .full = 40000,
100 .startup = SYNTH_START,
101 .checkval = SYNTH_CHECK,
102 .vars = vars,
103 .probe = serial_synth_probe,
104 .release = spk_serial_release,
105 .synth_immediate = spk_synth_immediate,
106 .catch_up = spk_do_catch_up,
107 .flush = spk_synth_flush,
108 .is_alive = spk_synth_is_alive_restart,
109 .synth_adjust = NULL,
110 .read_buff_add = NULL,
111 .get_index = NULL,
112 .indexing = {
113 .command = NULL,
114 .lowindex = 0,
115 .highindex = 0,
116 .currindex = 0,
117 },
118 .attributes = {
119 .attrs = synth_attrs,
120 .name = "bns",
121 },
122};
123
124module_param_named(ser, synth_bns.ser, int, S_IRUGO);
125module_param_named(start, synth_bns.startup, short, S_IRUGO);
126
127MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
128MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
129
130static int __init bns_init(void)
131{
132 return synth_add(&synth_bns);
133}
134
135static void __exit bns_exit(void)
136{
137 synth_remove(&synth_bns);
138}
139
140module_init(bns_init);
141module_exit(bns_exit);
142MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
143MODULE_AUTHOR("David Borowski");
144MODULE_DESCRIPTION("Speakup support for Braille 'n Speak synthesizers");
145MODULE_LICENSE("GPL");
146MODULE_VERSION(DRV_VERSION);
147
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
37static 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
42static void do_catch_up(struct spk_synth *synth);
43static void synth_flush(struct spk_synth *synth);
44
45static int in_escape;
46
47static 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 */
62static struct kobj_attribute caps_start_attribute =
63 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
64static struct kobj_attribute caps_stop_attribute =
65 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
66static struct kobj_attribute pitch_attribute =
67 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
68static struct kobj_attribute punct_attribute =
69 __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
70static struct kobj_attribute rate_attribute =
71 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
72static struct kobj_attribute voice_attribute =
73 __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
74static struct kobj_attribute vol_attribute =
75 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
76
77static struct kobj_attribute delay_time_attribute =
78 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
79static struct kobj_attribute direct_attribute =
80 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
81static struct kobj_attribute full_time_attribute =
82 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
83static struct kobj_attribute jiffy_delta_attribute =
84 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
85static 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 */
92static 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
108static 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
144static 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
213static void synth_flush(struct spk_synth *synth)
214{
215 in_escape = 0;
216 spk_synth_immediate(synth, "\033P;10z\033\\");
217}
218
219module_param_named(ser, synth_decext.ser, int, S_IRUGO);
220module_param_named(start, synth_decext.startup, short, S_IRUGO);
221
222MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
223MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
224
225static int __init decext_init(void)
226{
227 return synth_add(&synth_decext);
228}
229
230static void __exit decext_exit(void)
231{
232 synth_remove(&synth_decext);
233}
234
235module_init(decext_init);
236module_exit(decext_exit);
237MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
238MODULE_AUTHOR("David Borowski");
239MODULE_DESCRIPTION("Speakup support for DECtalk External synthesizers");
240MODULE_LICENSE("GPL");
241MODULE_VERSION(DRV_VERSION);
242
diff --git a/drivers/staging/speakup/speakup_decpc.c b/drivers/staging/speakup/speakup_decpc.c
new file mode 100644
index 00000000000..490b758fb4e
--- /dev/null
+++ b/drivers/staging/speakup/speakup_decpc.c
@@ -0,0 +1,503 @@
1/*
2 * This is the DECtalk PC speakup driver
3 *
4 * Some constants from DEC's DOS driver:
5 * Copyright (c) by Digital Equipment Corp.
6 *
7 * 386BSD DECtalk PC driver:
8 * Copyright (c) 1996 Brian Buhrow <buhrow@lothlorien.nfbcal.org>
9 *
10 * Linux DECtalk PC driver:
11 * Copyright (c) 1997 Nicolas Pitre <nico@cam.org>
12 *
13 * speakup DECtalk PC Internal driver:
14 * Copyright (c) 2003 David Borowski <david575@golden.net>
15 *
16 * All rights reserved.
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 */
32#include <linux/jiffies.h>
33#include <linux/sched.h>
34#include <linux/timer.h>
35#include <linux/kthread.h>
36
37#include "spk_priv.h"
38#include "speakup.h"
39
40#define MODULE_init 0x0dec /* module in boot code */
41#define MODULE_self_test 0x8800 /* module in self-test */
42#define MODULE_reset 0xffff /* reinit the whole module */
43
44#define MODE_mask 0xf000 /* mode bits in high nibble */
45#define MODE_null 0x0000
46#define MODE_test 0x2000 /* in testing mode */
47#define MODE_status 0x8000
48#define STAT_int 0x0001 /* running in interrupt mode */
49#define STAT_tr_char 0x0002 /* character data to transmit */
50#define STAT_rr_char 0x0004 /* ready to receive char data */
51#define STAT_cmd_ready 0x0008 /* ready to accept commands */
52#define STAT_dma_ready 0x0010 /* dma command ready */
53#define STAT_digitized 0x0020 /* spc in digitized mode */
54#define STAT_new_index 0x0040 /* new last index ready */
55#define STAT_new_status 0x0080 /* new status posted */
56#define STAT_dma_state 0x0100 /* dma state toggle */
57#define STAT_index_valid 0x0200 /* indexs are valid */
58#define STAT_flushing 0x0400 /* flush in progress */
59#define STAT_self_test 0x0800 /* module in self test */
60#define MODE_ready 0xc000 /* module ready for next phase */
61#define READY_boot 0x0000
62#define READY_kernel 0x0001
63#define MODE_error 0xf000
64
65#define CMD_mask 0xf000 /* mask for command nibble */
66#define CMD_null 0x0000 /* post status */
67#define CMD_control 0x1000 /* hard control command */
68#define CTRL_mask 0x0F00 /* mask off control nibble */
69#define CTRL_data 0x00FF /* madk to get data byte */
70#define CTRL_null 0x0000 /* null control */
71#define CTRL_vol_up 0x0100 /* increase volume */
72#define CTRL_vol_down 0x0200 /* decrease volume */
73#define CTRL_vol_set 0x0300 /* set volume */
74#define CTRL_pause 0x0400 /* pause spc */
75#define CTRL_resume 0x0500 /* resume spc clock */
76#define CTRL_resume_spc 0x0001 /* resume spc soft pause */
77#define CTRL_flush 0x0600 /* flush all buffers */
78#define CTRL_int_enable 0x0700 /* enable status change ints */
79#define CTRL_buff_free 0x0800 /* buffer remain count */
80#define CTRL_buff_used 0x0900 /* buffer in use */
81#define CTRL_speech 0x0a00 /* immediate speech change */
82#define CTRL_SP_voice 0x0001 /* voice change */
83#define CTRL_SP_rate 0x0002 /* rate change */
84#define CTRL_SP_comma 0x0003 /* comma pause change */
85#define CTRL_SP_period 0x0004 /* period pause change */
86#define CTRL_SP_rate_delta 0x0005 /* delta rate change */
87#define CTRL_SP_get_param 0x0006 /* return the desired parameter */
88#define CTRL_last_index 0x0b00 /* get last index spoken */
89#define CTRL_io_priority 0x0c00 /* change i/o priority */
90#define CTRL_free_mem 0x0d00 /* get free paragraphs on module */
91#define CTRL_get_lang 0x0e00 /* return bit mask of loaded
92 * languages */
93#define CMD_test 0x2000 /* self-test request */
94#define TEST_mask 0x0F00 /* isolate test field */
95#define TEST_null 0x0000 /* no test requested */
96#define TEST_isa_int 0x0100 /* assert isa irq */
97#define TEST_echo 0x0200 /* make data in == data out */
98#define TEST_seg 0x0300 /* set peek/poke segment */
99#define TEST_off 0x0400 /* set peek/poke offset */
100#define TEST_peek 0x0500 /* data out == *peek */
101#define TEST_poke 0x0600 /* *peek == data in */
102#define TEST_sub_code 0x00FF /* user defined test sub codes */
103#define CMD_id 0x3000 /* return software id */
104#define ID_null 0x0000 /* null id */
105#define ID_kernel 0x0100 /* kernel code executing */
106#define ID_boot 0x0200 /* boot code executing */
107#define CMD_dma 0x4000 /* force a dma start */
108#define CMD_reset 0x5000 /* reset module status */
109#define CMD_sync 0x6000 /* kernel sync command */
110#define CMD_char_in 0x7000 /* single character send */
111#define CMD_char_out 0x8000 /* single character get */
112#define CHAR_count_1 0x0100 /* one char in cmd_low */
113#define CHAR_count_2 0x0200 /* the second in data_low */
114#define CHAR_count_3 0x0300 /* the third in data_high */
115#define CMD_spc_mode 0x9000 /* change spc mode */
116#define CMD_spc_to_text 0x0100 /* set to text mode */
117#define CMD_spc_to_digit 0x0200 /* set to digital mode */
118#define CMD_spc_rate 0x0400 /* change spc data rate */
119#define CMD_error 0xf000 /* severe error */
120
121enum { PRIMARY_DIC = 0, USER_DIC, COMMAND_DIC, ABBREV_DIC };
122
123#define DMA_single_in 0x01
124#define DMA_single_out 0x02
125#define DMA_buff_in 0x03
126#define DMA_buff_out 0x04
127#define DMA_control 0x05
128#define DT_MEM_ALLOC 0x03
129#define DT_SET_DIC 0x04
130#define DT_START_TASK 0x05
131#define DT_LOAD_MEM 0x06
132#define DT_READ_MEM 0x07
133#define DT_DIGITAL_IN 0x08
134#define DMA_sync 0x06
135#define DMA_sync_char 0x07
136
137#define DRV_VERSION "2.12"
138#define PROCSPEECH 0x0b
139#define SYNTH_IO_EXTENT 8
140
141static int synth_probe(struct spk_synth *synth);
142static void dtpc_release(void);
143static const char *synth_immediate(struct spk_synth *synth, const char *buf);
144static void do_catch_up(struct spk_synth *synth);
145static void synth_flush(struct spk_synth *synth);
146
147static int synth_portlist[] = { 0x340, 0x350, 0x240, 0x250, 0 };
148static int in_escape, is_flushing;
149static int dt_stat, dma_state;
150
151static struct var_t vars[] = {
152 { CAPS_START, .u.s = {"[:dv ap 200]" }},
153 { CAPS_STOP, .u.s = {"[:dv ap 100]" }},
154 { RATE, .u.n = {"[:ra %d]", 9, 0, 18, 150, 25, NULL }},
155 { PITCH, .u.n = {"[:dv ap %d]", 80, 0, 100, 20, 0, NULL }},
156 { VOL, .u.n = {"[:vo se %d]", 5, 0, 9, 5, 10, NULL }},
157 { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" }},
158 { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" }},
159 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
160 V_LAST_VAR
161};
162
163/*
164 * These attributes will appear in /sys/accessibility/speakup/decpc.
165 */
166static struct kobj_attribute caps_start_attribute =
167 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
168static struct kobj_attribute caps_stop_attribute =
169 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
170static struct kobj_attribute pitch_attribute =
171 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
172static struct kobj_attribute punct_attribute =
173 __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
174static struct kobj_attribute rate_attribute =
175 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
176static struct kobj_attribute voice_attribute =
177 __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
178static struct kobj_attribute vol_attribute =
179 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
180
181static struct kobj_attribute delay_time_attribute =
182 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
183static struct kobj_attribute direct_attribute =
184 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
185static struct kobj_attribute full_time_attribute =
186 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
187static struct kobj_attribute jiffy_delta_attribute =
188 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
189static struct kobj_attribute trigger_time_attribute =
190 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
191
192/*
193 * Create a group of attributes so that we can create and destroy them all
194 * at once.
195 */
196static struct attribute *synth_attrs[] = {
197 &caps_start_attribute.attr,
198 &caps_stop_attribute.attr,
199 &pitch_attribute.attr,
200 &punct_attribute.attr,
201 &rate_attribute.attr,
202 &voice_attribute.attr,
203 &vol_attribute.attr,
204 &delay_time_attribute.attr,
205 &direct_attribute.attr,
206 &full_time_attribute.attr,
207 &jiffy_delta_attribute.attr,
208 &trigger_time_attribute.attr,
209 NULL, /* need to NULL terminate the list of attributes */
210};
211
212static struct spk_synth synth_dec_pc = {
213 .name = "decpc",
214 .version = DRV_VERSION,
215 .long_name = "Dectalk PC",
216 .init = "[:pe -380]",
217 .procspeech = PROCSPEECH,
218 .delay = 500,
219 .trigger = 50,
220 .jiffies = 50,
221 .full = 1000,
222 .flags = SF_DEC,
223 .startup = SYNTH_START,
224 .checkval = SYNTH_CHECK,
225 .vars = vars,
226 .probe = synth_probe,
227 .release = dtpc_release,
228 .synth_immediate = synth_immediate,
229 .catch_up = do_catch_up,
230 .flush = synth_flush,
231 .is_alive = spk_synth_is_alive_nop,
232 .synth_adjust = NULL,
233 .read_buff_add = NULL,
234 .get_index = NULL,
235 .indexing = {
236 .command = NULL,
237 .lowindex = 0,
238 .highindex = 0,
239 .currindex = 0,
240 },
241 .attributes = {
242 .attrs = synth_attrs,
243 .name = "decpc",
244 },
245};
246
247static int dt_getstatus(void)
248{
249 dt_stat = inb_p(speakup_info.port_tts) |
250 (inb_p(speakup_info.port_tts + 1) << 8);
251 return dt_stat;
252}
253
254static void dt_sendcmd(u_int cmd)
255{
256 outb_p(cmd & 0xFF, speakup_info.port_tts);
257 outb_p((cmd >> 8) & 0xFF, speakup_info.port_tts+1);
258}
259
260static int dt_waitbit(int bit)
261{
262 int timeout = 100;
263 while (--timeout > 0) {
264 if ((dt_getstatus() & bit) == bit)
265 return 1;
266 udelay(50);
267 }
268 return 0;
269}
270
271static int dt_wait_dma(void)
272{
273 int timeout = 100, state = dma_state;
274 if (!dt_waitbit(STAT_dma_ready))
275 return 0;
276 while (--timeout > 0) {
277 if ((dt_getstatus()&STAT_dma_state) == state)
278 return 1;
279 udelay(50);
280 }
281 dma_state = dt_getstatus() & STAT_dma_state;
282 return 1;
283}
284
285static int dt_ctrl(u_int cmd)
286{
287 int timeout = 10;
288 if (!dt_waitbit(STAT_cmd_ready))
289 return -1;
290 outb_p(0, speakup_info.port_tts+2);
291 outb_p(0, speakup_info.port_tts+3);
292 dt_getstatus();
293 dt_sendcmd(CMD_control|cmd);
294 outb_p(0, speakup_info.port_tts+6);
295 while (dt_getstatus() & STAT_cmd_ready) {
296 udelay(20);
297 if (--timeout == 0)
298 break;
299 }
300 dt_sendcmd(CMD_null);
301 return 0;
302}
303
304static void synth_flush(struct spk_synth *synth)
305{
306 int timeout = 10;
307 if (is_flushing)
308 return;
309 is_flushing = 4;
310 in_escape = 0;
311 while (dt_ctrl(CTRL_flush)) {
312 if (--timeout == 0)
313 break;
314udelay(50);
315 }
316 for (timeout = 0; timeout < 10; timeout++) {
317 if (dt_waitbit(STAT_dma_ready))
318 break;
319udelay(50);
320 }
321 outb_p(DMA_sync, speakup_info.port_tts+4);
322 outb_p(0, speakup_info.port_tts+4);
323 udelay(100);
324 for (timeout = 0; timeout < 10; timeout++) {
325 if (!(dt_getstatus() & STAT_flushing))
326 break;
327udelay(50);
328 }
329 dma_state = dt_getstatus() & STAT_dma_state;
330 dma_state ^= STAT_dma_state;
331 is_flushing = 0;
332}
333
334static int dt_sendchar(char ch)
335{
336 if (!dt_wait_dma())
337 return -1;
338 if (!(dt_stat & STAT_rr_char))
339 return -2;
340 outb_p(DMA_single_in, speakup_info.port_tts+4);
341 outb_p(ch, speakup_info.port_tts+4);
342 dma_state ^= STAT_dma_state;
343 return 0;
344}
345
346static int testkernel(void)
347{
348 int status = 0;
349 if (dt_getstatus() == 0xffff) {
350 status = -1;
351 goto oops;
352 }
353 dt_sendcmd(CMD_sync);
354 if (!dt_waitbit(STAT_cmd_ready))
355 status = -2;
356 else if (dt_stat&0x8000)
357 return 0;
358 else if (dt_stat == 0x0dec)
359 pr_warn("dec_pc at 0x%x, software not loaded\n",
360 speakup_info.port_tts);
361 status = -3;
362oops: synth_release_region(speakup_info.port_tts, SYNTH_IO_EXTENT);
363 speakup_info.port_tts = 0;
364 return status;
365}
366
367static void do_catch_up(struct spk_synth *synth)
368{
369 u_char ch;
370 static u_char last = '\0';
371 unsigned long flags;
372 unsigned long jiff_max;
373 struct var_t *jiffy_delta;
374 struct var_t *delay_time;
375 int jiffy_delta_val;
376 int delay_time_val;
377
378 jiffy_delta = get_var(JIFFY);
379 delay_time = get_var(DELAY);
380 spk_lock(flags);
381 jiffy_delta_val = jiffy_delta->u.n.value;
382 spk_unlock(flags);
383 jiff_max = jiffies + jiffy_delta_val;
384
385 while (!kthread_should_stop()) {
386 spk_lock(flags);
387 if (speakup_info.flushing) {
388 speakup_info.flushing = 0;
389 spk_unlock(flags);
390 synth->flush(synth);
391 continue;
392 }
393 if (synth_buffer_empty()) {
394 spk_unlock(flags);
395 break;
396 }
397 ch = synth_buffer_peek();
398 set_current_state(TASK_INTERRUPTIBLE);
399 delay_time_val = delay_time->u.n.value;
400 spk_unlock(flags);
401 if (ch == '\n')
402 ch = 0x0D;
403 if (dt_sendchar(ch)) {
404 schedule_timeout(msecs_to_jiffies(delay_time_val));
405 continue;
406 }
407 set_current_state(TASK_RUNNING);
408 spk_lock(flags);
409 synth_buffer_getc();
410 spk_unlock(flags);
411 if (ch == '[')
412 in_escape = 1;
413 else if (ch == ']')
414 in_escape = 0;
415 else if (ch <= SPACE) {
416 if (!in_escape && strchr(",.!?;:", last))
417 dt_sendchar(PROCSPEECH);
418 if (jiffies >= jiff_max) {
419 if (!in_escape)
420 dt_sendchar(PROCSPEECH);
421 spk_lock(flags);
422 jiffy_delta_val = jiffy_delta->u.n.value;
423 delay_time_val = delay_time->u.n.value;
424 spk_unlock(flags);
425 schedule_timeout(msecs_to_jiffies(delay_time_val));
426 jiff_max = jiffies + jiffy_delta_val;
427 }
428 }
429 last = ch;
430 ch = 0;
431 }
432 if (!in_escape)
433 dt_sendchar(PROCSPEECH);
434}
435
436static const char *synth_immediate(struct spk_synth *synth, const char *buf)
437{
438 u_char ch;
439 while ((ch = *buf)) {
440 if (ch == '\n')
441 ch = PROCSPEECH;
442 if (dt_sendchar(ch))
443 return buf;
444 buf++;
445 }
446 return 0;
447}
448
449static int synth_probe(struct spk_synth *synth)
450{
451 int i = 0, failed = 0;
452 pr_info("Probing for %s.\n", synth->long_name);
453 for (i = 0; synth_portlist[i]; i++) {
454 if (synth_request_region(synth_portlist[i], SYNTH_IO_EXTENT)) {
455 pr_warn("request_region: failed with 0x%x, %d\n",
456 synth_portlist[i], SYNTH_IO_EXTENT);
457 continue;
458 }
459 speakup_info.port_tts = synth_portlist[i];
460 failed = testkernel();
461 if (failed == 0)
462 break;
463 }
464 if (failed) {
465 pr_info("%s: not found\n", synth->long_name);
466 return -ENODEV;
467 }
468 pr_info("%s: %03x-%03x, Driver Version %s,\n", synth->long_name,
469 speakup_info.port_tts, speakup_info.port_tts + 7,
470 synth->version);
471 synth->alive = 1;
472 return 0;
473}
474
475static void dtpc_release(void)
476{
477 if (speakup_info.port_tts)
478 synth_release_region(speakup_info.port_tts, SYNTH_IO_EXTENT);
479 speakup_info.port_tts = 0;
480}
481
482module_param_named(start, synth_dec_pc.startup, short, S_IRUGO);
483
484MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
485
486static int __init decpc_init(void)
487{
488 return synth_add(&synth_dec_pc);
489}
490
491static void __exit decpc_exit(void)
492{
493 synth_remove(&synth_dec_pc);
494}
495
496module_init(decpc_init);
497module_exit(decpc_exit);
498MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
499MODULE_AUTHOR("David Borowski");
500MODULE_DESCRIPTION("Speakup support for DECtalk PC synthesizers");
501MODULE_LICENSE("GPL");
502MODULE_VERSION(DRV_VERSION);
503
diff --git a/drivers/staging/speakup/speakup_dectlk.c b/drivers/staging/speakup/speakup_dectlk.c
new file mode 100644
index 00000000000..c17e9bc3422
--- /dev/null
+++ b/drivers/staging/speakup/speakup_dectlk.c
@@ -0,0 +1,315 @@
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/unistd.h>
26#include <linux/proc_fs.h>
27#include <linux/jiffies.h>
28#include <linux/spinlock.h>
29#include <linux/sched.h>
30#include <linux/timer.h>
31#include <linux/kthread.h>
32#include "speakup.h"
33#include "spk_priv.h"
34#include "serialio.h"
35
36#define DRV_VERSION "2.20"
37#define SYNTH_CLEAR 0x03
38#define PROCSPEECH 0x0b
39static volatile int xoff;
40#define synth_full() (xoff)
41
42static void do_catch_up(struct spk_synth *synth);
43static void synth_flush(struct spk_synth *synth);
44static void read_buff_add(u_char c);
45static unsigned char get_index(void);
46
47static int in_escape;
48static int is_flushing;
49
50static spinlock_t flush_lock;
51static DECLARE_WAIT_QUEUE_HEAD(flush);
52
53static struct var_t vars[] = {
54 { CAPS_START, .u.s = {"[:dv ap 160] " }},
55 { CAPS_STOP, .u.s = {"[:dv ap 100 ] " }},
56 { RATE, .u.n = {"[:ra %d] ", 180, 75, 650, 0, 0, NULL }},
57 { PITCH, .u.n = {"[:dv ap %d] ", 122, 50, 350, 0, 0, NULL }},
58 { VOL, .u.n = {"[:dv g5 %d] ", 86, 60, 86, 0, 0, NULL }},
59 { PUNCT, .u.n = {"[:pu %c] ", 0, 0, 2, 0, 0, "nsa" }},
60 { VOICE, .u.n = {"[:n%c] ", 0, 0, 9, 0, 0, "phfdburwkv" }},
61 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
62 V_LAST_VAR
63};
64
65/*
66 * These attributes will appear in /sys/accessibility/speakup/dectlk.
67 */
68static struct kobj_attribute caps_start_attribute =
69 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
70static struct kobj_attribute caps_stop_attribute =
71 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
72static struct kobj_attribute pitch_attribute =
73 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
74static struct kobj_attribute punct_attribute =
75 __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
76static struct kobj_attribute rate_attribute =
77 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
78static struct kobj_attribute voice_attribute =
79 __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
80static struct kobj_attribute vol_attribute =
81 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
82
83static struct kobj_attribute delay_time_attribute =
84 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
85static struct kobj_attribute direct_attribute =
86 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
87static struct kobj_attribute full_time_attribute =
88 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
89static struct kobj_attribute jiffy_delta_attribute =
90 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
91static struct kobj_attribute trigger_time_attribute =
92 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
93
94/*
95 * Create a group of attributes so that we can create and destroy them all
96 * at once.
97 */
98static struct attribute *synth_attrs[] = {
99 &caps_start_attribute.attr,
100 &caps_stop_attribute.attr,
101 &pitch_attribute.attr,
102 &punct_attribute.attr,
103 &rate_attribute.attr,
104 &voice_attribute.attr,
105 &vol_attribute.attr,
106 &delay_time_attribute.attr,
107 &direct_attribute.attr,
108 &full_time_attribute.attr,
109 &jiffy_delta_attribute.attr,
110 &trigger_time_attribute.attr,
111 NULL, /* need to NULL terminate the list of attributes */
112};
113
114static int ap_defaults[] = {122, 89, 155, 110, 208, 240, 200, 106, 306};
115static int g5_defaults[] = {86, 81, 86, 84, 81, 80, 83, 83, 73};
116
117static struct spk_synth synth_dectlk = {
118 .name = "dectlk",
119 .version = DRV_VERSION,
120 .long_name = "Dectalk Express",
121 .init = "[:error sp :name paul :rate 180 :tsr off] ",
122 .procspeech = PROCSPEECH,
123 .clear = SYNTH_CLEAR,
124 .delay = 500,
125 .trigger = 50,
126 .jiffies = 50,
127 .full = 40000,
128 .startup = SYNTH_START,
129 .checkval = SYNTH_CHECK,
130 .vars = vars,
131 .default_pitch = ap_defaults,
132 .default_vol = g5_defaults,
133 .probe = serial_synth_probe,
134 .release = spk_serial_release,
135 .synth_immediate = spk_synth_immediate,
136 .catch_up = do_catch_up,
137 .flush = synth_flush,
138 .is_alive = spk_synth_is_alive_restart,
139 .synth_adjust = NULL,
140 .read_buff_add = read_buff_add,
141 .get_index = get_index,
142 .indexing = {
143 .command = "[:in re %d ] ",
144 .lowindex = 1,
145 .highindex = 8,
146 .currindex = 1,
147 },
148 .attributes = {
149 .attrs = synth_attrs,
150 .name = "dectlk",
151 },
152};
153
154static int is_indnum(u_char *ch)
155{
156 if ((*ch >= '0') && (*ch <= '9')) {
157 *ch = *ch - '0';
158 return 1;
159 }
160 return 0;
161}
162
163static u_char lastind = 0;
164
165static unsigned char get_index(void)
166{
167 u_char rv;
168 rv = lastind;
169 lastind = 0;
170 return rv;
171}
172
173static void read_buff_add(u_char c)
174{
175 static int ind = -1;
176
177 if (c == 0x01) {
178 unsigned long flags;
179 spin_lock_irqsave(&flush_lock, flags);
180 is_flushing = 0;
181 wake_up_interruptible(&flush);
182 spin_unlock_irqrestore(&flush_lock, flags);
183 } else if (c == 0x13) {
184 xoff = 1;
185 } else if (c == 0x11) {
186 xoff = 0;
187 } else if (is_indnum(&c)) {
188 if (ind == -1)
189 ind = c;
190 else
191 ind = ind * 10 + c;
192 } else if ((c > 31) && (c < 127)) {
193 if (ind != -1)
194 lastind = (u_char)ind;
195 ind = -1;
196 }
197}
198
199static void do_catch_up(struct spk_synth *synth)
200{
201 static u_char ch = 0;
202 static u_char last = '\0';
203 unsigned long flags;
204 unsigned long jiff_max;
205 unsigned long timeout = msecs_to_jiffies(4000);
206 DEFINE_WAIT(wait);
207 struct var_t *jiffy_delta;
208 struct var_t *delay_time;
209 int jiffy_delta_val;
210 int delay_time_val;
211
212 jiffy_delta = get_var(JIFFY);
213 delay_time = get_var(DELAY);
214 spk_lock(flags);
215 jiffy_delta_val = jiffy_delta->u.n.value;
216 spk_unlock(flags);
217 jiff_max = jiffies + jiffy_delta_val;
218
219 while (!kthread_should_stop()) {
220 /* if no ctl-a in 4, send data anyway */
221 spin_lock_irqsave(&flush_lock, flags);
222 while (is_flushing && timeout) {
223 prepare_to_wait(&flush, &wait, TASK_INTERRUPTIBLE);
224 spin_unlock_irqrestore(&flush_lock, flags);
225 timeout = schedule_timeout(timeout);
226 spin_lock_irqsave(&flush_lock, flags);
227 }
228 finish_wait(&flush, &wait);
229 is_flushing = 0;
230 spin_unlock_irqrestore(&flush_lock, flags);
231
232 spk_lock(flags);
233 if (speakup_info.flushing) {
234 speakup_info.flushing = 0;
235 spk_unlock(flags);
236 synth->flush(synth);
237 continue;
238 }
239 if (synth_buffer_empty()) {
240 spk_unlock(flags);
241 break;
242 }
243 ch = synth_buffer_peek();
244 set_current_state(TASK_INTERRUPTIBLE);
245 delay_time_val = delay_time->u.n.value;
246 spk_unlock(flags);
247 if (ch == '\n')
248 ch = 0x0D;
249 if (synth_full() || !spk_serial_out(ch)) {
250 schedule_timeout(msecs_to_jiffies(delay_time_val));
251 continue;
252 }
253 set_current_state(TASK_RUNNING);
254 spk_lock(flags);
255 synth_buffer_getc();
256 spk_unlock(flags);
257 if (ch == '[')
258 in_escape = 1;
259 else if (ch == ']')
260 in_escape = 0;
261 else if (ch <= SPACE) {
262 if (!in_escape && strchr(",.!?;:", last))
263 spk_serial_out(PROCSPEECH);
264 if (jiffies >= jiff_max) {
265 if ( ! in_escape )
266 spk_serial_out(PROCSPEECH);
267 spk_lock(flags);
268 jiffy_delta_val = jiffy_delta->u.n.value;
269 delay_time_val = delay_time->u.n.value;
270 spk_unlock(flags);
271 schedule_timeout(msecs_to_jiffies(delay_time_val));
272 jiff_max = jiffies + jiffy_delta_val;
273 }
274 }
275 last = ch;
276 }
277 if (!in_escape)
278 spk_serial_out(PROCSPEECH);
279}
280
281static void synth_flush(struct spk_synth *synth)
282{
283 if (in_escape) {
284 /* if in command output ']' so we don't get an error */
285 spk_serial_out(']');
286 }
287 in_escape = 0;
288 is_flushing = 1;
289 spk_serial_out(SYNTH_CLEAR);
290}
291
292module_param_named(ser, synth_dectlk.ser, int, S_IRUGO);
293module_param_named(start, synth_dectlk.startup, short, S_IRUGO);
294
295MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
296MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
297
298static int __init dectlk_init(void)
299{
300 return synth_add(&synth_dectlk);
301}
302
303static void __exit dectlk_exit(void)
304{
305 synth_remove(&synth_dectlk);
306}
307
308module_init(dectlk_init);
309module_exit(dectlk_exit);
310MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
311MODULE_AUTHOR("David Borowski");
312MODULE_DESCRIPTION("Speakup support for DECtalk Express synthesizers");
313MODULE_LICENSE("GPL");
314MODULE_VERSION(DRV_VERSION);
315
diff --git a/drivers/staging/speakup/speakup_dtlk.c b/drivers/staging/speakup/speakup_dtlk.c
new file mode 100644
index 00000000000..b907c4f27e8
--- /dev/null
+++ b/drivers/staging/speakup/speakup_dtlk.c
@@ -0,0 +1,386 @@
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 * package it's not a general device driver.
24 * This driver is for the RC Systems DoubleTalk PC internal synthesizer.
25 */
26#include <linux/jiffies.h>
27#include <linux/sched.h>
28#include <linux/timer.h>
29#include <linux/kthread.h>
30
31#include "spk_priv.h"
32#include "serialio.h"
33#include "speakup_dtlk.h" /* local header file for DoubleTalk values */
34#include "speakup.h"
35
36#define DRV_VERSION "2.10"
37#define PROCSPEECH 0x00
38#define synth_readable() ((synth_status = inb_p(speakup_info.port_tts + UART_RX)) & TTS_READABLE)
39#define synth_writable() ((synth_status = inb_p(speakup_info.port_tts + UART_RX)) & TTS_WRITABLE)
40#define synth_full() ((synth_status = inb_p(speakup_info.port_tts + UART_RX)) & TTS_ALMOST_FULL)
41
42static int synth_probe(struct spk_synth *synth);
43static void dtlk_release(void);
44static const char *synth_immediate(struct spk_synth *synth, const char *buf);
45static void do_catch_up(struct spk_synth *synth);
46static void synth_flush(struct spk_synth *synth);
47
48static int synth_lpc;
49static int port_forced;
50static unsigned int synth_portlist[] =
51 { 0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0 };
52static u_char synth_status;
53
54static struct var_t vars[] = {
55 { CAPS_START, .u.s = {"\x01+35p" }},
56 { CAPS_STOP, .u.s = {"\x01-35p" }},
57 { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL }},
58 { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL }},
59 { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL }},
60 { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL }},
61 { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL }},
62 { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL }},
63 { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL }},
64 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
65 V_LAST_VAR
66};
67
68/*
69 * These attributes will appear in /sys/accessibility/speakup/dtlk.
70 */
71static struct kobj_attribute caps_start_attribute =
72 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
73static struct kobj_attribute caps_stop_attribute =
74 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
75static struct kobj_attribute freq_attribute =
76 __ATTR(freq, USER_RW, spk_var_show, spk_var_store);
77static struct kobj_attribute pitch_attribute =
78 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
79static struct kobj_attribute punct_attribute =
80 __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
81static struct kobj_attribute rate_attribute =
82 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
83static struct kobj_attribute tone_attribute =
84 __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
85static struct kobj_attribute voice_attribute =
86 __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
87static struct kobj_attribute vol_attribute =
88 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
89
90static struct kobj_attribute delay_time_attribute =
91 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
92static struct kobj_attribute direct_attribute =
93 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
94static struct kobj_attribute full_time_attribute =
95 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
96static struct kobj_attribute jiffy_delta_attribute =
97 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
98static struct kobj_attribute trigger_time_attribute =
99 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
100
101/*
102 * Create a group of attributes so that we can create and destroy them all
103 * at once.
104 */
105static struct attribute *synth_attrs[] = {
106 &caps_start_attribute.attr,
107 &caps_stop_attribute.attr,
108 &freq_attribute.attr,
109 &pitch_attribute.attr,
110 &punct_attribute.attr,
111 &rate_attribute.attr,
112 &tone_attribute.attr,
113 &voice_attribute.attr,
114 &vol_attribute.attr,
115 &delay_time_attribute.attr,
116 &direct_attribute.attr,
117 &full_time_attribute.attr,
118 &jiffy_delta_attribute.attr,
119 &trigger_time_attribute.attr,
120 NULL, /* need to NULL terminate the list of attributes */
121};
122
123static struct spk_synth synth_dtlk = {
124 .name = "dtlk",
125 .version = DRV_VERSION,
126 .long_name = "DoubleTalk PC",
127 .init = "\x01@\x01\x31y",
128 .procspeech = PROCSPEECH,
129 .clear = SYNTH_CLEAR,
130 .delay = 500,
131 .trigger = 30,
132 .jiffies = 50,
133 .full = 1000,
134 .startup = SYNTH_START,
135 .checkval = SYNTH_CHECK,
136 .vars = vars,
137 .probe = synth_probe,
138 .release = dtlk_release,
139 .synth_immediate = synth_immediate,
140 .catch_up = do_catch_up,
141 .flush = synth_flush,
142 .is_alive = spk_synth_is_alive_nop,
143 .synth_adjust = NULL,
144 .read_buff_add = NULL,
145 .get_index = spk_serial_in_nowait,
146 .indexing = {
147 .command = "\x01%di",
148 .lowindex = 1,
149 .highindex = 5,
150 .currindex = 1,
151 },
152 .attributes = {
153 .attrs = synth_attrs,
154 .name = "dtlk",
155 },
156};
157
158static void spk_out(const char ch)
159{
160 int timeout = SPK_XMITR_TIMEOUT;
161 while (synth_writable() == 0) {
162 if (!--timeout)
163 break;
164 udelay(1);
165 }
166 outb_p(ch, speakup_info.port_tts);
167 timeout = SPK_XMITR_TIMEOUT;
168 while (synth_writable() != 0) {
169 if (!--timeout)
170 break;
171 udelay(1);
172 }
173}
174
175static void do_catch_up(struct spk_synth *synth)
176{
177 u_char ch;
178 unsigned long flags;
179 unsigned long jiff_max;
180 struct var_t *jiffy_delta;
181 struct var_t *delay_time;
182 int jiffy_delta_val;
183 int delay_time_val;
184
185 jiffy_delta = get_var(JIFFY);
186 delay_time = get_var(DELAY);
187 spk_lock(flags);
188 jiffy_delta_val = jiffy_delta->u.n.value;
189 spk_unlock(flags);
190 jiff_max = jiffies + jiffy_delta_val;
191 while (!kthread_should_stop()) {
192 spk_lock(flags);
193 if (speakup_info.flushing) {
194 speakup_info.flushing = 0;
195 spk_unlock(flags);
196 synth->flush(synth);
197 continue;
198 }
199 if (synth_buffer_empty()) {
200 spk_unlock(flags);
201 break;
202 }
203 set_current_state(TASK_INTERRUPTIBLE);
204 delay_time_val = delay_time->u.n.value;
205 spk_unlock(flags);
206 if (synth_full()) {
207 schedule_timeout(msecs_to_jiffies(delay_time_val));
208 continue;
209 }
210 set_current_state(TASK_RUNNING);
211 spk_lock(flags);
212 ch = synth_buffer_getc();
213 spk_unlock(flags);
214 if (ch == '\n')
215 ch = PROCSPEECH;
216 spk_out(ch);
217 if ((jiffies >= jiff_max) && (ch == SPACE)) {
218 spk_out(PROCSPEECH);
219 spk_lock(flags);
220 delay_time_val = delay_time->u.n.value;
221 jiffy_delta_val = jiffy_delta->u.n.value;
222 spk_unlock(flags);
223 schedule_timeout(msecs_to_jiffies(delay_time_val));
224 jiff_max = jiffies + jiffy_delta_val;
225 }
226 }
227 spk_out(PROCSPEECH);
228}
229
230static const char *synth_immediate(struct spk_synth *synth, const char *buf)
231{
232 u_char ch;
233 while ((ch = (u_char)*buf)) {
234 if (synth_full())
235 return buf;
236 if (ch == '\n')
237 ch = PROCSPEECH;
238 spk_out(ch);
239 buf++;
240 }
241 return 0;
242}
243
244static void synth_flush(struct spk_synth *synth)
245{
246 outb_p(SYNTH_CLEAR, speakup_info.port_tts);
247 while (synth_writable() != 0)
248 cpu_relax();
249}
250
251static char synth_read_tts(void)
252{
253 u_char ch;
254 while (synth_readable() == 0)
255 cpu_relax();
256 ch = synth_status & 0x7f;
257 outb_p(ch, speakup_info.port_tts);
258 while (synth_readable() != 0)
259 cpu_relax();
260 return (char) ch;
261}
262
263/* interrogate the DoubleTalk PC and return its settings */
264static struct synth_settings *synth_interrogate(struct spk_synth *synth)
265{
266 u_char *t;
267 static char buf[sizeof(struct synth_settings) + 1];
268 int total, i;
269 static struct synth_settings status;
270 synth_immediate(synth, "\x18\x01?");
271 for (total = 0, i = 0; i < 50; i++) {
272 buf[total] = synth_read_tts();
273 if (total > 2 && buf[total] == 0x7f)
274 break;
275 if (total < sizeof(struct synth_settings))
276 total++;
277 }
278 t = buf;
279 /* serial number is little endian */
280 status.serial_number = t[0] + t[1]*256;
281 t += 2;
282 for (i = 0; *t != '\r'; t++) {
283 status.rom_version[i] = *t;
284 if (i < sizeof(status.rom_version)-1)
285 i++;
286 }
287 status.rom_version[i] = 0;
288 t++;
289 status.mode = *t++;
290 status.punc_level = *t++;
291 status.formant_freq = *t++;
292 status.pitch = *t++;
293 status.speed = *t++;
294 status.volume = *t++;
295 status.tone = *t++;
296 status.expression = *t++;
297 status.ext_dict_loaded = *t++;
298 status.ext_dict_status = *t++;
299 status.free_ram = *t++;
300 status.articulation = *t++;
301 status.reverb = *t++;
302 status.eob = *t++;
303 return &status;
304}
305
306static int synth_probe(struct spk_synth *synth)
307{
308 unsigned int port_val = 0;
309 int i = 0;
310 struct synth_settings *sp;
311 pr_info("Probing for DoubleTalk.\n");
312 if (port_forced) {
313 speakup_info.port_tts = port_forced;
314 pr_info("probe forced to %x by kernel command line\n",
315 speakup_info.port_tts);
316 if ((port_forced & 0xf) != 0xf)
317 pr_info("warning: port base should probably end with f\n");
318 if (synth_request_region(speakup_info.port_tts-1,
319 SYNTH_IO_EXTENT)) {
320 pr_warn("sorry, port already reserved\n");
321 return -EBUSY;
322 }
323 port_val = inw(speakup_info.port_tts-1);
324 synth_lpc = speakup_info.port_tts-1;
325 } else {
326 for (i = 0; synth_portlist[i]; i++) {
327 if (synth_request_region(synth_portlist[i],
328 SYNTH_IO_EXTENT))
329 continue;
330 port_val = inw(synth_portlist[i]) & 0xfbff;
331 if (port_val == 0x107f) {
332 synth_lpc = synth_portlist[i];
333 speakup_info.port_tts = synth_lpc+1;
334 break;
335 }
336 synth_release_region(synth_portlist[i],
337 SYNTH_IO_EXTENT);
338 }
339 }
340 port_val &= 0xfbff;
341 if (port_val != 0x107f) {
342 pr_info("DoubleTalk PC: not found\n");
343 synth_release_region(synth_lpc, SYNTH_IO_EXTENT);
344 return -ENODEV;
345 }
346 while (inw_p(synth_lpc) != 0x147f)
347 cpu_relax(); /* wait until it's ready */
348 sp = synth_interrogate(synth);
349 pr_info("%s: %03x-%03x, ROM ver %s, s/n %u, driver: %s\n",
350 synth->long_name, synth_lpc, synth_lpc+SYNTH_IO_EXTENT - 1,
351 sp->rom_version, sp->serial_number, synth->version);
352 synth->alive = 1;
353 return 0;
354}
355
356static void dtlk_release(void)
357{
358 if (speakup_info.port_tts)
359 synth_release_region(speakup_info.port_tts-1, SYNTH_IO_EXTENT);
360 speakup_info.port_tts = 0;
361}
362
363module_param_named(port, port_forced, int, S_IRUGO);
364module_param_named(start, synth_dtlk.startup, short, S_IRUGO);
365
366MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
367MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
368
369static int __init dtlk_init(void)
370{
371 return synth_add(&synth_dtlk);
372}
373
374static void __exit dtlk_exit(void)
375{
376 synth_remove(&synth_dtlk);
377}
378
379module_init(dtlk_init);
380module_exit(dtlk_exit);
381MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
382MODULE_AUTHOR("David Borowski");
383MODULE_DESCRIPTION("Speakup support for DoubleTalk PC synthesizers");
384MODULE_LICENSE("GPL");
385MODULE_VERSION(DRV_VERSION);
386
diff --git a/drivers/staging/speakup/speakup_dtlk.h b/drivers/staging/speakup/speakup_dtlk.h
new file mode 100644
index 00000000000..d951d18c579
--- /dev/null
+++ b/drivers/staging/speakup/speakup_dtlk.h
@@ -0,0 +1,54 @@
1/* speakup_dtlk.h - header file for speakups DoubleTalk driver. */
2
3#define SYNTH_IO_EXTENT 0x02
4#define SYNTH_CLEAR 0x18 /* stops speech */
5 /* TTS Port Status Flags */
6#define TTS_READABLE 0x80 /* mask for bit which is nonzero if a
7 byte can be read from the TTS port */
8#define TTS_SPEAKING 0x40 /* mask for SYNC bit, which is nonzero
9 while DoubleTalk is producing
10 output with TTS, PCM or CVSD
11 synthesizers or tone generators
12 (that is, all but LPC) */
13#define TTS_SPEAKING2 0x20 /* mask for SYNC2 bit,
14 which falls to zero up to 0.4 sec
15 before speech stops */
16#define TTS_WRITABLE 0x10 /* mask for RDY bit, which when set to
17 1, indicates the TTS port is ready
18 to accept a byte of data. The RDY
19 bit goes zero 2-3 usec after
20 writing, and goes 1 again 180-190
21 usec later. */
22#define TTS_ALMOST_FULL 0x08 /* mask for AF bit: When set to 1,
23 indicates that less than 300 bytes
24 are available in the TTS input
25 buffer. AF is always 0 in the PCM,
26 TGN and CVSD modes. */
27#define TTS_ALMOST_EMPTY 0x04 /* mask for AE bit: When set to 1,
28 indicates that less than 300 bytes
29 are remaining in DoubleTalk's input
30 (TTS or PCM) buffer. AE is always 1
31 in the TGN and CVSD modes. */
32
33 /* data returned by Interrogate command */
34struct synth_settings {
35 u_short serial_number; /* 0-7Fh:0-7Fh */
36 u_char rom_version[24]; /* null terminated string */
37 u_char mode; /* 0=Character; 1=Phoneme; 2=Text */
38 u_char punc_level; /* nB; 0-7 */
39 u_char formant_freq; /* nF; 0-9 */
40 u_char pitch; /* nP; 0-99 */
41 u_char speed; /* nS; 0-9 */
42 u_char volume; /* nV; 0-9 */
43 u_char tone; /* nX; 0-2 */
44 u_char expression; /* nE; 0-9 */
45 u_char ext_dict_loaded; /* 1=exception dictionary loaded */
46 u_char ext_dict_status; /* 1=exception dictionary enabled */
47 u_char free_ram; /* # pages (truncated) remaining for
48 * text buffer */
49 u_char articulation; /* nA; 0-9 */
50 u_char reverb; /* nR; 0-9 */
51 u_char eob; /* 7Fh value indicating end of
52 * parameter block */
53 u_char has_indexing; /* nonzero if indexing is implemented */
54};
diff --git a/drivers/staging/speakup/speakup_dummy.c b/drivers/staging/speakup/speakup_dummy.c
new file mode 100644
index 00000000000..6712a728faa
--- /dev/null
+++ b/drivers/staging/speakup/speakup_dummy.c
@@ -0,0 +1,148 @@
1/*
2 * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
3 * this version considerably modified by David Borowski, david575@rogers.com
4 * eventually modified by Samuel Thibault <samuel.thibault@ens-lyon.org>
5 *
6 * Copyright (C) 1998-99 Kirk Reiser.
7 * Copyright (C) 2003 David Borowski.
8 * Copyright (C) 2007 Samuel Thibault.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * specificly written as a driver for the speakup screenreview
25 * s not a general device driver.
26 */
27#include "spk_priv.h"
28#include "speakup.h"
29
30#define PROCSPEECH '\n'
31#define DRV_VERSION "2.11"
32#define SYNTH_CLEAR '!'
33
34static struct var_t vars[] = {
35 { CAPS_START, .u.s = {"CAPS_START\n" }},
36 { CAPS_STOP, .u.s = {"CAPS_STOP\n" }},
37 { RATE, .u.n = {"RATE %d\n", 8, 1, 16, 0, 0, NULL }},
38 { PITCH, .u.n = {"PITCH %d\n", 8, 0, 16, 0, 0, NULL }},
39 { VOL, .u.n = {"VOL %d\n", 8, 0, 16, 0, 0, NULL }},
40 { TONE, .u.n = {"TONE %d\n", 8, 0, 16, 0, 0, NULL }},
41 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
42 V_LAST_VAR
43};
44
45/*
46 * These attributes will appear in /sys/accessibility/speakup/dummy.
47 */
48static struct kobj_attribute caps_start_attribute =
49 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
50static struct kobj_attribute caps_stop_attribute =
51 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
52static struct kobj_attribute pitch_attribute =
53 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
54static struct kobj_attribute rate_attribute =
55 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
56static struct kobj_attribute tone_attribute =
57 __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
58static struct kobj_attribute vol_attribute =
59 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
60
61static struct kobj_attribute delay_time_attribute =
62 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
63static struct kobj_attribute direct_attribute =
64 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
65static struct kobj_attribute full_time_attribute =
66 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
67static struct kobj_attribute jiffy_delta_attribute =
68 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
69static struct kobj_attribute trigger_time_attribute =
70 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
71
72/*
73 * Create a group of attributes so that we can create and destroy them all
74 * at once.
75 */
76static struct attribute *synth_attrs[] = {
77 &caps_start_attribute.attr,
78 &caps_stop_attribute.attr,
79 &pitch_attribute.attr,
80 &rate_attribute.attr,
81 &tone_attribute.attr,
82 &vol_attribute.attr,
83 &delay_time_attribute.attr,
84 &direct_attribute.attr,
85 &full_time_attribute.attr,
86 &jiffy_delta_attribute.attr,
87 &trigger_time_attribute.attr,
88 NULL, /* need to NULL terminate the list of attributes */
89};
90
91static struct spk_synth synth_dummy = {
92 .name = "dummy",
93 .version = DRV_VERSION,
94 .long_name = "Dummy",
95 .init = "Speakup\n",
96 .procspeech = PROCSPEECH,
97 .clear = SYNTH_CLEAR,
98 .delay = 500,
99 .trigger = 50,
100 .jiffies = 50,
101 .full = 40000,
102 .startup = SYNTH_START,
103 .checkval = SYNTH_CHECK,
104 .vars = vars,
105 .probe = serial_synth_probe,
106 .release = spk_serial_release,
107 .synth_immediate = spk_synth_immediate,
108 .catch_up = spk_do_catch_up,
109 .flush = spk_synth_flush,
110 .is_alive = spk_synth_is_alive_restart,
111 .synth_adjust = NULL,
112 .read_buff_add = NULL,
113 .get_index = NULL,
114 .indexing = {
115 .command = NULL,
116 .lowindex = 0,
117 .highindex = 0,
118 .currindex = 0,
119 },
120 .attributes = {
121 .attrs = synth_attrs,
122 .name = "dummy",
123 },
124};
125
126module_param_named(ser, synth_dummy.ser, int, S_IRUGO);
127module_param_named(start, synth_dummy.startup, short, S_IRUGO);
128
129MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
130MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
131
132static int __init dummy_init(void)
133{
134 return synth_add(&synth_dummy);
135}
136
137static void __exit dummy_exit(void)
138{
139 synth_remove(&synth_dummy);
140}
141
142module_init(dummy_init);
143module_exit(dummy_exit);
144MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
145MODULE_DESCRIPTION("Speakup support for text console");
146MODULE_LICENSE("GPL");
147MODULE_VERSION(DRV_VERSION);
148
diff --git a/drivers/staging/speakup/speakup_keypc.c b/drivers/staging/speakup/speakup_keypc.c
new file mode 100644
index 00000000000..0f18ec01425
--- /dev/null
+++ b/drivers/staging/speakup/speakup_keypc.c
@@ -0,0 +1,327 @@
1/*
2 * written by David Borowski
3 *
4 * Copyright (C) 2003 David Borowski.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * specificly written as a driver for the speakup screenreview
21 * package it's not a general device driver.
22 * This driver is for the Keynote Gold internal synthesizer.
23 */
24#include <linux/jiffies.h>
25#include <linux/sched.h>
26#include <linux/timer.h>
27#include <linux/kthread.h>
28#include <linux/serial_reg.h>
29
30#include "spk_priv.h"
31#include "speakup.h"
32
33#define DRV_VERSION "2.10"
34#define SYNTH_IO_EXTENT 0x04
35#define SWAIT udelay(70)
36#define synth_writable() (inb_p(synth_port + UART_RX) & 0x10)
37#define synth_readable() (inb_p(synth_port + UART_RX) & 0x10)
38#define synth_full() ((inb_p(synth_port + UART_RX) & 0x80) == 0)
39#define PROCSPEECH 0x1f
40#define SYNTH_CLEAR 0x03
41
42static int synth_probe(struct spk_synth *synth);
43static void keynote_release(void);
44static const char *synth_immediate(struct spk_synth *synth, const char *buf);
45static void do_catch_up(struct spk_synth *synth);
46static void synth_flush(struct spk_synth *synth);
47
48static int synth_port;
49static int port_forced;
50static unsigned int synth_portlist[] = { 0x2a8, 0 };
51
52static struct var_t vars[] = {
53 { CAPS_START, .u.s = {"[f130]" }},
54 { CAPS_STOP, .u.s = {"[f90]" }},
55 { RATE, .u.n = {"\04%c ", 8, 0, 10, 81, -8, NULL }},
56 { PITCH, .u.n = {"[f%d]", 5, 0, 9, 40, 10, NULL }},
57 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
58 V_LAST_VAR
59};
60
61/*
62 * These attributes will appear in /sys/accessibility/speakup/keypc.
63 */
64static struct kobj_attribute caps_start_attribute =
65 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
66static struct kobj_attribute caps_stop_attribute =
67 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
68static struct kobj_attribute pitch_attribute =
69 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
70static struct kobj_attribute rate_attribute =
71 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
72
73static struct kobj_attribute delay_time_attribute =
74 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
75static struct kobj_attribute direct_attribute =
76 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
77static struct kobj_attribute full_time_attribute =
78 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
79static struct kobj_attribute jiffy_delta_attribute =
80 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
81static struct kobj_attribute trigger_time_attribute =
82 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
83
84/*
85 * Create a group of attributes so that we can create and destroy them all
86 * at once.
87 */
88static struct attribute *synth_attrs[] = {
89 &caps_start_attribute.attr,
90 &caps_stop_attribute.attr,
91 &pitch_attribute.attr,
92 &rate_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
101static struct spk_synth synth_keypc = {
102 .name = "keypc",
103 .version = DRV_VERSION,
104 .long_name = "Keynote PC",
105 .init = "[t][n7,1][n8,0]",
106 .procspeech = PROCSPEECH,
107 .clear = SYNTH_CLEAR,
108 .delay = 500,
109 .trigger = 50,
110 .jiffies = 50,
111 .full = 1000,
112 .startup = SYNTH_START,
113 .checkval = SYNTH_CHECK,
114 .vars = vars,
115 .probe = synth_probe,
116 .release = keynote_release,
117 .synth_immediate = synth_immediate,
118 .catch_up = do_catch_up,
119 .flush = synth_flush,
120 .is_alive = spk_synth_is_alive_nop,
121 .synth_adjust = NULL,
122 .read_buff_add = NULL,
123 .get_index = NULL,
124 .indexing = {
125 .command = NULL,
126 .lowindex = 0,
127 .highindex = 0,
128 .currindex = 0,
129 },
130 .attributes = {
131 .attrs = synth_attrs,
132 .name = "keypc",
133 },
134};
135
136static char *oops(void)
137{
138 int s1, s2, s3, s4;
139 s1 = inb_p(synth_port);
140 s2 = inb_p(synth_port+1);
141 s3 = inb_p(synth_port+2);
142 s4 = inb_p(synth_port+3);
143 pr_warn("synth timeout %d %d %d %d\n", s1, s2, s3, s4);
144 return NULL;
145}
146
147static const char *synth_immediate(struct spk_synth *synth, const char *buf)
148{
149 u_char ch;
150 int timeout;
151 while ((ch = *buf)) {
152 if (ch == '\n')
153 ch = PROCSPEECH;
154 if (synth_full())
155 return buf;
156 timeout = 1000;
157 while (synth_writable())
158 if (--timeout <= 0)
159 return oops();
160 outb_p(ch, synth_port);
161 udelay(70);
162 buf++;
163 }
164 return 0;
165}
166
167static void do_catch_up(struct spk_synth *synth)
168{
169 u_char ch;
170 int timeout;
171 unsigned long flags;
172 unsigned long jiff_max;
173 struct var_t *jiffy_delta;
174 struct var_t *delay_time;
175 struct var_t *full_time;
176 int delay_time_val;
177 int full_time_val;
178 int jiffy_delta_val;
179
180 jiffy_delta = get_var(JIFFY);
181 delay_time = get_var(DELAY);
182 full_time = get_var(FULL);
183spk_lock(flags);
184 jiffy_delta_val = jiffy_delta->u.n.value;
185 spk_unlock(flags);
186
187 jiff_max = jiffies + jiffy_delta_val;
188 while (!kthread_should_stop()) {
189 spk_lock(flags);
190 if (speakup_info.flushing) {
191 speakup_info.flushing = 0;
192 spk_unlock(flags);
193 synth->flush(synth);
194 continue;
195 }
196 if (synth_buffer_empty()) {
197 spk_unlock(flags);
198 break;
199 }
200 set_current_state(TASK_INTERRUPTIBLE);
201 full_time_val = full_time->u.n.value;
202 spk_unlock(flags);
203 if (synth_full()) {
204 schedule_timeout(msecs_to_jiffies(full_time_val));
205 continue;
206 }
207 set_current_state(TASK_RUNNING);
208 timeout = 1000;
209 while (synth_writable())
210 if (--timeout <= 0)
211 break;
212 if (timeout <= 0) {
213 oops();
214 break;
215 }
216 spk_lock(flags);
217 ch = synth_buffer_getc();
218 spk_unlock(flags);
219 if (ch == '\n')
220 ch = PROCSPEECH;
221 outb_p(ch, synth_port);
222 SWAIT;
223 if ((jiffies >= jiff_max) && (ch == SPACE)) {
224 timeout = 1000;
225 while (synth_writable())
226 if (--timeout <= 0)
227 break;
228 if (timeout <= 0) {
229 oops();
230 break;
231 }
232 outb_p(PROCSPEECH, synth_port);
233 spk_lock(flags);
234 jiffy_delta_val = jiffy_delta->u.n.value;
235 delay_time_val = delay_time->u.n.value;
236 spk_unlock(flags);
237 schedule_timeout(msecs_to_jiffies(delay_time_val));
238 jiff_max = jiffies+jiffy_delta_val;
239 }
240 }
241 timeout = 1000;
242 while (synth_writable())
243 if (--timeout <= 0)
244 break;
245 if (timeout <= 0)
246 oops();
247 else
248 outb_p(PROCSPEECH, synth_port);
249}
250
251static void synth_flush(struct spk_synth *synth)
252{
253 outb_p(SYNTH_CLEAR, synth_port);
254}
255
256static int synth_probe(struct spk_synth *synth)
257{
258 unsigned int port_val = 0;
259 int i = 0;
260 pr_info("Probing for %s.\n", synth->long_name);
261 if (port_forced) {
262 synth_port = port_forced;
263 pr_info("probe forced to %x by kernel command line\n",
264 synth_port);
265 if (synth_request_region(synth_port-1, SYNTH_IO_EXTENT)) {
266 pr_warn("sorry, port already reserved\n");
267 return -EBUSY;
268 }
269 port_val = inb(synth_port);
270 } else {
271 for (i = 0; synth_portlist[i]; i++) {
272 if (synth_request_region(synth_portlist[i],
273 SYNTH_IO_EXTENT)) {
274 pr_warn("request_region: failed with 0x%x, %d\n",
275 synth_portlist[i], SYNTH_IO_EXTENT);
276 continue;
277 }
278 port_val = inb(synth_portlist[i]);
279 if (port_val == 0x80) {
280 synth_port = synth_portlist[i];
281 break;
282 }
283 }
284 }
285 if (port_val != 0x80) {
286 pr_info("%s: not found\n", synth->long_name);
287 synth_release_region(synth_port, SYNTH_IO_EXTENT);
288 synth_port = 0;
289 return -ENODEV;
290 }
291 pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name,
292 synth_port, synth_port+SYNTH_IO_EXTENT-1,
293 synth->version);
294 synth->alive = 1;
295 return 0;
296}
297
298static void keynote_release(void)
299{
300 if (synth_port)
301 synth_release_region(synth_port, SYNTH_IO_EXTENT);
302 synth_port = 0;
303}
304
305module_param_named(port, port_forced, int, S_IRUGO);
306module_param_named(start, synth_keypc.startup, short, S_IRUGO);
307
308MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
309MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
310
311static int __init keypc_init(void)
312{
313 return synth_add(&synth_keypc);
314}
315
316static void __exit keypc_exit(void)
317{
318 synth_remove(&synth_keypc);
319}
320
321module_init(keypc_init);
322module_exit(keypc_exit);
323MODULE_AUTHOR("David Borowski");
324MODULE_DESCRIPTION("Speakup support for Keynote Gold PC synthesizers");
325MODULE_LICENSE("GPL");
326MODULE_VERSION(DRV_VERSION);
327
diff --git a/drivers/staging/speakup/speakup_ltlk.c b/drivers/staging/speakup/speakup_ltlk.c
new file mode 100644
index 00000000000..d8569591c5a
--- /dev/null
+++ b/drivers/staging/speakup/speakup_ltlk.c
@@ -0,0 +1,195 @@
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 "speakup.h"
26#include "spk_priv.h"
27#include "serialio.h"
28#include "speakup_dtlk.h" /* local header file for LiteTalk values */
29
30#define DRV_VERSION "2.11"
31#define synth_full( ) ( !( inb( synth_port_tts + UART_MSR ) & UART_MSR_CTS ) )
32#define PROCSPEECH 0x0d
33
34static int synth_probe(struct spk_synth *synth);
35
36static struct var_t vars[] = {
37 { CAPS_START, .u.s = {"\x01+35p" }},
38 { CAPS_STOP, .u.s = {"\x01-35p" }},
39 { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL }},
40 { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL }},
41 { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL }},
42 { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL }},
43 { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL }},
44 { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL }},
45 { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL }},
46 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
47 V_LAST_VAR
48};
49
50/*
51 * These attributes will appear in /sys/accessibility/speakup/ltlk.
52 */
53static struct kobj_attribute caps_start_attribute =
54 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
55static struct kobj_attribute caps_stop_attribute =
56 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
57static struct kobj_attribute freq_attribute =
58 __ATTR(freq, USER_RW, spk_var_show, spk_var_store);
59static struct kobj_attribute pitch_attribute =
60 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
61static struct kobj_attribute punct_attribute =
62 __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
63static struct kobj_attribute rate_attribute =
64 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
65static struct kobj_attribute tone_attribute =
66 __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
67static struct kobj_attribute voice_attribute =
68 __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
69static struct kobj_attribute vol_attribute =
70 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
71
72static struct kobj_attribute delay_time_attribute =
73 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
74static struct kobj_attribute direct_attribute =
75 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
76static struct kobj_attribute full_time_attribute =
77 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
78static struct kobj_attribute jiffy_delta_attribute =
79 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
80static struct kobj_attribute trigger_time_attribute =
81 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
82
83/*
84 * Create a group of attributes so that we can create and destroy them all
85 * at once.
86 */
87static struct attribute *synth_attrs[] = {
88 &caps_start_attribute.attr,
89 &caps_stop_attribute.attr,
90 &freq_attribute.attr,
91 &pitch_attribute.attr,
92 &punct_attribute.attr,
93 &rate_attribute.attr,
94 &tone_attribute.attr,
95 &voice_attribute.attr,
96 &vol_attribute.attr,
97 &delay_time_attribute.attr,
98 &direct_attribute.attr,
99 &full_time_attribute.attr,
100 &jiffy_delta_attribute.attr,
101 &trigger_time_attribute.attr,
102 NULL, /* need to NULL terminate the list of attributes */
103};
104
105static struct spk_synth synth_ltlk = {
106 .name = "ltlk",
107 .version = DRV_VERSION,
108 .long_name = "LiteTalk",
109 .init = "\01@\x01\x31y\n\0",
110 .procspeech = PROCSPEECH,
111 .clear = SYNTH_CLEAR,
112 .delay = 500,
113 .trigger = 50,
114 .jiffies = 50,
115 .full = 40000,
116 .startup = SYNTH_START,
117 .checkval = SYNTH_CHECK,
118 .vars = vars,
119 .probe = synth_probe,
120 .release = spk_serial_release,
121 .synth_immediate = spk_synth_immediate,
122 .catch_up = spk_do_catch_up,
123 .flush = spk_synth_flush,
124 .is_alive = spk_synth_is_alive_restart,
125 .synth_adjust = NULL,
126 .read_buff_add = NULL,
127 .get_index = spk_serial_in_nowait,
128 .indexing = {
129 .command = "\x01%di",
130 .lowindex = 1,
131 .highindex = 5,
132 .currindex = 1,
133 },
134 .attributes = {
135 .attrs = synth_attrs,
136 .name = "ltlk",
137 },
138};
139
140/* interrogate the LiteTalk and print its settings */
141static void synth_interrogate(struct spk_synth *synth)
142{
143 unsigned char *t, i;
144 unsigned char buf[50], rom_v[20];
145 spk_synth_immediate(synth, "\x18\x01?");
146 for (i = 0; i < 50; i++) {
147 buf[i] = spk_serial_in();
148 if (i > 2 && buf[i] == 0x7f)
149 break;
150 }
151 t = buf+2;
152 for (i = 0; *t != '\r'; t++) {
153 rom_v[i] = *t;
154 if (++i >= 19)
155 break;
156 }
157 rom_v[i] = 0;
158 pr_info("%s: ROM version: %s\n", synth->long_name, rom_v);
159}
160
161static int synth_probe(struct spk_synth *synth)
162{
163 int failed = 0;
164
165 failed = serial_synth_probe(synth);
166 if (failed == 0)
167 synth_interrogate(synth);
168 synth->alive = !failed;
169 return failed;
170}
171
172module_param_named(ser, synth_ltlk.ser, int, S_IRUGO);
173module_param_named(start, synth_ltlk.startup, short, S_IRUGO);
174
175MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
176MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
177
178static int __init ltlk_init(void)
179{
180 return synth_add(&synth_ltlk);
181}
182
183static void __exit ltlk_exit(void)
184{
185 synth_remove(&synth_ltlk);
186}
187
188module_init(ltlk_init);
189module_exit(ltlk_exit);
190MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
191MODULE_AUTHOR("David Borowski");
192MODULE_DESCRIPTION("Speakup support for DoubleTalk LT/LiteTalk synthesizers");
193MODULE_LICENSE("GPL");
194MODULE_VERSION(DRV_VERSION);
195
diff --git a/drivers/staging/speakup/speakup_soft.c b/drivers/staging/speakup/speakup_soft.c
new file mode 100644
index 00000000000..2c85773fdbf
--- /dev/null
+++ b/drivers/staging/speakup/speakup_soft.c
@@ -0,0 +1,366 @@
1/* speakup_soft.c - speakup driver to register and make available
2 * a user space device for software synthesizers. written by: Kirk
3 * Reiser <kirk@braille.uwo.ca>
4 *
5 * Copyright (C) 2003 Kirk Reiser.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * this code is specificly written as a driver for the speakup screenreview
22 * package and is not a general device driver. */
23
24#include <linux/unistd.h>
25#include <linux/miscdevice.h> /* for misc_register, and SYNTH_MINOR */
26#include <linux/poll.h> /* for poll_wait() */
27#include <linux/sched.h> /* schedule(), signal_pending(), TASK_INTERRUPTIBLE */
28
29#include "spk_priv.h"
30#include "speakup.h"
31
32#define DRV_VERSION "2.6"
33#define SOFTSYNTH_MINOR 26 /* might as well give it one more than /dev/synth */
34#define PROCSPEECH 0x0d
35#define CLEAR_SYNTH 0x18
36
37static int softsynth_probe(struct spk_synth *synth);
38static void softsynth_release(void);
39static int softsynth_is_alive(struct spk_synth *synth);
40static unsigned char get_index(void);
41
42static struct miscdevice synth_device;
43static int initialized = 0;
44static int misc_registered;
45
46static struct var_t vars[] = {
47 { CAPS_START, .u.s = {"\x01+3p" }},
48 { CAPS_STOP, .u.s = {"\x01-3p" }},
49 { RATE, .u.n = {"\x01%ds", 5, 0, 9, 0, 0, NULL }},
50 { PITCH, .u.n = {"\x01%dp", 5, 0, 9, 0, 0, NULL }},
51 { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL }},
52 { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL }},
53 { PUNCT, .u.n = {"\x01%db", 0, 0, 2, 0, 0, NULL }},
54 { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL }},
55 { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL }},
56 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
57 V_LAST_VAR
58};
59
60/*
61 * These attributes will appear in /sys/accessibility/speakup/soft.
62 */
63static struct kobj_attribute caps_start_attribute =
64 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
65static struct kobj_attribute caps_stop_attribute =
66 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
67static struct kobj_attribute freq_attribute =
68 __ATTR(freq, USER_RW, spk_var_show, spk_var_store);
69//static struct kobj_attribute lang_attribute =
70// __ATTR(lang, USER_RW, spk_var_show, spk_var_store);
71static struct kobj_attribute pitch_attribute =
72 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
73static struct kobj_attribute punct_attribute =
74 __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
75static struct kobj_attribute rate_attribute =
76 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
77static struct kobj_attribute tone_attribute =
78 __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
79static struct kobj_attribute voice_attribute =
80 __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
81static struct kobj_attribute vol_attribute =
82 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
83
84static struct kobj_attribute delay_time_attribute =
85 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
86static struct kobj_attribute direct_attribute =
87 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
88static struct kobj_attribute full_time_attribute =
89 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
90static struct kobj_attribute jiffy_delta_attribute =
91 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
92static struct kobj_attribute trigger_time_attribute =
93 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
94
95/*
96 * Create a group of attributes so that we can create and destroy them all
97 * at once.
98 */
99static struct attribute *synth_attrs[] = {
100 &caps_start_attribute.attr,
101 &caps_stop_attribute.attr,
102 &freq_attribute.attr,
103// &lang_attribute.attr,
104 &pitch_attribute.attr,
105 &punct_attribute.attr,
106 &rate_attribute.attr,
107 &tone_attribute.attr,
108 &voice_attribute.attr,
109 &vol_attribute.attr,
110 &delay_time_attribute.attr,
111 &direct_attribute.attr,
112 &full_time_attribute.attr,
113 &jiffy_delta_attribute.attr,
114 &trigger_time_attribute.attr,
115 NULL, /* need to NULL terminate the list of attributes */
116};
117
118static struct spk_synth synth_soft = {
119 .name = "soft",
120 .version = DRV_VERSION,
121 .long_name = "software synth",
122 .init = "\01@\x01\x31y\n",
123 .procspeech = PROCSPEECH,
124 .delay = 0,
125 .trigger = 0,
126 .jiffies = 0,
127 .full = 0,
128 .startup = SYNTH_START,
129 .checkval = SYNTH_CHECK,
130 .vars = vars,
131 .probe = softsynth_probe,
132 .release = softsynth_release,
133 .synth_immediate = NULL,
134 .catch_up = NULL,
135 .flush = NULL,
136 .is_alive = softsynth_is_alive,
137 .synth_adjust = NULL,
138 .read_buff_add = NULL,
139 .get_index = get_index,
140 .indexing = {
141 .command = "\x01%di",
142 .lowindex = 1,
143 .highindex = 5,
144 .currindex = 1,
145 },
146 .attributes = {
147 .attrs = synth_attrs,
148 .name = "soft",
149 },
150};
151
152static char *get_initstring(void)
153{
154 static char buf[40];
155 char *cp;
156 struct var_t *var;
157
158 memset(buf, 0, sizeof(buf));
159 cp = buf;
160 var = synth_soft.vars;
161 while (var->var_id != MAXVARS) {
162 if (var->var_id != CAPS_START && var->var_id != CAPS_STOP
163 && var->var_id != DIRECT)
164 cp = cp + sprintf(cp, var->u.n.synth_fmt, var->u.n.value);
165 var++;
166 }
167 cp = cp + sprintf(cp, "\n");
168 return buf;
169}
170
171static int softsynth_open(struct inode *inode, struct file *fp)
172{
173 unsigned long flags;
174 /*if ((fp->f_flags & O_ACCMODE) != O_RDONLY) */
175 /* return -EPERM; */
176 spk_lock(flags);
177 if (synth_soft.alive) {
178 spk_unlock(flags);
179 return -EBUSY;
180 }
181 synth_soft.alive = 1;
182 spk_unlock(flags);
183 return 0;
184}
185
186static int softsynth_close(struct inode *inode, struct file *fp)
187{
188 unsigned long flags;
189 spk_lock(flags);
190 synth_soft.alive = 0;
191 initialized = 0;
192 spk_unlock(flags);
193 /* Make sure we let applications go before leaving */
194 speakup_start_ttys();
195 return 0;
196}
197
198static ssize_t softsynth_read(struct file *fp, char *buf, size_t count,
199 loff_t *pos)
200{
201 int chars_sent = 0;
202 char *cp;
203 char *init;
204 char ch;
205 int empty;
206 unsigned long flags;
207 DEFINE_WAIT(wait);
208
209 spk_lock(flags);
210 while (1) {
211 prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE);
212 if (!synth_buffer_empty() || speakup_info.flushing)
213 break;
214 spk_unlock(flags);
215 if (fp->f_flags & O_NONBLOCK) {
216 finish_wait(&speakup_event, &wait);
217 return -EAGAIN;
218 }
219 if (signal_pending(current)) {
220 finish_wait(&speakup_event, &wait);
221 return -ERESTARTSYS;
222 }
223 schedule();
224 spk_lock(flags);
225 }
226 finish_wait(&speakup_event, &wait);
227
228 cp = buf;
229 init = get_initstring();
230 while (chars_sent < count) {
231 if (speakup_info.flushing) {
232 speakup_info.flushing = 0;
233 ch = '\x18';
234 } else if (synth_buffer_empty()) {
235 break;
236 } else if (! initialized) {
237 if (*init) {
238 ch = *init;
239 init++;
240 } else {
241 initialized = 1;
242 }
243 } else {
244 ch = synth_buffer_getc();
245 }
246 spk_unlock(flags);
247 if (copy_to_user(cp, &ch, 1))
248 return -EFAULT;
249 spk_lock(flags);
250 chars_sent++;
251 cp++;
252 }
253 *pos += chars_sent;
254 empty = synth_buffer_empty();
255 spk_unlock(flags);
256 if (empty) {
257 speakup_start_ttys();
258 *pos = 0;
259 }
260 return chars_sent;
261}
262
263static int last_index = 0;
264
265static ssize_t softsynth_write(struct file *fp, const char *buf, size_t count,
266 loff_t *pos)
267{
268 char indbuf[5];
269 if (count >= sizeof(indbuf))
270 return -EINVAL;
271
272 if (copy_from_user(indbuf, buf, count))
273 return -EFAULT;
274 indbuf[4] = 0;
275
276 last_index = simple_strtoul(indbuf, NULL, 0);
277 return count;
278}
279
280static unsigned int softsynth_poll(struct file *fp,
281 struct poll_table_struct *wait)
282{
283 unsigned long flags;
284 int ret = 0;
285 poll_wait(fp, &speakup_event, wait);
286
287 spk_lock(flags);
288 if (! synth_buffer_empty() || speakup_info.flushing)
289 ret = POLLIN | POLLRDNORM;
290 spk_unlock(flags);
291 return ret;
292}
293
294static unsigned char get_index(void)
295{
296 int rv;
297 rv = last_index;
298 last_index = 0;
299 return rv;
300}
301
302static struct file_operations softsynth_fops = {
303 .owner = THIS_MODULE,
304 .poll = softsynth_poll,
305 .read = softsynth_read,
306 .write = softsynth_write,
307 .open = softsynth_open,
308 .release = softsynth_close,
309};
310
311
312static int softsynth_probe(struct spk_synth *synth)
313{
314
315 if (misc_registered != 0)
316 return 0;
317 memset(&synth_device, 0, sizeof(synth_device));
318 synth_device.minor = SOFTSYNTH_MINOR;
319 synth_device.name = "softsynth";
320 synth_device.fops = &softsynth_fops;
321 if (misc_register(&synth_device)) {
322 pr_warn("Couldn't initialize miscdevice /dev/softsynth.\n");
323 return -ENODEV;
324 }
325
326 misc_registered = 1;
327 pr_info("initialized device: /dev/softsynth, node (MAJOR 10, MINOR 26)\n");
328 return 0;
329}
330
331static void softsynth_release(void)
332{
333 misc_deregister(&synth_device);
334 misc_registered = 0;
335 pr_info("unregistered /dev/softsynth\n");
336}
337
338static int softsynth_is_alive(struct spk_synth *synth)
339{
340 if (synth_soft.alive)
341 return 1;
342 return 0;
343}
344
345module_param_named(start, synth_soft.startup, short, S_IRUGO);
346
347MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
348
349
350static int __init soft_init(void)
351{
352 return synth_add(&synth_soft);
353}
354
355static void __exit soft_exit(void)
356{
357 synth_remove(&synth_soft);
358}
359
360module_init(soft_init);
361module_exit(soft_exit);
362MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
363MODULE_DESCRIPTION("Speakup userspace software synthesizer support");
364MODULE_LICENSE("GPL");
365MODULE_VERSION(DRV_VERSION);
366
diff --git a/drivers/staging/speakup/speakup_spkout.c b/drivers/staging/speakup/speakup_spkout.c
new file mode 100644
index 00000000000..32fd8d76152
--- /dev/null
+++ b/drivers/staging/speakup/speakup_spkout.c
@@ -0,0 +1,165 @@
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 "spk_priv.h"
26#include "speakup.h"
27#include "serialio.h"
28
29#define DRV_VERSION "2.11"
30#define SYNTH_CLEAR 0x18
31#define PROCSPEECH '\r'
32
33static void synth_flush(struct spk_synth *synth);
34
35static struct var_t vars[] = {
36 { CAPS_START, .u.s = {"\x05P+" }},
37 { CAPS_STOP, .u.s = {"\x05P-" }},
38 { RATE, .u.n = {"\x05R%d", 7, 0, 9, 0, 0, NULL }},
39 { PITCH, .u.n = {"\x05P%d", 3, 0, 9, 0, 0, NULL }},
40 { VOL, .u.n = {"\x05V%d", 9, 0, 9, 0, 0, NULL }},
41 { TONE, .u.n = {"\x05T%c", 8, 0, 25, 65, 0, NULL }},
42 { PUNCT, .u.n = {"\x05M%c", 0, 0, 3, 0, 0, "nsma" }},
43 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
44 V_LAST_VAR
45};
46
47/*
48 * These attributes will appear in /sys/accessibility/speakup/spkout.
49 */
50static struct kobj_attribute caps_start_attribute =
51 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
52static struct kobj_attribute caps_stop_attribute =
53 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
54static struct kobj_attribute pitch_attribute =
55 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
56static struct kobj_attribute punct_attribute =
57 __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
58static struct kobj_attribute rate_attribute =
59 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
60static struct kobj_attribute tone_attribute =
61 __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
62static struct kobj_attribute vol_attribute =
63 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
64
65static struct kobj_attribute delay_time_attribute =
66 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
67static struct kobj_attribute direct_attribute =
68 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
69static struct kobj_attribute full_time_attribute =
70 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
71static struct kobj_attribute jiffy_delta_attribute =
72 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
73static struct kobj_attribute trigger_time_attribute =
74 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
75
76/*
77 * Create a group of attributes so that we can create and destroy them all
78 * at once.
79 */
80static struct attribute *synth_attrs[] = {
81 &caps_start_attribute.attr,
82 &caps_stop_attribute.attr,
83 &pitch_attribute.attr,
84 &punct_attribute.attr,
85 &rate_attribute.attr,
86 &tone_attribute.attr,
87 &vol_attribute.attr,
88 &delay_time_attribute.attr,
89 &direct_attribute.attr,
90 &full_time_attribute.attr,
91 &jiffy_delta_attribute.attr,
92 &trigger_time_attribute.attr,
93 NULL, /* need to NULL terminate the list of attributes */
94};
95
96static struct spk_synth synth_spkout = {
97 .name = "spkout",
98 .version = DRV_VERSION,
99 .long_name = "Speakout",
100 .init = "\005W1\005I2\005C3",
101 .procspeech = PROCSPEECH,
102 .clear = SYNTH_CLEAR,
103 .delay = 500,
104 .trigger = 50,
105 .jiffies = 50,
106 .full = 40000,
107 .startup = SYNTH_START,
108 .checkval = SYNTH_CHECK,
109 .vars = vars,
110 .probe = serial_synth_probe,
111 .release = spk_serial_release,
112 .synth_immediate = spk_synth_immediate,
113 .catch_up = spk_do_catch_up,
114 .flush = synth_flush,
115 .is_alive = spk_synth_is_alive_restart,
116 .synth_adjust = NULL,
117 .read_buff_add = NULL,
118 .get_index = spk_serial_in_nowait,
119 .indexing = {
120 .command = "\x05[%c",
121 .lowindex = 1,
122 .highindex = 5,
123 .currindex = 1,
124 },
125 .attributes = {
126 .attrs = synth_attrs,
127 .name = "spkout",
128 },
129};
130
131static void synth_flush(struct spk_synth *synth)
132{
133 int timeout = SPK_XMITR_TIMEOUT;
134 while (spk_serial_tx_busy()) {
135 if (!--timeout)
136 break;
137 udelay(1);
138 }
139 outb(SYNTH_CLEAR, speakup_info.port_tts);
140}
141
142module_param_named(ser, synth_spkout.ser, int, S_IRUGO);
143module_param_named(start, synth_spkout.startup, short, S_IRUGO);
144
145MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
146MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
147
148static int __init spkout_init(void)
149{
150 return synth_add(&synth_spkout);
151}
152
153static void __exit spkout_exit(void)
154{
155 synth_remove(&synth_spkout);
156}
157
158module_init(spkout_init);
159module_exit(spkout_exit);
160MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
161MODULE_AUTHOR("David Borowski");
162MODULE_DESCRIPTION("Speakup support for Speak Out synthesizers");
163MODULE_LICENSE("GPL");
164MODULE_VERSION(DRV_VERSION);
165
diff --git a/drivers/staging/speakup/speakup_txprt.c b/drivers/staging/speakup/speakup_txprt.c
new file mode 100644
index 00000000000..9ffeeac0dbc
--- /dev/null
+++ b/drivers/staging/speakup/speakup_txprt.c
@@ -0,0 +1,147 @@
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 "spk_priv.h"
26#include "speakup.h"
27
28#define DRV_VERSION "2.11"
29#define SYNTH_CLEAR 0x18
30#define PROCSPEECH '\r' /* process speech char */
31
32static struct var_t vars[] = {
33 { CAPS_START, .u.s = {"\x05P8" }},
34 { CAPS_STOP, .u.s = {"\x05P5" }},
35 { RATE, .u.n = {"\x05R%d", 5, 0, 9, 0, 0, NULL }},
36 { PITCH, .u.n = {"\x05P%d", 5, 0, 9, 0, 0, NULL }},
37 { VOL, .u.n = {"\x05V%d", 5, 0, 9, 0, 0, NULL }},
38 { TONE, .u.n = {"\x05T%c", 12, 0, 25, 61, 0, NULL }},
39 { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }},
40 V_LAST_VAR
41 };
42
43/*
44 * These attributes will appear in /sys/accessibility/speakup/txprt.
45 */
46static struct kobj_attribute caps_start_attribute =
47 __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
48static struct kobj_attribute caps_stop_attribute =
49 __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
50static struct kobj_attribute pitch_attribute =
51 __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
52static struct kobj_attribute rate_attribute =
53 __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
54static struct kobj_attribute tone_attribute =
55 __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
56static struct kobj_attribute vol_attribute =
57 __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
58
59static struct kobj_attribute delay_time_attribute =
60 __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
61static struct kobj_attribute direct_attribute =
62 __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
63static struct kobj_attribute full_time_attribute =
64 __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
65static struct kobj_attribute jiffy_delta_attribute =
66 __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
67static struct kobj_attribute trigger_time_attribute =
68 __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
69
70/*
71 * Create a group of attributes so that we can create and destroy them all
72 * at once.
73 */
74static struct attribute *synth_attrs[] = {
75 &caps_start_attribute.attr,
76 &caps_stop_attribute.attr,
77 &pitch_attribute.attr,
78 &rate_attribute.attr,
79 &tone_attribute.attr,
80 &vol_attribute.attr,
81 &delay_time_attribute.attr,
82 &direct_attribute.attr,
83 &full_time_attribute.attr,
84 &jiffy_delta_attribute.attr,
85 &trigger_time_attribute.attr,
86 NULL, /* need to NULL terminate the list of attributes */
87};
88
89static struct spk_synth synth_txprt = {
90 .name = "txprt",
91 .version = DRV_VERSION,
92 .long_name = "Transport",
93 .init = "\x05N1",
94 .procspeech = PROCSPEECH,
95 .clear = SYNTH_CLEAR,
96 .delay = 500,
97 .trigger = 50,
98 .jiffies = 50,
99 .full = 40000,
100 .startup = SYNTH_START,
101 .checkval = SYNTH_CHECK,
102 .vars = vars,
103 .probe = serial_synth_probe,
104 .release = spk_serial_release,
105 .synth_immediate = spk_synth_immediate,
106 .catch_up = spk_do_catch_up,
107 .flush = spk_synth_flush,
108 .is_alive = spk_synth_is_alive_restart,
109 .synth_adjust = NULL,
110 .read_buff_add = NULL,
111 .get_index = NULL,
112 .indexing = {
113 .command = NULL,
114 .lowindex = 0,
115 .highindex = 0,
116 .currindex = 0,
117 },
118 .attributes = {
119 .attrs = synth_attrs,
120 .name = "txprt",
121 },
122};
123
124module_param_named(ser, synth_txprt.ser, int, S_IRUGO);
125module_param_named(start, synth_txprt.startup, short, S_IRUGO);
126
127MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
128MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
129
130static int __init txprt_init(void)
131{
132 return synth_add(&synth_txprt);
133}
134
135static void __exit txprt_exit(void)
136{
137 synth_remove(&synth_txprt);
138}
139
140module_init(txprt_init);
141module_exit(txprt_exit);
142MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
143MODULE_AUTHOR("David Borowski");
144MODULE_DESCRIPTION("Speakup support for Transport synthesizers");
145MODULE_LICENSE("GPL");
146MODULE_VERSION(DRV_VERSION);
147
diff --git a/drivers/staging/speakup/speakupmap.h b/drivers/staging/speakup/speakupmap.h
new file mode 100644
index 00000000000..f1c0dd3b2c3
--- /dev/null
+++ b/drivers/staging/speakup/speakupmap.h
@@ -0,0 +1,65 @@
1 119, 62, 6,
2 0, 16, 20, 17, 32, 48, 0,
3 2, 0, 78, 0, 0, 0, 0,
4 3, 0, 79, 0, 0, 0, 0,
5 4, 0, 76, 0, 0, 0, 0,
6 5, 0, 77, 0, 0, 0, 0,
7 6, 0, 74, 0, 0, 0, 0,
8 7, 0, 75, 0, 0, 0, 0,
9 9, 0, 5, 46, 0, 0, 0,
10 10, 0, 4, 0, 0, 0, 0,
11 11, 0, 0, 1, 0, 0, 0,
12 12, 0, 27, 0, 33, 0, 0,
13 19, 0, 47, 0, 0, 0, 0,
14 21, 0, 29, 17, 0, 0, 0,
15 22, 0, 15, 0, 0, 0, 0,
16 23, 0, 14, 0, 0, 0, 28,
17 24, 0, 16, 0, 0, 0, 0,
18 25, 0, 30, 18, 0, 0, 0,
19 28, 0, 3, 26, 0, 0, 0,
20 35, 0, 31, 0, 0, 0, 0,
21 36, 0, 12, 0, 0, 0, 0,
22 37, 0, 11, 0, 0, 0, 22,
23 38, 0, 13, 0, 0, 0, 0,
24 39, 0, 32, 7, 0, 0, 0,
25 40, 0, 23, 0, 0, 0, 0,
26 44, 0, 44, 0, 0, 0, 0,
27 49, 0, 24, 0, 0, 0, 0,
28 50, 0, 9, 19, 6, 0, 0,
29 51, 0, 8, 0, 0, 0, 36,
30 52, 0, 10, 20, 0, 0, 0,
31 53, 0, 25, 0, 0, 0, 0,
32 55, 46, 1, 0, 0, 0, 0,
33 58, 128, 128, 0, 0, 0, 0,
34 59, 0, 45, 0, 0, 0, 0,
35 60, 0, 40, 0, 0, 0, 0,
36 61, 0, 41, 0, 0, 0, 0,
37 62, 0, 42, 0, 0, 0, 0,
38 63, 0, 34, 0, 0, 0, 0,
39 64, 0, 35, 0, 0, 0, 0,
40 65, 0, 37, 0, 0, 0, 0,
41 66, 0, 38, 0, 0, 0, 0,
42 67, 0, 66, 0, 39, 0, 0,
43 68, 0, 67, 0, 0, 0, 0,
44 71, 15, 19, 0, 0, 0, 0,
45 72, 14, 29, 0, 0, 28, 0,
46 73, 16, 17, 0, 0, 0, 0,
47 74, 27, 33, 0, 0, 0, 0,
48 75, 12, 31, 0, 0, 0, 0,
49 76, 11, 21, 0, 0, 22, 0,
50 77, 13, 32, 0, 0, 0, 0,
51 78, 23, 43, 0, 0, 0, 0,
52 79, 9, 20, 0, 0, 0, 0,
53 80, 8, 30, 0, 0, 36, 0,
54 81, 10, 18, 0, 0, 0, 0,
55 82, 128, 128, 0, 0, 0, 0,
56 83, 24, 25, 0, 0, 0, 0,
57 87, 0, 68, 0, 0, 0, 0,
58 88, 0, 69, 0, 0, 0, 0,
59 96, 3, 26, 0, 0, 0, 0,
60 98, 4, 5, 0, 0, 0, 0,
61 99, 2, 0, 0, 0, 0, 0,
62 104, 0, 6, 0, 0, 0, 0,
63 109, 0, 7, 0, 0, 0, 0,
64 125, 128, 128, 0, 0, 0, 0,
65 0, 119
diff --git a/drivers/staging/speakup/speakupmap.map b/drivers/staging/speakup/speakupmap.map
new file mode 100644
index 00000000000..f10d44cf5d7
--- /dev/null
+++ b/drivers/staging/speakup/speakupmap.map
@@ -0,0 +1,93 @@
1spk key_f9 = punc_level_dec
2spk key_f10 = punc_level_inc
3spk key_f11 = reading_punc_dec
4spk key_f12 = reading_punc_inc
5spk key_1 = vol_dec
6spk key_2 = vol_inc
7spk key_3 = pitch_dec
8spk key_4 = pitch_inc
9spk key_5 = rate_dec
10spk key_6 = rate_inc
11key_kpasterisk = toggle_cursoring
12ctrl spk key_8 = toggle_cursoring
13spk key_kpasterisk = speakup_goto
14spk key_f1 = speakup_help
15spk key_f2 = set_win
16spk key_f3 = clear_win
17spk key_f4 = enable_win
18spk key_f5 = edit_some
19spk key_f6 = edit_most
20spk key_f7 = edit_delim
21spk key_f8 = edit_repeat
22shift spk key_f9 = edit_exnum
23 key_kp7 = say_prev_line
24spk key_kp7 = left_edge
25 key_kp8 = say_line
26double key_kp8 = say_line_indent
27spk key_kp8 = say_from_top
28 key_kp9 = say_next_line
29spk key_kp9 = top_edge
30 key_kpminus = speakup_parked
31spk key_kpminus = say_char_num
32 key_kp4 = say_prev_word
33spk key_kp4 = say_from_left
34 key_kp5 = say_word
35double key_kp5 = spell_word
36spk key_kp5 = spell_phonetic
37 key_kp6 = say_next_word
38spk key_kp6 = say_to_right
39 key_kpplus = say_screen
40spk key_kpplus = say_win
41 key_kp1 = say_prev_char
42spk key_kp1 = right_edge
43 key_kp2 = say_char
44spk key_kp2 = say_to_bottom
45double key_kp2 = say_phonetic_char
46 key_kp3 = say_next_char
47spk key_kp3 = bottom_edge
48 key_kp0 = spk_key
49 key_kpdot = say_position
50spk key_kpdot = say_attributes
51key_kpenter = speakup_quiet
52spk key_kpenter = speakup_off
53key_sysrq = speech_kill
54 key_kpslash = speakup_cut
55spk key_kpslash = speakup_paste
56spk key_pageup = say_first_char
57spk key_pagedown = say_last_char
58key_capslock = spk_key
59 spk key_z = spk_lock
60key_leftmeta = spk_key
61ctrl spk key_0 = speakup_goto
62spk key_u = say_prev_line
63spk key_i = say_line
64double spk key_i = say_line_indent
65spk key_o = say_next_line
66spk key_minus = speakup_parked
67shift spk key_minus = say_char_num
68spk key_j = say_prev_word
69spk key_k = say_word
70double spk key_k = spell_word
71spk key_l = say_next_word
72spk key_m = say_prev_char
73spk key_comma = say_char
74double spk key_comma = say_phonetic_char
75spk key_dot = say_next_char
76spk key_n = say_position
77 ctrl spk key_m = left_edge
78 ctrl spk key_y = top_edge
79 ctrl spk key_dot = right_edge
80ctrl spk key_p = bottom_edge
81spk key_apostrophe = say_screen
82spk key_h = say_from_left
83spk key_y = say_from_top
84spk key_semicolon = say_to_right
85spk key_p = say_to_bottom
86spk key_slash = say_attributes
87 spk key_enter = speakup_quiet
88 ctrl spk key_enter = speakup_off
89 spk key_9 = speakup_cut
90spk key_8 = speakup_paste
91shift spk key_m = say_first_char
92 ctrl spk key_semicolon = say_last_char
93spk key_r = read_all_doc
diff --git a/drivers/staging/speakup/spk_priv.h b/drivers/staging/speakup/spk_priv.h
new file mode 100644
index 00000000000..16ace4af68a
--- /dev/null
+++ b/drivers/staging/speakup/spk_priv.h
@@ -0,0 +1,93 @@
1/* spk_priv.h
2 review functions for the speakup screen review package.
3 originally written by: Kirk Reiser and Andy Berdan.
4
5 extensively modified by David Borowski.
6
7 Copyright (C) 1998 Kirk Reiser.
8 Copyright (C) 2003 David Borowski.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23*/
24#ifndef _SPEAKUP_PRIVATE_H
25#define _SPEAKUP_PRIVATE_H
26
27#include "spk_types.h"
28#include "spk_priv_keyinfo.h"
29
30#ifndef pr_warn
31#define pr_warn(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
32#endif
33
34#define V_LAST_VAR { MAXVARS }
35#define SPACE 0x20
36#define SYNTH_CHECK 20030716 /* today's date ought to do for check value */
37/* synth flags, for odd synths */
38#define SF_DEC 1 /* to fiddle puncs in alpha strings so it doesn't spell */
39#ifdef MODULE
40#define SYNTH_START 1
41#else
42#define SYNTH_START 0
43#endif
44
45#define KT_SPKUP 15
46
47extern struct serial_state *spk_serial_init(int index);
48extern void stop_serial_interrupt(void);
49extern int wait_for_xmitr(void);
50extern unsigned char spk_serial_in(void);
51extern unsigned char spk_serial_in_nowait(void);
52extern int spk_serial_out(const char ch);
53extern void spk_serial_release(void);
54
55extern char synth_buffer_getc(void);
56extern char synth_buffer_peek(void);
57extern int synth_buffer_empty(void);
58extern struct var_t *get_var(enum var_id_t var_id);
59extern ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
60 char *buf);
61extern ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
62 const char *buf, size_t count);
63
64extern int serial_synth_probe(struct spk_synth *synth);
65extern const char *spk_synth_immediate(struct spk_synth *synth, const char *buff);
66extern void spk_do_catch_up(struct spk_synth *synth);
67extern void spk_synth_flush(struct spk_synth *synth);
68extern int spk_synth_is_alive_nop(struct spk_synth *synth);
69extern int spk_synth_is_alive_restart(struct spk_synth *synth);
70extern void synth_printf(const char *buf, ...);
71extern int synth_request_region(u_long, u_long);
72extern int synth_release_region(u_long, u_long);
73extern int synth_add(struct spk_synth *in_synth);
74extern void synth_remove(struct spk_synth *in_synth);
75
76extern struct speakup_info_t speakup_info;
77
78extern struct var_t synth_time_vars[];
79
80/* Protect the whole speakup machinery, must be taken at each kernel->speakup
81 * transition and released at all corresponding speakup->kernel transitions
82 * (flags must be the same variable between lock/trylock and unlock).
83 *
84 * The progression thread only interferes with the speakup machinery through
85 * the synth buffer, and so only needs to take the lock while tinkering with
86 * it.
87 */
88/* Speakup needs to disable the keyboard IRQ, hence _irqsave/restore */
89#define spk_lock(flags) spin_lock_irqsave(&speakup_info.spinlock, flags)
90#define spk_trylock(flags) spin_trylock_irqsave(&speakup_info.spinlock, flags)
91#define spk_unlock(flags) spin_unlock_irqrestore(&speakup_info.spinlock, flags)
92
93#endif
diff --git a/drivers/staging/speakup/spk_priv_keyinfo.h b/drivers/staging/speakup/spk_priv_keyinfo.h
new file mode 100644
index 00000000000..3fd4b82f84a
--- /dev/null
+++ b/drivers/staging/speakup/spk_priv_keyinfo.h
@@ -0,0 +1,110 @@
1/* spk_priv.h
2 review functions for the speakup screen review package.
3 originally written by: Kirk Reiser and Andy Berdan.
4
5 extensively modified by David Borowski.
6
7 Copyright (C) 1998 Kirk Reiser.
8 Copyright (C) 2003 David Borowski.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23*/
24
25#ifndef _SPEAKUP_KEYINFO_H
26#define _SPEAKUP_KEYINFO_H
27
28#define FIRST_SYNTH_VAR RATE
29/* 0 is reserved for no remap */
30#define SPEAKUP_GOTO 0x01
31#define SPEECH_KILL 0x02
32#define SPEAKUP_QUIET 0x03
33#define SPEAKUP_CUT 0x04
34#define SPEAKUP_PASTE 0x05
35#define SAY_FIRST_CHAR 0x06
36#define SAY_LAST_CHAR 0x07
37#define SAY_CHAR 0x08
38#define SAY_PREV_CHAR 0x09
39#define SAY_NEXT_CHAR 0x0a
40#define SAY_WORD 0x0b
41#define SAY_PREV_WORD 0x0c
42#define SAY_NEXT_WORD 0x0d
43#define SAY_LINE 0x0e
44#define SAY_PREV_LINE 0x0f
45#define SAY_NEXT_LINE 0x10
46#define TOP_EDGE 0x11
47#define BOTTOM_EDGE 0x12
48#define LEFT_EDGE 0x13
49#define RIGHT_EDGE 0x14
50#define SPELL_PHONETIC 0x15
51#define SPELL_WORD 0x16
52#define SAY_SCREEN 0x17
53#define SAY_POSITION 0x18
54#define SAY_ATTRIBUTES 0x19
55#define SPEAKUP_OFF 0x1a
56#define SPEAKUP_PARKED 0x1b
57#define SAY_LINE_INDENT 0x1c
58#define SAY_FROM_TOP 0x1d
59#define SAY_TO_BOTTOM 0x1e
60#define SAY_FROM_LEFT 0x1f
61#define SAY_TO_RIGHT 0x20
62#define SAY_CHAR_NUM 0x21
63#define EDIT_SOME 0x22
64#define EDIT_MOST 0x23
65#define SAY_PHONETIC_CHAR 0x24
66#define EDIT_DELIM 0x25
67#define EDIT_REPEAT 0x26
68#define EDIT_EXNUM 0x27
69#define SET_WIN 0x28
70#define CLEAR_WIN 0x29
71#define ENABLE_WIN 0x2a
72#define SAY_WIN 0x2b
73#define SPK_LOCK 0x2c
74#define SPEAKUP_HELP 0x2d
75#define TOGGLE_CURSORING 0x2e
76#define READ_ALL_DOC 0x2f
77#define SPKUP_MAX_FUNC 0x30 /* one greater than the last func handler */
78
79#define SPK_KEY 0x80
80#define FIRST_EDIT_BITS 0x22
81
82#define FIRST_SET_VAR SPELL_DELAY
83#define VAR_START 0x40 /* increase if adding more than 0x3f functions */
84
85/* keys for setting variables, must be ordered same as the enum for var_ids */
86/* with dec being even and inc being 1 greater */
87#define SPELL_DELAY_DEC VAR_START+0
88#define SPELL_DELAY_INC SPELL_DELAY_DEC+1
89#define PUNC_LEVEL_DEC SPELL_DELAY_DEC+2
90#define PUNC_LEVEL_INC PUNC_LEVEL_DEC+1
91#define READING_PUNC_DEC PUNC_LEVEL_DEC+2
92#define READING_PUNC_INC READING_PUNC_DEC+1
93#define ATTRIB_BLEEP_DEC READING_PUNC_DEC+2
94#define ATTRIB_BLEEP_INC ATTRIB_BLEEP_DEC+1
95#define BLEEPS_DEC ATTRIB_BLEEP_DEC+2
96#define BLEEPS_INC BLEEPS_DEC+1
97#define RATE_DEC BLEEPS_DEC+2
98#define RATE_INC RATE_DEC+1
99#define PITCH_DEC RATE_DEC+2
100#define PITCH_INC PITCH_DEC+1
101#define VOL_DEC PITCH_DEC+2
102#define VOL_INC VOL_DEC+1
103#define TONE_DEC VOL_DEC+2
104#define TONE_INC TONE_DEC+1
105#define PUNCT_DEC TONE_DEC+2
106#define PUNCT_INC PUNCT_DEC+1
107#define VOICE_DEC PUNCT_DEC+2
108#define VOICE_INC VOICE_DEC+1
109
110#endif
diff --git a/drivers/staging/speakup/spk_types.h b/drivers/staging/speakup/spk_types.h
new file mode 100644
index 00000000000..840bddb6410
--- /dev/null
+++ b/drivers/staging/speakup/spk_types.h
@@ -0,0 +1,193 @@
1#ifndef SPEAKUP_TYPES_H
2#define SPEAKUP_TYPES_H
3
4/*
5 * This file includes all of the typedefs and structs used in speakup.
6 */
7
8#include <linux/types.h>
9#include <linux/fs.h>
10#include <linux/errno.h>
11#include <linux/delay.h>
12#include <linux/wait.h> /* for wait_queue */
13#include <linux/init.h> /* for __init */
14#include <linux/module.h>
15#include <linux/vt_kern.h>
16#include <linux/spinlock.h>
17#include <linux/mutex.h>
18#include <linux/io.h> /* for inb_p, outb_p, inb, outb, etc... */
19
20enum var_type_t {
21 VAR_NUM = 0,
22 VAR_TIME,
23 VAR_STRING,
24 VAR_PROC
25};
26
27enum {
28 E_DEFAULT = 0,
29 E_SET,
30 E_INC,
31 E_DEC,
32 E_NEW_DEFAULT,
33};
34
35enum var_id_t {
36 VERSION = 0, SYNTH, SILENT, SYNTH_DIRECT,
37 KEYMAP, CHARS,
38 PUNC_SOME, PUNC_MOST, PUNC_ALL,
39 DELIM, REPEATS, EXNUMBER,
40 DELAY, TRIGGER, JIFFY, FULL, /* all timers must be together */
41 BLEEP_TIME, CURSOR_TIME, BELL_POS,
42SAY_CONTROL, SAY_WORD_CTL, NO_INTERRUPT, KEY_ECHO,
43 SPELL_DELAY, PUNC_LEVEL, READING_PUNC,
44 ATTRIB_BLEEP, BLEEPS,
45 RATE, PITCH, VOL, TONE, PUNCT, VOICE, FREQUENCY, LANG, DIRECT,
46 CAPS_START, CAPS_STOP, CHARTAB,
47 MAXVARS
48};
49
50typedef int (*special_func)(struct vc_data *vc, u_char type, u_char ch,
51 u_short key);
52
53#define COLOR_BUFFER_SIZE 160
54
55struct spk_highlight_color_track{
56 /* Count of each background color */
57 unsigned int bgcount[8];
58 /* Buffer for characters drawn with each background color */
59 char highbuf[8][COLOR_BUFFER_SIZE];
60 /* Current index into highbuf */
61 unsigned int highsize[8];
62 /* Reading Position for each color */
63 u_long rpos[8], rx[8], ry[8];
64 /* Real Cursor Y Position */
65 ulong cy;
66};
67
68struct st_spk_t {
69 u_long reading_x, cursor_x;
70 u_long reading_y, cursor_y;
71 u_long reading_pos, cursor_pos;
72 u_long go_x, go_pos;
73 u_long w_top, w_bottom, w_left, w_right;
74 u_char w_start, w_enabled;
75 u_char reading_attr, old_attr;
76 char parked, shut_up;
77 struct spk_highlight_color_track ht;
78 int tty_stopped;
79};
80
81/* now some defines to make these easier to use. */
82#define spk_shut_up speakup_console[vc->vc_num]->shut_up
83#define spk_killed (speakup_console[vc->vc_num]->shut_up & 0x40)
84#define spk_x speakup_console[vc->vc_num]->reading_x
85#define spk_cx speakup_console[vc->vc_num]->cursor_x
86#define spk_y speakup_console[vc->vc_num]->reading_y
87#define spk_cy speakup_console[vc->vc_num]->cursor_y
88#define spk_pos (speakup_console[vc->vc_num]->reading_pos)
89#define spk_cp speakup_console[vc->vc_num]->cursor_pos
90#define goto_pos (speakup_console[vc->vc_num]->go_pos)
91#define goto_x (speakup_console[vc->vc_num]->go_x)
92#define win_top (speakup_console[vc->vc_num]->w_top)
93#define win_bottom (speakup_console[vc->vc_num]->w_bottom)
94#define win_left (speakup_console[vc->vc_num]->w_left)
95#define win_right (speakup_console[vc->vc_num]->w_right)
96#define win_start (speakup_console[vc->vc_num]->w_start)
97#define win_enabled (speakup_console[vc->vc_num]->w_enabled)
98#define spk_attr speakup_console[vc->vc_num]->reading_attr
99#define spk_old_attr speakup_console[vc->vc_num]->old_attr
100#define spk_parked speakup_console[vc->vc_num]->parked
101
102struct st_var_header {
103 char *name;
104 enum var_id_t var_id;
105 enum var_type_t var_type;
106 void *p_val; /* ptr to programs variable to store value */
107 void *data; /* ptr to the vars data */
108};
109
110struct num_var_t {
111 char *synth_fmt;
112 int default_val;
113 int low;
114 int high;
115 short offset, multiplier; /* for fiddling rates etc. */
116 char *out_str; /* if synth needs char representation of number */
117 int value; /* current value */
118};
119
120struct punc_var_t {
121 enum var_id_t var_id;
122 short value;
123};
124
125struct string_var_t {
126 char *default_val;
127};
128
129struct var_t {
130 enum var_id_t var_id;
131 union {
132 struct num_var_t n;
133 struct string_var_t s;
134 } u;
135};
136
137struct st_bits_data { /* punc, repeats, word delim bits */
138 char *name;
139 char *value;
140 short mask;
141};
142
143struct synth_indexing {
144 char *command;
145 unsigned char lowindex;
146 unsigned char highindex;
147 unsigned char currindex;
148};
149
150struct spk_synth {
151 const char *name;
152 const char *version;
153 const char *long_name;
154 const char *init;
155 char procspeech;
156 char clear;
157 int delay;
158 int trigger;
159 int jiffies;
160 int full;
161 int ser;
162 short flags;
163 short startup;
164 const int checkval; /* for validating a proper synth module */
165 struct var_t *vars;
166 int *default_pitch;
167 int *default_vol;
168 int (*probe)(struct spk_synth *synth);
169 void (*release)(void);
170 const char *(*synth_immediate)(struct spk_synth *synth, const char *buff);
171 void (*catch_up)(struct spk_synth *synth);
172 void (*flush)(struct spk_synth *synth);
173 int (*is_alive)(struct spk_synth *synth);
174 int (*synth_adjust)(struct st_var_header *var);
175 void (*read_buff_add)(u_char);
176 unsigned char (*get_index)(void);
177 struct synth_indexing indexing;
178 int alive;
179 struct attribute_group attributes;
180};
181
182struct speakup_info_t {
183 spinlock_t spinlock;
184 int port_tts;
185 int flushing;
186};
187
188struct bleep {
189 short freq;
190 unsigned long jiffies;
191 int active;
192};
193#endif
diff --git a/drivers/staging/speakup/spkguide.txt b/drivers/staging/speakup/spkguide.txt
new file mode 100644
index 00000000000..24362eb7b8f
--- /dev/null
+++ b/drivers/staging/speakup/spkguide.txt
@@ -0,0 +1,1575 @@
1
2The Speakup User's Guide
3For Speakup 3.1.2 and Later
4By Gene Collins
5Updated by others
6Last modified on Mon Sep 27 14:26:31 2010
7Document version 1.3
8
9Copyright (c) 2005 Gene Collins
10Copyright (c) 2008 Samuel Thibault
11Copyright (c) 2009, 2010 the Speakup Team
12
13Permission is granted to copy, distribute and/or modify this document
14under the terms of the GNU Free Documentation License, Version 1.2 or
15any later version published by the Free Software Foundation; with no
16Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
17copy of the license is included in the section entitled "GNU Free
18Documentation License".
19
20Preface
21
22The purpose of this document is to familiarize users with the user
23interface to Speakup, a Linux Screen Reader. If you need instructions
24for installing or obtaining Speakup, visit the web site at
25http://linux-speakup.org/. Speakup is a set of patches to the standard
26Linux kernel source tree. It can be built as a series of modules, or as
27a part of a monolithic kernel. These details are beyond the scope of
28this manual, but the user may need to be aware of the module
29capabilities, depending on how your system administrator has installed
30Speakup. If Speakup is built as a part of a monolithic kernel, and the
31user is using a hardware synthesizer, then Speakup will be able to
32provide speech access from the time the kernel is loaded, until the time
33the system is shutdown. This means that if you have obtained Linux
34installation media for a distribution which includes Speakup as a part
35of its kernel, you will be able, as a blind person, to install Linux
36with speech access unaided by a sighted person. Again, these details
37are beyond the scope of this manual, but the user should be aware of
38them. See the web site mentioned above for further details.
39
401. Starting Speakup
41
42If your system administrator has installed Speakup to work with your
43specific synthesizer by default, then all you need to do to use Speakup
44is to boot your system, and Speakup should come up talking. This
45assumes of course that your synthesizer is a supported hardware
46synthesizer, and that it is either installed in or connected to your
47system, and is if necessary powered on.
48
49It is possible, however, that Speakup may have been compiled into the
50kernel with no default synthesizer. It is even possible that your
51kernel has been compiled with support for some of the supported
52synthesizers and not others. If you find that this is the case, and
53your synthesizer is supported but not available, complain to the person
54who compiled and installed your kernel. Or better yet, go to the web
55site, and learn how to patch Speakup into your own kernel source, and
56build and install your own kernel.
57
58If your kernel has been compiled with Speakup, and has no default
59synthesizer set, or you would like to use a different synthesizer than
60the default one, then you may issue the following command at the boot
61prompt of your boot loader.
62
63linux speakup.synth=ltlk
64
65This command would tell Speakup to look for and use a LiteTalk or
66DoubleTalk LT at boot up. You may replace the ltlk synthesizer keyword
67with the keyword for whatever synthesizer you wish to use. The
68speakup.synth parameter will accept the following keywords, provided
69that support for the related synthesizers has been built into the
70kernel.
71
72acntsa -- Accent SA
73acntpc -- Accent PC
74apollo -- Apollo
75audptr -- Audapter
76bns -- Braille 'n Speak
77dectlk -- DecTalk Express (old and new, db9 serial only)
78decext -- DecTalk (old) External
79dtlk -- DoubleTalk PC
80keypc -- Keynote Gold PC
81ltlk -- DoubleTalk LT, LiteTalk, or external Tripletalk (db9 serial only)
82spkout -- Speak Out
83txprt -- Transport
84dummy -- Plain text terminal
85
86Note: Speakup does * NOT * support usb connections! Speakup also does *
87NOT * support the internal Tripletalk!
88
89Speakup does support two other synthesizers, but because they work in
90conjunction with other software, they must be loaded as modules after
91their related software is loaded, and so are not available at boot up.
92These are as follows:
93
94decpc -- DecTalk PC (not available at boot up)
95soft -- One of several software synthesizers (not available at boot up)
96
97See the sections on loading modules and software synthesizers later in
98this manual for further details. It should be noted here that the
99speakup.synth boot parameter will have no effect if Speakup has been
100compiled as modules. In order for Speakup modules to be loaded during
101the boot process, such action must be configured by your system
102administrator. This will mean that you will hear some, but not all, of
103the bootup messages.
104
1052. Basic operation
106
107Once you have booted the system, and if necessary, have supplied the
108proper bootup parameter for your synthesizer, Speakup will begin
109talking as soon as the kernel is loaded. In fact, it will talk a lot!
110It will speak all the boot up messages that the kernel prints on the
111screen during the boot process. This is because Speakup is not a
112separate screen reader, but is actually built into the operating
113system. Since almost all console applications must print text on the
114screen using the kernel, and must get their keyboard input through the
115kernel, they are automatically handled properly by Speakup. There are a
116few exceptions, but we'll come to those later.
117
118Note: In this guide I will refer to the numeric keypad as the keypad.
119This is done because the speakupmap.map file referred to later in this
120manual uses the term keypad instead of numeric keypad. Also I'm lazy
121and would rather only type one word. So keypad it is. Got it? Good.
122
123Most of the Speakup review keys are located on the keypad at the far
124right of the keyboard. The numlock key should be off, in order for these
125to work. If you toggle the numlock on, the keypad will produce numbers,
126which is exactly what you want for spreadsheets and such. For the
127purposes of this guide, you should have the numlock turned off, which is
128its default state at bootup.
129
130You probably won't want to listen to all the bootup messages every time
131you start your system, though it's a good idea to listen to them at
132least once, just so you'll know what kind of information is available to
133you during the boot process. You can always review these messages after
134bootup with the command:
135
136dmesg | more
137
138In order to speed the boot process, and to silence the speaking of the
139bootup messages, just press the keypad enter key. This key is located
140in the bottom right corner of the keypad. Speakup will shut up and stay
141that way, until you press another key.
142
143You can check to see if the boot process has completed by pressing the 8
144key on the keypad, which reads the current line. This also has the
145effect of starting Speakup talking again, so you can press keypad enter
146to silence it again if the boot process has not completed.
147
148When the boot process is complete, you will arrive at a "login" prompt.
149At this point, you'll need to type in your user id and password, as
150provided by your system administrator. You will hear Speakup speak the
151letters of your user id as you type it, but not the password. This is
152because the password is not displayed on the screen for security
153reasons. This has nothing to do with Speakup, it's a Linux security
154feature.
155
156Once you've logged in, you can run any Linux command or program which is
157allowed by your user id. Normal users will not be able to run programs
158which require root privileges.
159
160When you are running a program or command, Speakup will automatically
161speak new text as it arrives on the screen. You can at any time silence
162the speech with keypad enter, or use any of the Speakup review keys.
163
164Here are some basic Speakup review keys, and a short description of what
165they do.
166
167keypad 1 -- read previous character
168keypad 2 -- read current character (pressing keypad 2 twice rapidly will speak
169 the current character phonetically)
170keypad 3 -- read next character
171keypad 4 -- read previous word
172keypad 5 -- read current word (press twice rapidly to spell the current word)
173keypad 6 -- read next word
174keypad 7 -- read previous line
175keypad 8 -- read current line (press twice rapidly to hear how much the
176 text on the current line is indented)
177keypad 9 -- read next line
178keypad period -- speak current cursor position and announce current
179 virtual console
180
181It's also worth noting that the insert key on the keypad is mapped
182as the speakup key. Instead of pressing and releasing this key, as you
183do under DOS or Windows, you hold it like a shift key, and press other
184keys in combination with it. For example, repeatedly holding keypad
185insert, from now on called speakup, and keypad enter will toggle the
186speaking of new text on the screen on and off. This is not the same as
187just pressing keypad enter by itself, which just silences the speech
188until you hit another key. When you hit speakup plus keypad enter,
189Speakup will say, "You turned me off.", or "Hey, that's better." When
190Speakup is turned off, no new text on the screen will be spoken. You
191can still use the reading controls to review the screen however.
192
1933. Using the Speakup Help System
194
195In order to enter the Speakup help system, press and hold the speakup
196key (remember that this is the keypad insert key), and press the f1 key.
197You will hear the message:
198
199"Press space to leave help, cursor up or down to scroll, or a letter to
200go to commands in list."
201
202When you press the spacebar to leave the help system, you will hear:
203
204"Leaving help."
205
206While you are in the Speakup help system, you can scroll up or down
207through the list of available commands using the cursor keys. The list
208of commands is arranged in alphabetical order. If you wish to jump to
209commands in a specific part of the alphabet, you may press the letter of
210the alphabet you wish to jump to.
211
212You can also just explore by typing keyboard keys. Pressing keys will
213cause Speakup to speak the command associated with that key. For
214example, if you press the keypad 8 key, you will hear:
215
216"Keypad 8 is line, say current."
217
218You'll notice that some commands do not have keys assigned to them.
219This is because they are very infrequently used commands, and are also
220accessible through the sys system. We'll discuss the sys system later
221in this manual.
222
223You'll also notice that some commands have two keys assigned to them.
224This is because Speakup has a built in set of alternative key bindings
225for laptop users. The alternate speakup key is the caps lock key. You
226can press and hold the caps lock key, while pressing an alternate
227speakup command key to activate the command. On most laptops, the
228numeric keypad is defined as the keys in the j k l area of the keyboard.
229
230There is usually a function key which turns this keypad function on and
231off, and some other key which controls the numlock state. Toggling the
232keypad functionality on and off can become a royal pain. So, Speakup
233gives you a simple way to get at an alternative set of key mappings for
234your laptop. These are also available by default on desktop systems,
235because Speakup does not know whether it is running on a desktop or
236laptop. So you may choose which set of Speakup keys to use. Some
237system administrators may have chosen to compile Speakup for a desktop
238system without this set of alternate key bindings, but these details are
239beyond the scope of this manual. To use the caps lock for its normal
240purpose, hold the shift key while toggling the caps lock on and off. We
241should note here, that holding the caps lock key and pressing the z key
242will toggle the alternate j k l keypad on and off.
243
2444. Keys and Their Assigned Commands
245
246In this section, we'll go through a list of all the speakup keys and
247commands. You can also get a list of commands and assigned keys from
248the help system.
249
250The following list was taken from the speakupmap.map file. Key
251assignments are on the left of the equal sign, and the associated
252Speakup commands are on the right. The designation "spk" means to press
253and hold the speakup key, a.k.a. keypad insert, a.k.a. caps lock, while
254pressing the other specified key.
255
256spk key_f9 = punc_level_dec
257spk key_f10 = punc_level_inc
258spk key_f11 = reading_punc_dec
259spk key_f12 = reading_punc_inc
260spk key_1 = vol_dec
261spk key_2 = vol_inc
262spk key_3 = pitch_dec
263spk key_4 = pitch_inc
264spk key_5 = rate_dec
265spk key_6 = rate_inc
266key_kpasterisk = toggle_cursoring
267spk key_kpasterisk = speakup_goto
268spk key_f1 = speakup_help
269spk key_f2 = set_win
270spk key_f3 = clear_win
271spk key_f4 = enable_win
272spk key_f5 = edit_some
273spk key_f6 = edit_most
274spk key_f7 = edit_delim
275spk key_f8 = edit_repeat
276shift spk key_f9 = edit_exnum
277 key_kp7 = say_prev_line
278spk key_kp7 = left_edge
279 key_kp8 = say_line
280double key_kp8 = say_line_indent
281spk key_kp8 = say_from_top
282 key_kp9 = say_next_line
283spk key_kp9 = top_edge
284 key_kpminus = speakup_parked
285spk key_kpminus = say_char_num
286 key_kp4 = say_prev_word
287spk key_kp4 = say_from_left
288 key_kp5 = say_word
289double key_kp5 = spell_word
290spk key_kp5 = spell_phonetic
291 key_kp6 = say_next_word
292spk key_kp6 = say_to_right
293 key_kpplus = say_screen
294spk key_kpplus = say_win
295 key_kp1 = say_prev_char
296spk key_kp1 = right_edge
297 key_kp2 = say_char
298spk key_kp2 = say_to_bottom
299double key_kp2 = say_phonetic_char
300 key_kp3 = say_next_char
301spk key_kp3 = bottom_edge
302 key_kp0 = spk_key
303 key_kpdot = say_position
304spk key_kpdot = say_attributes
305key_kpenter = speakup_quiet
306spk key_kpenter = speakup_off
307key_sysrq = speech_kill
308 key_kpslash = speakup_cut
309spk key_kpslash = speakup_paste
310spk key_pageup = say_first_char
311spk key_pagedown = say_last_char
312key_capslock = spk_key
313 spk key_z = spk_lock
314key_leftmeta = spk_key
315ctrl spk key_0 = speakup_goto
316spk key_u = say_prev_line
317spk key_i = say_line
318double spk key_i = say_line_indent
319spk key_o = say_next_line
320spk key_minus = speakup_parked
321shift spk key_minus = say_char_num
322spk key_j = say_prev_word
323spk key_k = say_word
324double spk key_k = spell_word
325spk key_l = say_next_word
326spk key_m = say_prev_char
327spk key_comma = say_char
328double spk key_comma = say_phonetic_char
329spk key_dot = say_next_char
330spk key_n = say_position
331 ctrl spk key_m = left_edge
332 ctrl spk key_y = top_edge
333 ctrl spk key_dot = right_edge
334ctrl spk key_p = bottom_edge
335spk key_apostrophe = say_screen
336spk key_h = say_from_left
337spk key_y = say_from_top
338spk key_semicolon = say_to_right
339spk key_p = say_to_bottom
340spk key_slash = say_attributes
341 spk key_enter = speakup_quiet
342 ctrl spk key_enter = speakup_off
343 spk key_9 = speakup_cut
344spk key_8 = speakup_paste
345shift spk key_m = say_first_char
346 ctrl spk key_semicolon = say_last_char
347
3485. The Speakup Sys System
349
350The Speakup screen reader also creates a speakup subdirectory as a part
351of the sys system.
352
353As a convenience, run as root
354
355ln -s /sys/accessibility/speakup /speakup
356
357to directly access speakup parameters from /speakup.
358You can see these entries by typing the command:
359
360ls -1 /speakup/*
361
362If you issue the above ls command, you will get back something like
363this:
364
365/speakup/attrib_bleep
366/speakup/bell_pos
367/speakup/bleep_time
368/speakup/bleeps
369/speakup/cursor_time
370/speakup/delimiters
371/speakup/ex_num
372/speakup/key_echo
373/speakup/keymap
374/speakup/no_interrupt
375/speakup/punc_all
376/speakup/punc_level
377/speakup/punc_most
378/speakup/punc_some
379/speakup/reading_punc
380/speakup/repeats
381/speakup/say_control
382/speakup/say_word_ctl
383/speakup/silent
384/speakup/spell_delay
385/speakup/synth
386/speakup/synth_direct
387/speakup/version
388
389/speakup/i18n:
390announcements
391characters
392chartab
393colors
394ctl_keys
395formatted
396function_names
397key_names
398states
399
400/speakup/soft:
401caps_start
402caps_stop
403delay_time
404direct
405freq
406full_time
407jiffy_delta
408pitch
409punct
410rate
411tone
412trigger_time
413voice
414vol
415
416Notice the two subdirectories of /speakup: /speakup/i18n and
417/speakup/soft.
418The i18n subdirectory is described in a later section.
419The files under /speakup/soft represent settings that are specific to the
420driver for the software synthesizer. If you use the LiteTalk, your
421synthesizer-specific settings would be found in /speakup/ltlk. In other words,
422a subdirectory named /speakup/KWD is created to hold parameters specific
423to the device whose keyword is KWD.
424These parameters include volume, rate, pitch, and others.
425
426In addition to using the Speakup hot keys to change such things as
427volume, pitch, and rate, you can also echo values to the appropriate
428entry in the /speakup directory. This is very useful, since it
429lets you control Speakup parameters from within a script. How you
430would write such scripts is somewhat beyond the scope of this manual,
431but I will include a couple of simple examples here to give you a
432general idea of what such scripts can do.
433
434Suppose for example, that you wanted to control both the punctuation
435level and the reading punctuation level at the same time. For
436simplicity, we'll call them punc0, punc1, punc2, and punc3. The scripts
437might look something like this:
438
439#!/bin/bash
440# punc0
441# set punc and reading punc levels to 0
442echo 0 >/speakup/punc_level
443echo 0 >/speakup/reading_punc
444echo Punctuation level set to 0.
445
446#!/bin/bash
447# punc1
448# set punc and reading punc levels to 1
449echo 1 >/speakup/punc_level
450echo 1 >/speakup/reading_punc
451echo Punctuation level set to 1.
452
453#!/bin/bash
454# punc2
455# set punc and reading punc levels to 2
456echo 2 >/speakup/punc_level
457echo 2 >/speakup/reading_punc
458echo Punctuation level set to 2.
459
460#!/bin/bash
461# punc3
462# set punc and reading punc levels to 3
463echo 3 >/speakup/punc_level
464echo 3 >/speakup/reading_punc
465echo Punctuation level set to 3.
466
467If you were to store these four small scripts in a directory in your
468path, perhaps /usr/local/bin, and set the permissions to 755 with the
469chmod command, then you could change the default reading punc and
470punctuation levels at the same time by issuing just one command. For
471example, if you were to execute the punc3 command at your shell prompt,
472then the reading punc and punc level would both get set to 3.
473
474I should note that the above scripts were written to work with bash, but
475regardless of which shell you use, you should be able to do something
476similar.
477
478The Speakup sys system also has another interesting use. You can echo
479Speakup parameters into the sys system in a script during system
480startup, and speakup will return to your preferred parameters every time
481the system is rebooted.
482
483Most of the Speakup sys parameters can be manipulated by a regular user
484on the system. However, there are a few parameters that are dangerous
485enough that they should only be manipulated by the root user on your
486system. There are even some parameters that are read only, and cannot
487be written to at all. For example, the version entry in the Speakup
488sys system is read only. This is because there is no reason for a user
489to tamper with the version number which is reported by Speakup. Doing
490an ls -l on /speakup/version will return this:
491
492-r--r--r-- 1 root root 0 Mar 21 13:46 /speakup/version
493
494As you can see, the version entry in the Speakup sys system is read
495only, is owned by root, and belongs to the root group. Doing a cat of
496/speakup/version will display the Speakup version number, like
497this:
498
499cat /speakup/version
500Speakup v-2.00 CVS: Thu Oct 21 10:38:21 EDT 2004
501synth dtlk version 1.1
502
503The display shows the Speakup version number, along with the version
504number of the driver for the current synthesizer.
505
506Looking at entries in the Speakup sys system can be useful in many
507ways. For example, you might wish to know what level your volume is set
508at. You could type:
509
510cat /speakup/KWD/vol
511# Replace KWD with the keyword for your synthesizer, E.G., ltlk for LiteTalk.
5125
513
514The number five which comes back is the level at which the synthesizer
515volume is set at.
516
517All the entries in the Speakup sys system are readable, some are
518writable by root only, and some are writable by everyone. Unless you
519know what you are doing, you should probably leave the ones that are
520writable by root only alone. Most of the names are self explanatory.
521Vol for controlling volume, pitch for pitch, rate for controlling speaking
522rate, etc. If you find one you aren't sure about, you can post a query
523on the Speakup list.
524
5256. Changing Synthesizers
526
527It is possible to change to a different synthesizer while speakup is
528running. In other words, it is not necessary to reboot the system
529in order to use a different synthesizer. You can simply echo the
530synthesizer keyword to the /speakup/synth sys entry.
531Depending on your situation, you may wish to echo none to the synth
532sys entry, to disable speech while one synthesizer is disconnected and
533a second one is connected in its place. Then echo the keyword for the
534new synthesizer into the synth sys entry in order to start speech
535with the newly connected synthesizer. See the list of synthesizer
536keywords in section 1 to find the keyword which matches your synth.
537
5387. Loading modules
539
540As mentioned earlier, Speakup can either be completely compiled into the
541kernel, with the exception of the help module, or it can be compiled as
542a series of modules. When compiled as modules, Speakup will only be
543able to speak some of the bootup messages if your system administrator
544has configured the system to load the modules at boo time. The modules
545can be loaded after the file systems have been checked and mounted, or
546from an initrd. There is a third possibility. Speakup can be compiled
547with some components built into the kernel, and others as modules. As
548we'll see in the next section, this is particularly useful when you are
549working with software synthesizers.
550
551If Speakup is completely compiled as modules, then you must use the
552modprobe command to load Speakup. You do this by loading the module for
553the synthesizer driver you wish to use. The driver modules are all
554named speakup_<keyword>, where <keyword> is the keyword for the
555synthesizer you want. So, in order to load the driver for the DecTalk
556Express, you would type the following command:
557
558modprobe speakup_dectlk
559
560Issuing this command would load the DecTalk Express driver and all other
561related Speakup modules necessary to get Speakup up and running.
562
563To completely unload Speakup, again presuming that it is entirely built
564as modules, you would give the command:
565
566modprobe -r speakup_dectlk
567
568The above command assumes you were running a DecTalk Express. If you
569were using a different synth, then you would substitute its keyword in
570place of dectlk.
571
572If you have multiple drivers loaded, you need to unload all of them, in
573order to completely unload Speakup.
574For example, if you have loaded both the dectlk and ltlk drivers, use the
575command:
576modprobe -r speakup_dectlk speakup_ltlk
577
578You cannot unload the driver for software synthesizers when a user-space
579daemon is using /dev/softsynth. First, kill the daemon. Next, remove
580the driver with the command:
581modprobe -r speakup_soft
582
583Now, suppose we have a situation where the main Speakup component
584is built into the kernel, and some or all of the drivers are built as
585modules. Since the main part of Speakup is compiled into the kernel, a
586partial Speakup sys system has been created which we can take advantage
587of by simply echoing the synthesizer keyword into the
588/speakup/synth sys entry. This will cause the kernel to
589automatically load the appropriate driver module, and start Speakup
590talking. To switch to another synth, just echo a new keyword to the
591synth sys entry. For example, to load the DoubleTalk LT driver,
592you would type:
593
594echo ltlk >/speakup/synth
595
596You can use the modprobe -r command to unload driver modules, regardless
597of whether the main part of Speakup has been built into the kernel or
598not.
599
6008. Using Software Synthesizers
601
602Using a software synthesizer requires that some other software be
603installed and running on your system. For this reason, software
604synthesizers are not available for use at bootup, or during a system
605installation process.
606There are two freely-available solutions for software speech: Espeakup and
607Speech Dispatcher.
608These are described in subsections 8.1 and 8.2, respectively.
609
610During the rest of this section, we assume that speakup_soft is either
611built in to your kernel, or loaded as a module.
612
613If your system does not have udev installed , before you can use a
614software synthesizer, you must have created the /dev/softsynth device.
615If you have not already done so, issue the following commands as root:
616
617cd /dev
618mknod softsynth c 10 26
619
620While we are at it, we might just as well create the /dev/synth device,
621which can be used to let user space programs send information to your
622synthesizer. To create /dev/synth, change to the /dev directory, and
623issue the following command as root:
624
625mknod synth c 10 25
626
627of both.
628
6298.1. Espeakup
630
631Espeakup is a connector between Speakup and the eSpeak software synthesizer.
632Espeakup may already be available as a package for your distribution
633of Linux. If it is not packaged, you need to install it manually.
634You can find it in the contrib/ subdirectory of the Speakup sources.
635The filename is espeakup-$VERSION.tar.bz2, where $VERSION
636depends on the current release of Espeakup. The Speakup 3.1.2 source
637ships with version 0.71 of Espeakup.
638The README file included with the Espeakup sources describes the process
639of manual installation.
640
641Assuming that Espeakup is installed, either by the user or by the distributor,
642follow these steps to use it.
643
644Tell Speakup to use the "soft driver:
645echo soft > /speakup/synth
646
647Finally, start the espeakup program. There are two ways to do it.
648Both require root privileges.
649
650If Espeakup was installed as a package for your Linux distribution,
651you probably have a distribution-specific script that controls the operation
652of the daemon. Look for a file named espeakup under /etc/init.d or
653/etc/rc.d. Execute the following command with root privileges:
654/etc/init.d/espeakup start
655Replace init.d with rc.d, if your distribution uses scripts located under
656/etc/rc.d.
657Your distribution will also have a procedure for starting daemons at
658boot-time, so it is possible to have software speech as soon as user-space
659daemons are started by the bootup scripts.
660These procedures are not described in this document.
661
662If you built Espeakup manually, the "make install" step placed the binary
663under /usr/bin.
664Run the following command as root:
665/usr/bin/espeakup
666Espeakup should start speaking.
667
6688.2. Speech Dispatcher
669
670For this option, you must have a package called
671Speech Dispatcher running on your system, and it must be configured to
672work with one of its supported software synthesizers.
673
674Two open source synthesizers you might use are Flite and Festival. You
675might also choose to purchase the Software DecTalk from Fonix Sales Inc.
676If you run a google search for Fonix, you'll find their web site.
677
678You can obtain a copy of Speech Dispatcher from free(b)soft at
679http://www.freebsoft.org/. Follow the installation instructions that
680come with Speech Dispatcher in order to install and configure Speech
681Dispatcher. You can check out the web site for your Linux distribution
682in order to get a copy of either Flite or Festival. Your Linux
683distribution may also have a precompiled Speech Dispatcher package.
684
685Once you've installed, configured, and tested Speech Dispatcher with your
686chosen software synthesizer, you still need one more piece of software
687in order to make things work. You need a package called speechd-up.
688You get it from the free(b)soft web site mentioned above. After you've
689compiled and installed speechd-up, you are almost ready to begin using
690your software synthesizer.
691
692Now you can begin using your software synthesizer. In order to do so,
693echo the soft keyword to the synth sys entry like this:
694
695echo soft >/speakup/synth
696
697Next run the speechd_up command like this:
698
699speechd_up &
700
701Your synth should now start talking, and you should be able to adjust
702the pitch, rate, etc.
703
7049. Using The DecTalk PC Card
705
706The DecTalk PC card is an ISA card that is inserted into one of the ISA
707slots in your computer. It requires that the DecTalk PC software be
708installed on your computer, and that the software be loaded onto the
709Dectalk PC card before it can be used.
710
711You can get the dec_pc.tgz file from the linux-speakup.org site. The
712dec_pc.tgz file is in the ~ftp/pub/linux/speakup directory.
713
714After you have downloaded the dec_pc.tgz file, untar it in your home
715directory, and read the Readme file in the newly created dec_pc
716directory.
717
718The easiest way to get the software working is to copy the entire dec_pc
719directory into /user/local/lib. To do this, su to root in your home
720directory, and issue the command:
721
722cp dec_pc /usr/local/lib
723
724You will need to copy the dtload command from the dec_pc directory to a
725directory in your path. Either /usr/bin or /usr/local/bin is a good
726choice.
727
728You can now run the dtload command in order to load the DecTalk PC
729software onto the card. After you have done this, echo the decpc
730keyword to the synth entry in the sys system like this:
731
732echo decpc >/speakup/synth
733
734Your DecTalk PC should start talking, and then you can adjust the pitch,
735rate, volume, voice, etc. The voice entry in the Speakup sys system
736will accept a number from 0 through 7 for the DecTalk PC synthesizer,
737which will give you access to some of the DecTalk voices.
738
73910. Using Cursor Tracking
740
741In Speakup version 2.0 and later, cursor tracking is turned on by
742default. This means that when you are using an editor, Speakup will
743automatically speak characters as you move left and right with the
744cursor keys, and lines as you move up and down with the cursor keys.
745This is the traditional sort of cursor tracking.
746Recent versions of Speakup provide two additional ways to control the
747text that is spoken when the cursor is moved:
748"highlight tracking" and "read window."
749They are described later in this section.
750Sometimes, these modes get in your way, so you can disable cursor tracking
751altogether.
752
753You may select among the various forms of cursor tracking using the keypad
754asterisk key.
755Each time you press this key, a new mode is selected, and Speakup speaks
756the name of the new mode. The names for the four possible states of cursor
757tracking are: "cursoring on", "highlight tracking", "read window",
758and "cursoring off." The keypad asterisk key moves through the list of
759modes in a circular fashion.
760
761If highlight tracking is enabled, Speakup tracks highlighted text,
762rather than the cursor itself. When you move the cursor with the arrow keys,
763Speakup speaks the currently highlighted information.
764This is useful when moving through various menus and dialog boxes.
765If cursor tracking isn't helping you while navigating a menu,
766try highlight tracking.
767
768With the "read window" variety of cursor tracking, you can limit the text
769that Speakup speaks by specifying a window of interest on the screen.
770See section 15 for a description of the process of defining windows.
771When you move the cursor via the arrow keys, Speakup only speaks
772the contents of the window. This is especially helpful when you are hearing
773superfluous speech. Consider the following example.
774
775Suppose that you are at a shell prompt. You use bash, and you want to
776explore your command history using the up and down arrow keys. If you
777have enabled cursor tracking, you will hear two pieces of information.
778Speakup speaks both your shell prompt and the current entry from the
779command history. You may not want to hear the prompt repeated
780each time you move, so you can silence it by specifying a window. Find
781the last line of text on the screen. Clear the current window by pressing
782the key combination speakup f3. Use the review cursor to find the first
783character that follows your shell prompt. Press speakup + f2 twice, to
784define a one-line window. The boundaries of the window are the
785character following the shell prompt and the end of the line. Now, cycle
786through the cursor tracking modes using keypad asterisk, until Speakup
787says "read window." Move through your history using your arrow keys.
788You will notice that Speakup no longer speaks the redundant prompt.
789
790Some folks like to turn cursor tracking off while they are using the
791lynx web browser. You definitely want to turn cursor tracking off when
792you are using the alsamixer application. Otherwise, you won't be able
793to hear your mixer settings while you are using the arrow keys.
794
79511. Cut and Paste
796
797One of Speakup's more useful features is the ability to cut and paste
798text on the screen. This means that you can capture information from a
799program, and paste that captured text into a different place in the
800program, or into an entirely different program, which may even be
801running on a different console.
802
803For example, in this manual, we have made references to several web
804sites. It would be nice if you could cut and paste these urls into your
805web browser. Speakup does this quite nicely. Suppose you wanted to
806past the following url into your browser:
807
808http://linux-speakup.org/
809
810Use the speakup review keys to position the reading cursor on the first
811character of the above url. When the reading cursor is in position,
812press the keypad slash key once. Speakup will say, "mark". Next,
813position the reading cursor on the rightmost character of the above
814url. Press the keypad slash key once again to actually cut the text
815from the screen. Speakup will say, "cut". Although we call this
816cutting, Speakup does not actually delete the cut text from the screen.
817It makes a copy of the text in a special buffer for later pasting.
818
819Now that you have the url cut from the screen, you can paste it into
820your browser, or even paste the url on a command line as an argument to
821your browser.
822
823Suppose you want to start lynx and go to the Speakup site.
824
825You can switch to a different console with the alt left and right
826arrows, or you can switch to a specific console by typing alt and a
827function key. These are not Speakup commands, just standard Linux
828console capabilities.
829
830Once you've changed to an appropriate console, and are at a shell prompt,
831type the word lynx, followed by a space. Now press and hold the speakup
832key, while you type the keypad slash character. The url will be pasted
833onto the command line, just as though you had typed it in. Press the
834enter key to execute the command.
835
836The paste buffer will continue to hold the cut information, until a new
837mark and cut operation is carried out. This means you can paste the cut
838information as many times as you like before doing another cut
839operation.
840
841You are not limited to cutting and pasting only one line on the screen.
842You can also cut and paste rectangular regions of the screen. Just
843position the reading cursor at the top left corner of the text to be
844cut, mark it with the keypad slash key, then position the reading cursor
845at the bottom right corner of the region to be cut, and cut it with the
846keypad slash key.
847
84812. Changing the Pronunciation of Characters
849
850Through the /speakup/i18n/characters sys entry, Speakup gives you the
851ability to change how Speakup pronounces a given character. You could,
852for example, change how some punctuation characters are spoken. You can
853even change how Speakup will pronounce certain letters.
854
855You may, for example, wish to change how Speakup pronounces the z
856character. The author of Speakup, Kirk Reiser, is Canadian, and thus
857believes that the z should be pronounced zed. If you are an American,
858you might wish to use the zee pronunciation instead of zed. You can
859change the pronunciation of both the upper and lower case z with the
860following two commands:
861
862echo 90 zee >/speakup/characters
863echo 122 zee >/speakup/characters
864
865Let's examine the parts of the two previous commands. They are issued
866at the shell prompt, and could be placed in a startup script.
867
868The word echo tells the shell that you want to have it display the
869string of characters that follow the word echo. If you were to just
870type:
871
872echo hello.
873
874You would get the word hello printed on your screen as soon as you
875pressed the enter key. In this case, we are echoing strings that we
876want to be redirected into the sys system.
877
878The numbers 90 and 122 in the above echo commands are the ascii numeric
879values for the upper and lower case z, the characters we wish to change.
880
881The string zee is the pronunciation that we want Speakup to use for the
882upper and lower case z.
883
884The > symbol redirects the output of the echo command to a file, just
885like in DOS, or at the Windows command prompt.
886
887And finally, /speakup/i18n/characters is the file entry in the sys system
888where we want the output to be directed. Speakup looks at the numeric
889value of the character we want to change, and inserts the pronunciation
890string into an internal table.
891
892You can look at the whole table with the following command:
893
894cat /speakup/i18n/characters
895
896Speakup will then print out the entire character pronunciation table. I
897won't display it here, but leave you to look at it at your convenience.
898
89913. Mapping Keys
900
901Speakup has the capability of allowing you to assign or "map" keys to
902internal Speakup commands. This section necessarily assumes you have a
903Linux kernel source tree installed, and that it has been patched and
904configured with Speakup. How you do this is beyond the scope of this
905manual. For this information, visit the Speakup web site at
906http://linux-speakup.org/. The reason you'll need the kernel source
907tree patched with Speakup is that the genmap utility you'll need for
908processing keymaps is in the
909/usr/src/linux-<version_number>/drivers/char/speakup directory. The
910<version_number> in the above directory path is the version number of
911the Linux source tree you are working with.
912
913So ok, you've gone off and gotten your kernel source tree, and patched
914and configured it. Now you can start manipulating keymaps.
915
916You can either use the
917/usr/src/linux-<version_number>/drivers/char/speakup/speakupmap.map file
918included with the Speakup source, or you can cut and paste the copy in
919section 4 into a separate file. If you use the one in the Speakup
920source tree, make sure you make a backup of it before you start making
921changes. You have been warned!
922
923Suppose that you want to swap the key assignments for the Speakup
924say_last_char and the Speakup say_first_char commands. The
925speakupmap.map lists the key mappings for these two commands as follows:
926
927spk key_pageup = say_first_char
928spk key_pagedown = say_last_char
929
930You can edit your copy of the speakupmap.map file and swap the command
931names on the right side of the = (equals) sign. You did make a backup,
932right? The new keymap lines would look like this:
933
934spk key_pageup = say_last_char
935spk key_pagedown = say_first_char
936
937After you edit your copy of the speakupmap.map file, save it under a new
938file name, perhaps newmap.map. Then exit your editor and return to the
939shell prompt.
940
941You are now ready to load your keymap with your swapped key assignments.
942 Assuming that you saved your new keymap as the file newmap.map, you
943would load your keymap into the sys system like this:
944
945/usr/src/linux-<version_number>/drivers/char/speakup/genmap newmap.map
946>/speakup/keymap
947
948Remember to substitute your kernel version number for the
949<version_number> in the above command. Also note that although the
950above command wrapped onto two lines in this document, you should type
951it all on one line.
952
953Your say first and say last characters should now be swapped. Pressing
954speakup pagedown should read you the first non-whitespace character on
955the line your reading cursor is in, and pressing speakup pageup should
956read you the last character on the line your reading cursor is in.
957
958You should note that these new mappings will only stay in effect until
959you reboot, or until you load another keymap.
960
961One final warning. If you try to load a partial map, you will quickly
962find that all the mappings you didn't include in your file got deleted
963from the working map. Be extremely careful, and always make a backup!
964You have been warned!
965
96614. Internationalizing Speakup
967
968Speakup indicates various conditions to the user by speaking messages.
969For instance, when you move to the left edge of the screen with the
970review keys, Speakup says, "left."
971Prior to version 3.1.0 of Speakup, all of these messages were in English,
972and they could not be changed. If you used a non-English synthesizer,
973you still heard English messages, such as "left" and "cursoring on."
974In version 3.1.0 or higher, one may load translations for the various
975messages via the /sys filesystem.
976
977The directory /speakup/i18n contains several collections of messages.
978Each group of messages is stored in its own file.
979The following section lists all of these files, along with a brief description
980of each.
981
98214.1. Files Under the i18n Subdirectory
983
984* announcements:
985This file contains various general announcements, most of which cannot
986be categorized. You will find messages such as "You killed Speakup",
987"I'm alive", "leaving help", "parked", "unparked", and others.
988You will also find the names of the screen edges and cursor tracking modes
989here.
990
991* characters:
992See section 12 for a description of this file.
993
994* chartab:
995See section 12. Unlike the rest of the files in the i18n subdirectory,
996this one does not contain messages to be spoken.
997
998* colors:
999When you use the "say attributes" function, Speakup says the name of the
1000foreground and background colors. These names come from the i18n/colors
1001file.
1002
1003* ctl_keys:
1004Here, you will find names of control keys. These are used with Speakup's
1005say_control feature.
1006
1007* formatted:
1008This group of messages contains embedded formatting codes, to specify
1009the type and width of displayed data. If you change these, you must
1010preserve all of the formatting codes, and they must appear in the order
1011used by the default messages.
1012
1013* function_names:
1014Here, you will find a list of names for Speakup functions. These are used
1015by the help system. For example, suppose that you have activated help mode,
1016and you pressed keypad 3. Speakup says:
1017"keypad 3 is character, say next."
1018The message "character, say next" names a Speakup function, and it
1019comes from this function_names file.
1020
1021* key_names:
1022Again, key_names is used by Speakup's help system. In the previous
1023example, Speakup said that you pressed "keypad 3."
1024This name came from the key_names file.
1025
1026* states:
1027This file contains names for key states.
1028Again, these are part of the help system. For instance, if you had pressed
1029speakup + keypad 3, you would hear:
1030"speakup keypad 3 is go to bottom edge."
1031The speakup key is depressed, so the name of the key state is speakup.
1032This part of the message comes from the states collection.
1033
103414.2. Loading Your Own Messages
1035
1036The files under the i18n subdirectory all follow the same format.
1037They consist of lines, with one message per line.
1038Each message is represented by a number, followed by the text of the message.
1039The number is the position of the message in the given collection.
1040For example, if you view the file /speakup/i18n/colors, you will see the
1041following list:
1042
10430 black
10441 blue
10452 green
10463 cyan
10474 red
10485 magenta
10496 yellow
10507 white
10518 grey
1052
1053You can change one message, or you can change a whole group.
1054To load a whole collection of messages from a new source, simply use
1055the cp command:
1056cp ~/my_colors /speakup/i18n/colors
1057You can change an individual message with the echo command,
1058as shown in the following example.
1059
1060The Spanish name for the color blue is azul.
1061Looking at the colors file, we see that the name "blue" is at position 1
1062within the colors group. Let's change blue to azul:
1063echo '1 azul' > /speakup/i18n/colors
1064The next time that Speakup says message 1 from the colors group, it will
1065say "azul", rather than "blue."
1066
1067In the future, translations into various languages will be made available,
1068and most users will just load the files necessary for their language.
1069
107014.3. No Support for Non-Western-European Languages
1071
1072As of the current release, Speakup only supports Western European languages.
1073Support for the extended characters used by languages outside of the Western
1074European family of languages is a work in progress.
1075
107615. Using Speakup's Windowing Capability
1077
1078Speakup has the capability of defining and manipulating windows on the
1079screen. Speakup uses the term "Window", to mean a user defined area of
1080the screen. The key strokes for defining and manipulating Speakup
1081windows are as follows:
1082
1083speakup + f2 -- Set the bounds of the window.
1084Speakup + f3 -- clear the current window definition.
1085speakup + f4 -- Toggle window silence on and off.
1086speakup + keypad plus -- Say the currently defined window.
1087
1088These capabilities are useful for tracking a certain part of the screen
1089without rereading the whole screen, or for silencing a part of the
1090screen that is constantly changing, such as a clock or status line.
1091
1092There is no way to save these window settings, and you can only have one
1093window defined for each virtual console. There is also no way to have
1094windows automaticly defined for specific applications.
1095
1096In order to define a window, use the review keys to move your reading
1097cursor to the beginning of the area you want to define. Then press
1098speakup + f2. Speakup will tell you that the window starts at the
1099indicated row and column position. Then move the reading cursor to the
1100end of the area to be defined as a window, and press speakup + f2 again.
1101 If there is more than one line in the window, Speakup will tell you
1102that the window ends at the indicated row and column position. If there
1103is only one line in the window, then Speakup will tell you that the
1104window is the specified line on the screen. If you are only defining a
1105one line window, you can just press speakup + f2 twice after placing the
1106reading cursor on the line you want to define as a window. It is not
1107necessary to position the reading cursor at the end of the line in order
1108to define the whole line as a window.
1109
111016. Tools for Controlling Speakup
1111
1112The speakup distribution includes extra tools (in the tools directory)
1113which were written to make speakup easier to use. This section will
1114briefly describe the use of these tools.
1115
111616.1. Speakupconf
1117
1118speakupconf began life as a contribution from Steve Holmes, a member of
1119the speakup community. We would like to thank him for his work on the
1120early versions of this project.
1121
1122This script may be installed as part of your linux distribution, but if
1123it isn't, the recommended places to put it are /usr/local/bin or
1124/usr/bin. This script can be run by any user, so it does not require
1125root privileges.
1126
1127Speakupconf allows you to save and load your Speakup settings. It works
1128by reading and writing the /sys files described above.
1129
1130The directory that speakupconf uses to store your settings depends on
1131whether it is run from the root account. If you execute speakupconf as
1132root, it uses the directory /etc/speakup. Otherwise, it uses the directory
1133~/.speakup, where ~ is your home directory.
1134Anyone who needs to use Speakup from your console can load his own custom
1135settings with this script.
1136
1137speakupconf takes one required argument: load or save.
1138Use the command
1139speakupconf save
1140to save your Speakup settings, and
1141speakupconf load
1142to load them into Speakup.
1143A second argument may be specified to use an alternate directory to
1144load or save the speakup parameters.
1145
114616.2. Talkwith
1147
1148Charles Hallenbeck, another member of the speakup community, wrote the
1149initial versions of this script, and we would also like to thank him for
1150his work on it.
1151
1152This script needs root privileges to run, so if it is not installed as
1153part of your linux distribution, the recommended places to install it
1154are /usr/local/sbin or /usr/sbin.
1155
1156Talkwith allows you to switch synthesizers on the fly. It takes a synthesizer
1157name as an argument. For instance,
1158talkwith dectlk
1159causes Speakup to use the DecTalk Express. If you wish to switch to a
1160software synthesizer, you must also indicate which daemon you wish to
1161use. There are two possible choices:
1162spd and espeakup. spd is an abbreviation for speechd-up.
1163If you wish to use espeakup for software synthesis, give the command
1164talkwith soft espeakup
1165To use speechd-up, type:
1166talkwith soft spd
1167Any arguments that follow the name of the daemon are passed to the daemon
1168when it is invoked. For instance:
1169talkwith espeakup --default-voice=fr
1170causes espeakup to use the French voice.
1171Note that talkwith must always be executed with root privileges.
1172
1173Talkwith does not attempt to load your settings after the new
1174synthesizer is activated. You can use speakupconf to load your settings
1175if desired.
1176
1177 GNU Free Documentation License
1178 Version 1.2, November 2002
1179
1180
1181 Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
1182 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1183 Everyone is permitted to copy and distribute verbatim copies
1184 of this license document, but changing it is not allowed.
1185
1186
11870. PREAMBLE
1188
1189The purpose of this License is to make a manual, textbook, or other
1190functional and useful document "free" in the sense of freedom: to
1191assure everyone the effective freedom to copy and redistribute it,
1192with or without modifying it, either commercially or noncommercially.
1193Secondarily, this License preserves for the author and publisher a way
1194to get credit for their work, while not being considered responsible
1195for modifications made by others.
1196
1197This License is a kind of "copyleft", which means that derivative
1198works of the document must themselves be free in the same sense. It
1199complements the GNU General Public License, which is a copyleft
1200license designed for free software.
1201
1202We have designed this License in order to use it for manuals for free
1203software, because free software needs free documentation: a free
1204program should come with manuals providing the same freedoms that the
1205software does. But this License is not limited to software manuals;
1206it can be used for any textual work, regardless of subject matter or
1207whether it is published as a printed book. We recommend this License
1208principally for works whose purpose is instruction or reference.
1209
1210
12111. APPLICABILITY AND DEFINITIONS
1212
1213This License applies to any manual or other work, in any medium, that
1214contains a notice placed by the copyright holder saying it can be
1215distributed under the terms of this License. Such a notice grants a
1216world-wide, royalty-free license, unlimited in duration, to use that
1217work under the conditions stated herein. The "Document", below,
1218refers to any such manual or work. Any member of the public is a
1219licensee, and is addressed as "you". You accept the license if you
1220copy, modify or distribute the work in a way requiring permission
1221under copyright law.
1222
1223A "Modified Version" of the Document means any work containing the
1224Document or a portion of it, either copied verbatim, or with
1225modifications and/or translated into another language.
1226
1227A "Secondary Section" is a named appendix or a front-matter section of
1228the Document that deals exclusively with the relationship of the
1229publishers or authors of the Document to the Document's overall subject
1230(or to related matters) and contains nothing that could fall directly
1231within that overall subject. (Thus, if the Document is in part a
1232textbook of mathematics, a Secondary Section may not explain any
1233mathematics.) The relationship could be a matter of historical
1234connection with the subject or with related matters, or of legal,
1235commercial, philosophical, ethical or political position regarding
1236them.
1237
1238The "Invariant Sections" are certain Secondary Sections whose titles
1239are designated, as being those of Invariant Sections, in the notice
1240that says that the Document is released under this License. If a
1241section does not fit the above definition of Secondary then it is not
1242allowed to be designated as Invariant. The Document may contain zero
1243Invariant Sections. If the Document does not identify any Invariant
1244Sections then there are none.
1245
1246The "Cover Texts" are certain short passages of text that are listed,
1247as Front-Cover Texts or Back-Cover Texts, in the notice that says that
1248the Document is released under this License. A Front-Cover Text may
1249be at most 5 words, and a Back-Cover Text may be at most 25 words.
1250
1251A "Transparent" copy of the Document means a machine-readable copy,
1252represented in a format whose specification is available to the
1253general public, that is suitable for revising the document
1254straightforwardly with generic text editors or (for images composed of
1255pixels) generic paint programs or (for drawings) some widely available
1256drawing editor, and that is suitable for input to text formatters or
1257for automatic translation to a variety of formats suitable for input
1258to text formatters. A copy made in an otherwise Transparent file
1259format whose markup, or absence of markup, has been arranged to thwart
1260or discourage subsequent modification by readers is not Transparent.
1261An image format is not Transparent if used for any substantial amount
1262of text. A copy that is not "Transparent" is called "Opaque".
1263
1264Examples of suitable formats for Transparent copies include plain
1265ASCII without markup, Texinfo input format, LaTeX input format, SGML
1266or XML using a publicly available DTD, and standard-conforming simple
1267HTML, PostScript or PDF designed for human modification. Examples of
1268transparent image formats include PNG, XCF and JPG. Opaque formats
1269include proprietary formats that can be read and edited only by
1270proprietary word processors, SGML or XML for which the DTD and/or
1271processing tools are not generally available, and the
1272machine-generated HTML, PostScript or PDF produced by some word
1273processors for output purposes only.
1274
1275The "Title Page" means, for a printed book, the title page itself,
1276plus such following pages as are needed to hold, legibly, the material
1277this License requires to appear in the title page. For works in
1278formats which do not have any title page as such, "Title Page" means
1279the text near the most prominent appearance of the work's title,
1280preceding the beginning of the body of the text.
1281
1282A section "Entitled XYZ" means a named subunit of the Document whose
1283title either is precisely XYZ or contains XYZ in parentheses following
1284text that translates XYZ in another language. (Here XYZ stands for a
1285specific section name mentioned below, such as "Acknowledgements",
1286"Dedications", "Endorsements", or "History".) To "Preserve the Title"
1287of such a section when you modify the Document means that it remains a
1288section "Entitled XYZ" according to this definition.
1289
1290The Document may include Warranty Disclaimers next to the notice which
1291states that this License applies to the Document. These Warranty
1292Disclaimers are considered to be included by reference in this
1293License, but only as regards disclaiming warranties: any other
1294implication that these Warranty Disclaimers may have is void and has
1295no effect on the meaning of this License.
1296
1297
12982. VERBATIM COPYING
1299
1300You may copy and distribute the Document in any medium, either
1301commercially or noncommercially, provided that this License, the
1302copyright notices, and the license notice saying this License applies
1303to the Document are reproduced in all copies, and that you add no other
1304conditions whatsoever to those of this License. You may not use
1305technical measures to obstruct or control the reading or further
1306copying of the copies you make or distribute. However, you may accept
1307compensation in exchange for copies. If you distribute a large enough
1308number of copies you must also follow the conditions in section 3.
1309
1310You may also lend copies, under the same conditions stated above, and
1311you may publicly display copies.
1312
1313
13143. COPYING IN QUANTITY
1315
1316If you publish printed copies (or copies in media that commonly have
1317printed covers) of the Document, numbering more than 100, and the
1318Document's license notice requires Cover Texts, you must enclose the
1319copies in covers that carry, clearly and legibly, all these Cover
1320Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
1321the back cover. Both covers must also clearly and legibly identify
1322you as the publisher of these copies. The front cover must present
1323the full title with all words of the title equally prominent and
1324visible. You may add other material on the covers in addition.
1325Copying with changes limited to the covers, as long as they preserve
1326the title of the Document and satisfy these conditions, can be treated
1327as verbatim copying in other respects.
1328
1329If the required texts for either cover are too voluminous to fit
1330legibly, you should put the first ones listed (as many as fit
1331reasonably) on the actual cover, and continue the rest onto adjacent
1332pages.
1333
1334If you publish or distribute Opaque copies of the Document numbering
1335more than 100, you must either include a machine-readable Transparent
1336copy along with each Opaque copy, or state in or with each Opaque copy
1337a computer-network location from which the general network-using
1338public has access to download using public-standard network protocols
1339a complete Transparent copy of the Document, free of added material.
1340If you use the latter option, you must take reasonably prudent steps,
1341when you begin distribution of Opaque copies in quantity, to ensure
1342that this Transparent copy will remain thus accessible at the stated
1343location until at least one year after the last time you distribute an
1344Opaque copy (directly or through your agents or retailers) of that
1345edition to the public.
1346
1347It is requested, but not required, that you contact the authors of the
1348Document well before redistributing any large number of copies, to give
1349them a chance to provide you with an updated version of the Document.
1350
1351
13524. MODIFICATIONS
1353
1354You may copy and distribute a Modified Version of the Document under
1355the conditions of sections 2 and 3 above, provided that you release
1356the Modified Version under precisely this License, with the Modified
1357Version filling the role of the Document, thus licensing distribution
1358and modification of the Modified Version to whoever possesses a copy
1359of it. In addition, you must do these things in the Modified Version:
1360
1361A. Use in the Title Page (and on the covers, if any) a title distinct
1362 from that of the Document, and from those of previous versions
1363 (which should, if there were any, be listed in the History section
1364 of the Document). You may use the same title as a previous version
1365 if the original publisher of that version gives permission.
1366B. List on the Title Page, as authors, one or more persons or entities
1367 responsible for authorship of the modifications in the Modified
1368 Version, together with at least five of the principal authors of the
1369 Document (all of its principal authors, if it has fewer than five),
1370 unless they release you from this requirement.
1371C. State on the Title page the name of the publisher of the
1372 Modified Version, as the publisher.
1373D. Preserve all the copyright notices of the Document.
1374E. Add an appropriate copyright notice for your modifications
1375 adjacent to the other copyright notices.
1376F. Include, immediately after the copyright notices, a license notice
1377 giving the public permission to use the Modified Version under the
1378 terms of this License, in the form shown in the Addendum below.
1379G. Preserve in that license notice the full lists of Invariant Sections
1380 and required Cover Texts given in the Document's license notice.
1381H. Include an unaltered copy of this License.
1382I. Preserve the section Entitled "History", Preserve its Title, and add
1383 to it an item stating at least the title, year, new authors, and
1384 publisher of the Modified Version as given on the Title Page. If
1385 there is no section Entitled "History" in the Document, create one
1386 stating the title, year, authors, and publisher of the Document as
1387 given on its Title Page, then add an item describing the Modified
1388 Version as stated in the previous sentence.
1389J. Preserve the network location, if any, given in the Document for
1390 public access to a Transparent copy of the Document, and likewise
1391 the network locations given in the Document for previous versions
1392 it was based on. These may be placed in the "History" section.
1393 You may omit a network location for a work that was published at
1394 least four years before the Document itself, or if the original
1395 publisher of the version it refers to gives permission.
1396K. For any section Entitled "Acknowledgements" or "Dedications",
1397 Preserve the Title of the section, and preserve in the section all
1398 the substance and tone of each of the contributor acknowledgements
1399 and/or dedications given therein.
1400L. Preserve all the Invariant Sections of the Document,
1401 unaltered in their text and in their titles. Section numbers
1402 or the equivalent are not considered part of the section titles.
1403M. Delete any section Entitled "Endorsements". Such a section
1404 may not be included in the Modified Version.
1405N. Do not retitle any existing section to be Entitled "Endorsements"
1406 or to conflict in title with any Invariant Section.
1407O. Preserve any Warranty Disclaimers.
1408
1409If the Modified Version includes new front-matter sections or
1410appendices that qualify as Secondary Sections and contain no material
1411copied from the Document, you may at your option designate some or all
1412of these sections as invariant. To do this, add their titles to the
1413list of Invariant Sections in the Modified Version's license notice.
1414These titles must be distinct from any other section titles.
1415
1416You may add a section Entitled "Endorsements", provided it contains
1417nothing but endorsements of your Modified Version by various
1418parties--for example, statements of peer review or that the text has
1419been approved by an organization as the authoritative definition of a
1420standard.
1421
1422You may add a passage of up to five words as a Front-Cover Text, and a
1423passage of up to 25 words as a Back-Cover Text, to the end of the list
1424of Cover Texts in the Modified Version. Only one passage of
1425Front-Cover Text and one of Back-Cover Text may be added by (or
1426through arrangements made by) any one entity. If the Document already
1427includes a cover text for the same cover, previously added by you or
1428by arrangement made by the same entity you are acting on behalf of,
1429you may not add another; but you may replace the old one, on explicit
1430permission from the previous publisher that added the old one.
1431
1432The author(s) and publisher(s) of the Document do not by this License
1433give permission to use their names for publicity for or to assert or
1434imply endorsement of any Modified Version.
1435
1436
14375. COMBINING DOCUMENTS
1438
1439You may combine the Document with other documents released under this
1440License, under the terms defined in section 4 above for modified
1441versions, provided that you include in the combination all of the
1442Invariant Sections of all of the original documents, unmodified, and
1443list them all as Invariant Sections of your combined work in its
1444license notice, and that you preserve all their Warranty Disclaimers.
1445
1446The combined work need only contain one copy of this License, and
1447multiple identical Invariant Sections may be replaced with a single
1448copy. If there are multiple Invariant Sections with the same name but
1449different contents, make the title of each such section unique by
1450adding at the end of it, in parentheses, the name of the original
1451author or publisher of that section if known, or else a unique number.
1452Make the same adjustment to the section titles in the list of
1453Invariant Sections in the license notice of the combined work.
1454
1455In the combination, you must combine any sections Entitled "History"
1456in the various original documents, forming one section Entitled
1457"History"; likewise combine any sections Entitled "Acknowledgements",
1458and any sections Entitled "Dedications". You must delete all sections
1459Entitled "Endorsements".
1460
1461
14626. COLLECTIONS OF DOCUMENTS
1463
1464You may make a collection consisting of the Document and other documents
1465released under this License, and replace the individual copies of this
1466License in the various documents with a single copy that is included in
1467the collection, provided that you follow the rules of this License for
1468verbatim copying of each of the documents in all other respects.
1469
1470You may extract a single document from such a collection, and distribute
1471it individually under this License, provided you insert a copy of this
1472License into the extracted document, and follow this License in all
1473other respects regarding verbatim copying of that document.
1474
1475
14767. AGGREGATION WITH INDEPENDENT WORKS
1477
1478A compilation of the Document or its derivatives with other separate
1479and independent documents or works, in or on a volume of a storage or
1480distribution medium, is called an "aggregate" if the copyright
1481resulting from the compilation is not used to limit the legal rights
1482of the compilation's users beyond what the individual works permit.
1483When the Document is included in an aggregate, this License does not
1484apply to the other works in the aggregate which are not themselves
1485derivative works of the Document.
1486
1487If the Cover Text requirement of section 3 is applicable to these
1488copies of the Document, then if the Document is less than one half of
1489the entire aggregate, the Document's Cover Texts may be placed on
1490covers that bracket the Document within the aggregate, or the
1491electronic equivalent of covers if the Document is in electronic form.
1492Otherwise they must appear on printed covers that bracket the whole
1493aggregate.
1494
1495
14968. TRANSLATION
1497
1498Translation is considered a kind of modification, so you may
1499distribute translations of the Document under the terms of section 4.
1500Replacing Invariant Sections with translations requires special
1501permission from their copyright holders, but you may include
1502translations of some or all Invariant Sections in addition to the
1503original versions of these Invariant Sections. You may include a
1504translation of this License, and all the license notices in the
1505Document, and any Warranty Disclaimers, provided that you also include
1506the original English version of this License and the original versions
1507of those notices and disclaimers. In case of a disagreement between
1508the translation and the original version of this License or a notice
1509or disclaimer, the original version will prevail.
1510
1511If a section in the Document is Entitled "Acknowledgements",
1512"Dedications", or "History", the requirement (section 4) to Preserve
1513its Title (section 1) will typically require changing the actual
1514title.
1515
1516
15179. TERMINATION
1518
1519You may not copy, modify, sublicense, or distribute the Document except
1520as expressly provided for under this License. Any other attempt to
1521copy, modify, sublicense or distribute the Document is void, and will
1522automatically terminate your rights under this License. However,
1523parties who have received copies, or rights, from you under this
1524License will not have their licenses terminated so long as such
1525parties remain in full compliance.
1526
1527
152810. FUTURE REVISIONS OF THIS LICENSE
1529
1530The Free Software Foundation may publish new, revised versions
1531of the GNU Free Documentation License from time to time. Such new
1532versions will be similar in spirit to the present version, but may
1533differ in detail to address new problems or concerns. See
1534http://www.gnu.org/copyleft/.
1535
1536Each version of the License is given a distinguishing version number.
1537If the Document specifies that a particular numbered version of this
1538License "or any later version" applies to it, you have the option of
1539following the terms and conditions either of that specified version or
1540of any later version that has been published (not as a draft) by the
1541Free Software Foundation. If the Document does not specify a version
1542number of this License, you may choose any version ever published (not
1543as a draft) by the Free Software Foundation.
1544
1545
1546ADDENDUM: How to use this License for your documents
1547
1548To use this License in a document you have written, include a copy of
1549the License in the document and put the following copyright and
1550license notices just after the title page:
1551
1552 Copyright (c) YEAR YOUR NAME.
1553 Permission is granted to copy, distribute and/or modify this document
1554 under the terms of the GNU Free Documentation License, Version 1.2
1555 or any later version published by the Free Software Foundation;
1556 with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
1557 A copy of the license is included in the section entitled "GNU
1558 Free Documentation License".
1559
1560If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
1561replace the "with...Texts." line with this:
1562
1563 with the Invariant Sections being LIST THEIR TITLES, with the
1564 Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
1565
1566If you have Invariant Sections without Cover Texts, or some other
1567combination of the three, merge those two alternatives to suit the
1568situation.
1569
1570If your document contains nontrivial examples of program code, we
1571recommend releasing these examples in parallel under your choice of
1572free software license, such as the GNU General Public License,
1573to permit their use in free software.
1574
1575The End.
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c
new file mode 100644
index 00000000000..7f74f80be69
--- /dev/null
+++ b/drivers/staging/speakup/synth.c
@@ -0,0 +1,458 @@
1#include <linux/types.h>
2#include <linux/ctype.h> /* for isdigit() and friends */
3#include <linux/fs.h>
4#include <linux/mm.h> /* for verify_area */
5#include <linux/errno.h> /* for -EBUSY */
6#include <linux/ioport.h> /* for check_region, request_region */
7#include <linux/interrupt.h>
8#include <linux/delay.h> /* for loops_per_sec */
9#include <linux/kmod.h>
10#include <linux/jiffies.h>
11#include <linux/uaccess.h> /* for copy_from_user */
12#include <linux/sched.h>
13#include <linux/timer.h>
14#include <linux/kthread.h>
15
16#include "spk_priv.h"
17#include "speakup.h"
18#include "serialio.h"
19
20#define MAXSYNTHS 16 /* Max number of synths in array. */
21static struct spk_synth *synths[MAXSYNTHS];
22struct spk_synth *synth = NULL;
23char pitch_buff[32] = "";
24static int module_status;
25int quiet_boot;
26
27struct speakup_info_t speakup_info = {
28 .spinlock = SPIN_LOCK_UNLOCKED,
29 .flushing = 0,
30};
31EXPORT_SYMBOL_GPL(speakup_info);
32
33static int do_synth_init(struct spk_synth *in_synth);
34
35int serial_synth_probe(struct spk_synth *synth)
36{
37 struct serial_state *ser;
38 int failed = 0;
39
40 if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) {
41 ser = spk_serial_init(synth->ser);
42 if (ser == NULL) {
43 failed = -1;
44 } else {
45 outb_p(0, ser->port);
46 mdelay(1);
47 outb_p('\r', ser->port);
48 }
49 } else {
50 failed = -1;
51 pr_warn("ttyS%i is an invalid port\n", synth->ser);
52 }
53 if (failed) {
54 pr_info("%s: not found\n", synth->long_name);
55 return -ENODEV;
56 }
57 pr_info("%s: ttyS%i, Driver Version %s\n",
58 synth->long_name, synth->ser, synth->version);
59 synth->alive = 1;
60 return 0;
61}
62EXPORT_SYMBOL_GPL(serial_synth_probe);
63
64/* Main loop of the progression thread: keep eating from the buffer
65 * and push to the serial port, waiting as needed
66 *
67 * For devices that have a "full" notification mecanism, the driver can
68 * adapt the loop the way they prefer.
69 */
70void spk_do_catch_up(struct spk_synth *synth)
71{
72 u_char ch;
73 unsigned long flags;
74 unsigned long jiff_max;
75 struct var_t *delay_time;
76 struct var_t *full_time;
77 struct var_t *jiffy_delta;
78 int jiffy_delta_val;
79 int delay_time_val;
80 int full_time_val;
81
82 jiffy_delta = get_var(JIFFY);
83 full_time = get_var(FULL);
84 delay_time = get_var(DELAY);
85
86 spk_lock(flags);
87 jiffy_delta_val = jiffy_delta->u.n.value;
88 spk_unlock(flags);
89
90 jiff_max = jiffies + jiffy_delta_val;
91 while (!kthread_should_stop()) {
92 spk_lock(flags);
93 if (speakup_info.flushing) {
94 speakup_info.flushing = 0;
95 spk_unlock(flags);
96 synth->flush(synth);
97 continue;
98 }
99 if (synth_buffer_empty()) {
100 spk_unlock(flags);
101 break;
102 }
103 ch = synth_buffer_peek();
104 set_current_state(TASK_INTERRUPTIBLE);
105 full_time_val = full_time->u.n.value;
106 spk_unlock(flags);
107 if (ch == '\n')
108 ch = synth->procspeech;
109 if (!spk_serial_out(ch)) {
110 schedule_timeout(msecs_to_jiffies(full_time_val));
111 continue;
112 }
113 if ((jiffies >= jiff_max) && (ch == SPACE)) {
114 spk_lock(flags);
115 jiffy_delta_val = jiffy_delta->u.n.value;
116 delay_time_val = delay_time->u.n.value;
117 full_time_val = full_time->u.n.value;
118 spk_unlock(flags);
119 if (spk_serial_out(synth->procspeech))
120 schedule_timeout(msecs_to_jiffies(delay_time_val));
121 else
122 schedule_timeout(msecs_to_jiffies(full_time_val));
123 jiff_max = jiffies + jiffy_delta_val;
124 }
125 set_current_state(TASK_RUNNING);
126 spk_lock(flags);
127 synth_buffer_getc();
128 spk_unlock(flags);
129 }
130 spk_serial_out(synth->procspeech);
131}
132EXPORT_SYMBOL_GPL(spk_do_catch_up);
133
134const char *spk_synth_immediate(struct spk_synth *synth, const char *buff)
135{
136 u_char ch;
137 while ((ch = *buff)) {
138 if (ch == '\n')
139 ch = synth->procspeech;
140 if (wait_for_xmitr())
141 outb(ch, speakup_info.port_tts);
142 else
143 return buff;
144 buff++;
145 }
146 return 0;
147}
148EXPORT_SYMBOL_GPL(spk_synth_immediate);
149
150void spk_synth_flush(struct spk_synth *synth)
151{
152 spk_serial_out(synth->clear);
153}
154EXPORT_SYMBOL_GPL(spk_synth_flush);
155
156int spk_synth_is_alive_nop(struct spk_synth *synth)
157{
158 synth->alive = 1;
159 return 1;
160}
161EXPORT_SYMBOL_GPL(spk_synth_is_alive_nop);
162
163int spk_synth_is_alive_restart(struct spk_synth *synth)
164{
165 if (synth->alive)
166 return 1;
167 if (!synth->alive && wait_for_xmitr() > 0) {
168 /* restart */
169 synth->alive = 1;
170 synth_printf("%s", synth->init);
171 return 2; /* reenabled */
172 }
173 pr_warn("%s: can't restart synth\n", synth->long_name);
174 return 0;
175}
176EXPORT_SYMBOL_GPL(spk_synth_is_alive_restart);
177
178static void thread_wake_up(u_long data)
179{
180 wake_up_interruptible_all(&speakup_event);
181}
182
183static DEFINE_TIMER(thread_timer, thread_wake_up, 0, 0);
184
185void synth_start(void)
186{
187 struct var_t *trigger_time;
188
189 if (!synth->alive) {
190 synth_buffer_clear();
191 return;
192 }
193 trigger_time = get_var(TRIGGER);
194 if (!timer_pending(&thread_timer))
195 mod_timer(&thread_timer, jiffies + msecs_to_jiffies(trigger_time->u.n.value));
196}
197
198void do_flush(void)
199{
200 speakup_info.flushing = 1;
201 synth_buffer_clear();
202 if (synth->alive) {
203 if (pitch_shift) {
204 synth_printf("%s", pitch_buff);
205 pitch_shift = 0;
206 }
207 }
208 wake_up_interruptible_all(&speakup_event);
209 wake_up_process(speakup_task);
210}
211
212void synth_write(const char *buf, size_t count)
213{
214 while (count--)
215 synth_buffer_add(*buf++);
216 synth_start();
217}
218
219void synth_printf(const char *fmt, ...)
220{
221 va_list args;
222 unsigned char buf[160], *p;
223 int r;
224
225 va_start(args, fmt);
226 r = vsnprintf(buf, sizeof(buf), fmt, args);
227 va_end(args);
228 if (r > sizeof(buf) - 1)
229 r = sizeof(buf) - 1;
230
231 p = buf;
232 while (r--)
233 synth_buffer_add(*p++);
234 synth_start();
235}
236EXPORT_SYMBOL_GPL(synth_printf);
237
238static int index_count = 0;
239static int sentence_count = 0;
240
241void reset_index_count(int sc)
242{
243 static int first = 1;
244 if (first)
245 first = 0;
246 else
247 synth->get_index();
248 index_count = 0;
249 sentence_count = sc;
250}
251
252int synth_supports_indexing(void)
253{
254 if (synth->get_index != NULL)
255 return 1;
256 return 0;
257}
258
259void synth_insert_next_index(int sent_num)
260{
261 int out;
262 if (synth->alive) {
263 if (sent_num == 0) {
264 synth->indexing.currindex++;
265 index_count++;
266 if (synth->indexing.currindex >
267 synth->indexing.highindex)
268 synth->indexing.currindex =
269 synth->indexing.lowindex;
270 }
271
272 out = synth->indexing.currindex * 10 + sent_num;
273 synth_printf(synth->indexing.command, out, out);
274 }
275}
276
277void get_index_count(int *linecount, int *sentcount)
278{
279 int ind = synth->get_index();
280 if (ind) {
281 sentence_count = ind % 10;
282
283 if ((ind / 10) <= synth->indexing.currindex)
284 index_count = synth->indexing.currindex-(ind/10);
285 else
286 index_count = synth->indexing.currindex-synth->indexing.lowindex
287 + synth->indexing.highindex-(ind/10)+1;
288
289 }
290 *sentcount = sentence_count;
291 *linecount = index_count;
292}
293
294static struct resource synth_res;
295
296int synth_request_region(unsigned long start, unsigned long n)
297{
298 struct resource *parent = &ioport_resource;
299 memset(&synth_res, 0, sizeof(synth_res));
300 synth_res.name = synth->name;
301 synth_res.start = start;
302 synth_res.end = start + n - 1;
303 synth_res.flags = IORESOURCE_BUSY;
304 return request_resource(parent, &synth_res);
305}
306EXPORT_SYMBOL_GPL(synth_request_region);
307
308int synth_release_region(unsigned long start, unsigned long n)
309{
310 return release_resource(&synth_res);
311}
312EXPORT_SYMBOL_GPL(synth_release_region);
313
314struct var_t synth_time_vars[] = {
315 { DELAY, .u.n = {NULL, 100, 100, 2000, 0, 0, NULL }},
316 { TRIGGER, .u.n = {NULL, 20, 10, 2000, 0, 0, NULL }},
317 { JIFFY, .u.n = {NULL, 50, 20, 200, 0, 0, NULL }},
318 { FULL, .u.n = {NULL, 400, 200, 60000, 0, 0, NULL }},
319 V_LAST_VAR
320};
321
322/* called by: speakup_init() */
323int synth_init(char *synth_name)
324{
325 int i;
326 int ret = 0;
327 struct spk_synth *synth = NULL;
328
329 if (synth_name == NULL)
330 return 0;
331
332 if (strcmp(synth_name, "none") == 0) {
333 mutex_lock(&spk_mutex);
334 synth_release();
335 mutex_unlock(&spk_mutex);
336 return 0;
337 }
338
339 mutex_lock(&spk_mutex);
340 /* First, check if we already have it loaded. */
341 for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++)
342 if (strcmp(synths[i]->name, synth_name) == 0)
343 synth = synths[i];
344
345 /* If we got one, initialize it now. */
346 if (synth)
347 ret = do_synth_init(synth);
348 else
349 ret = -ENODEV;
350 mutex_unlock(&spk_mutex);
351
352 return ret;
353}
354
355/* called by: synth_add() */
356static int do_synth_init(struct spk_synth *in_synth)
357{
358 struct var_t *var;
359
360 synth_release();
361 if (in_synth->checkval != SYNTH_CHECK)
362 return -EINVAL;
363 synth = in_synth;
364 synth->alive = 0;
365 pr_warn("synth probe\n");
366 if (synth->probe(synth) < 0) {
367 pr_warn("%s: device probe failed\n", in_synth->name);
368 synth = NULL;
369 return -ENODEV;
370 }
371 synth_time_vars[0].u.n.value =
372 synth_time_vars[0].u.n.default_val = synth->delay;
373 synth_time_vars[1].u.n.value =
374 synth_time_vars[1].u.n.default_val = synth->trigger;
375 synth_time_vars[2].u.n.value =
376 synth_time_vars[2].u.n.default_val = synth->jiffies;
377 synth_time_vars[3].u.n.value =
378 synth_time_vars[3].u.n.default_val = synth->full;
379 synth_printf("%s", synth->init);
380 for (var = synth->vars; (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
381 speakup_register_var(var);
382 if (!quiet_boot)
383 synth_printf("%s found\n", synth->long_name);
384 if (synth->attributes.name
385 && sysfs_create_group(speakup_kobj, &(synth->attributes)) < 0)
386 return -ENOMEM;
387 synth_flags = synth->flags;
388 wake_up_interruptible_all(&speakup_event);
389 if (speakup_task)
390 wake_up_process(speakup_task);
391 return 0;
392}
393
394void synth_release(void)
395{
396 struct var_t *var;
397 unsigned long flags;
398
399 if (synth == NULL)
400 return;
401 spk_lock(flags);
402 pr_info("releasing synth %s\n", synth->name);
403 synth->alive = 0;
404 del_timer(&thread_timer);
405 spk_unlock(flags);
406 if (synth->attributes.name)
407 sysfs_remove_group(speakup_kobj, &(synth->attributes));
408 for (var = synth->vars; var->var_id != MAXVARS; var++)
409 speakup_unregister_var(var->var_id);
410 stop_serial_interrupt();
411 synth->release();
412 synth = NULL;
413}
414
415/* called by: all_driver_init() */
416int synth_add(struct spk_synth *in_synth)
417{
418 int i;
419 int status = 0;
420 mutex_lock(&spk_mutex);
421 for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++)
422 /* synth_remove() is responsible for rotating the array down */
423 if (in_synth == synths[i]) {
424 mutex_unlock(&spk_mutex);
425 return 0;
426 }
427 if (i == MAXSYNTHS) {
428 pr_warn("Error: attempting to add a synth past end of array\n");
429 mutex_unlock(&spk_mutex);
430 return -1;
431 }
432 synths[i++] = in_synth;
433 synths[i] = NULL;
434 if (in_synth->startup)
435 status = do_synth_init(in_synth);
436 mutex_unlock(&spk_mutex);
437 return status;
438}
439EXPORT_SYMBOL_GPL(synth_add);
440
441void synth_remove(struct spk_synth *in_synth)
442{
443 int i;
444 mutex_lock(&spk_mutex);
445 if (synth == in_synth)
446 synth_release();
447 for (i = 0; synths[i] != NULL; i++) {
448 if (in_synth == synths[i])
449 break;
450 }
451 for ( ; synths[i] != NULL; i++) /* compress table */
452 synths[i] = synths[i+1];
453 module_status = 0;
454 mutex_unlock(&spk_mutex);
455}
456EXPORT_SYMBOL_GPL(synth_remove);
457
458short punc_masks[] = { 0, SOME, MOST, PUNC, PUNC|B_SYM };
diff --git a/drivers/staging/speakup/thread.c b/drivers/staging/speakup/thread.c
new file mode 100644
index 00000000000..84531e70daf
--- /dev/null
+++ b/drivers/staging/speakup/thread.c
@@ -0,0 +1,58 @@
1#include <linux/kthread.h>
2#include <linux/wait.h>
3
4#include "spk_types.h"
5#include "speakup.h"
6#include "spk_priv.h"
7
8DECLARE_WAIT_QUEUE_HEAD(speakup_event);
9EXPORT_SYMBOL_GPL(speakup_event);
10
11int speakup_thread(void *data)
12{
13 unsigned long flags;
14 int should_break;
15 struct bleep our_sound;
16
17 our_sound.active = 0;
18 our_sound.freq = 0;
19 our_sound.jiffies = 0;
20
21 mutex_lock(&spk_mutex);
22 while (1) {
23 DEFINE_WAIT(wait);
24 while(1) {
25 spk_lock(flags);
26 our_sound = unprocessed_sound;
27 unprocessed_sound.active = 0;
28 prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE);
29 should_break = kthread_should_stop() ||
30 our_sound.active ||
31 (synth && synth->catch_up && synth->alive &&
32 (speakup_info.flushing ||
33 !synth_buffer_empty()));
34 spk_unlock(flags);
35 if (should_break)
36 break;
37 mutex_unlock(&spk_mutex);
38 schedule();
39 mutex_lock(&spk_mutex);
40 }
41 finish_wait(&speakup_event, &wait);
42 if (kthread_should_stop())
43 break;
44
45 if (our_sound.active) {
46 kd_mksound(our_sound.freq, our_sound.jiffies);
47 }
48 if (synth && synth->catch_up && synth->alive) {
49 /* It is up to the callee to take the lock, so that it
50 * can sleep whenever it likes */
51 synth->catch_up(synth);
52 }
53
54 speakup_start_ttys();
55 }
56 mutex_unlock(&spk_mutex);
57 return 0;
58}
diff --git a/drivers/staging/speakup/varhandlers.c b/drivers/staging/speakup/varhandlers.c
new file mode 100644
index 00000000000..2d137bd84df
--- /dev/null
+++ b/drivers/staging/speakup/varhandlers.c
@@ -0,0 +1,403 @@
1#include <linux/ctype.h>
2#include "spk_types.h"
3#include "spk_priv.h"
4#include "speakup.h"
5
6static struct st_var_header var_headers[] = {
7 { "version", VERSION, VAR_PROC, NULL, NULL },
8 { "synth_name", SYNTH, VAR_PROC, NULL, NULL },
9 { "keymap", KEYMAP, VAR_PROC, NULL, NULL },
10 { "silent", SILENT, VAR_PROC, NULL, NULL },
11 { "punc_some", PUNC_SOME, VAR_PROC, NULL, NULL },
12 { "punc_most", PUNC_MOST, VAR_PROC, NULL, NULL },
13 { "punc_all", PUNC_ALL, VAR_PROC, NULL, NULL },
14 { "delimiters", DELIM, VAR_PROC, NULL, NULL },
15 { "repeats", REPEATS, VAR_PROC, NULL, NULL },
16 { "ex_num", EXNUMBER, VAR_PROC, NULL, NULL },
17 { "characters", CHARS, VAR_PROC, NULL, NULL },
18 { "synth_direct", SYNTH_DIRECT, VAR_PROC, NULL, NULL },
19 { "caps_start", CAPS_START, VAR_STRING, str_caps_start, NULL },
20 { "caps_stop", CAPS_STOP, VAR_STRING, str_caps_stop, NULL },
21 { "delay_time", DELAY, VAR_TIME, NULL, NULL },
22 { "trigger_time", TRIGGER, VAR_TIME, NULL, NULL },
23 { "jiffy_delta", JIFFY, VAR_TIME, NULL, NULL },
24 { "full_time", FULL, VAR_TIME, NULL, NULL },
25 { "spell_delay", SPELL_DELAY, VAR_NUM, &spell_delay, NULL },
26 { "bleeps", BLEEPS, VAR_NUM, &bleeps, NULL },
27 { "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, &attrib_bleep, NULL },
28 { "bleep_time", BLEEP_TIME, VAR_TIME, &bleep_time, NULL },
29 { "cursor_time", CURSOR_TIME, VAR_TIME, NULL, NULL },
30 { "punc_level", PUNC_LEVEL, VAR_NUM, &punc_level, NULL },
31 { "reading_punc", READING_PUNC, VAR_NUM, &reading_punc, NULL },
32 { "say_control", SAY_CONTROL, VAR_NUM, &say_ctrl, NULL },
33 { "say_word_ctl", SAY_WORD_CTL, VAR_NUM, &say_word_ctl, NULL },
34 { "no_interrupt", NO_INTERRUPT, VAR_NUM, &no_intr, NULL },
35 { "key_echo", KEY_ECHO, VAR_NUM, &key_echo, NULL },
36 { "bell_pos", BELL_POS, VAR_NUM, &bell_pos, NULL },
37 { "rate", RATE, VAR_NUM, NULL, NULL },
38 { "pitch", PITCH, VAR_NUM, NULL, NULL },
39 { "vol", VOL, VAR_NUM, NULL, NULL },
40 { "tone", TONE, VAR_NUM, NULL, NULL },
41 { "punct", PUNCT, VAR_NUM, NULL, NULL },
42 { "voice", VOICE, VAR_NUM, NULL, NULL },
43 { "freq", FREQUENCY, VAR_NUM, NULL, NULL },
44 { "lang", LANG, VAR_NUM, NULL, NULL },
45 { "chartab", CHARTAB, VAR_PROC, NULL, NULL },
46 { "direct", DIRECT, VAR_NUM, NULL, NULL },
47};
48
49static struct st_var_header *var_ptrs[MAXVARS] = { 0, 0, 0 };
50
51static struct punc_var_t punc_vars[] = {
52 { PUNC_SOME, 1 },
53 { PUNC_MOST, 2 },
54 { PUNC_ALL, 3 },
55 { DELIM, 4 },
56 { REPEATS, 5 },
57 { EXNUMBER, 6 },
58 { -1, -1 },
59};
60
61int chartab_get_value(char *keyword)
62{
63 int value = 0;
64
65 if (!strcmp(keyword, "ALPHA"))
66 value = ALPHA;
67 else if (!strcmp(keyword, "B_CTL"))
68 value = B_CTL;
69 else if (!strcmp(keyword, "WDLM"))
70 value = WDLM;
71 else if (!strcmp(keyword, "A_PUNC"))
72 value = A_PUNC;
73 else if (!strcmp(keyword, "PUNC"))
74 value = PUNC;
75 else if (!strcmp(keyword, "NUM"))
76 value = NUM;
77 else if (!strcmp(keyword, "A_CAP"))
78 value = A_CAP;
79 else if (!strcmp(keyword, "B_CAPSYM"))
80 value = B_CAPSYM;
81 else if (!strcmp(keyword, "B_SYM"))
82 value = B_SYM;
83 return value;
84}
85
86void speakup_register_var(struct var_t *var)
87{
88 static char nothing[2] = "\0";
89 int i;
90 struct st_var_header *p_header;
91
92 BUG_ON(!var || var->var_id < 0 || var->var_id >= MAXVARS);
93 if (var_ptrs[0] == NULL) {
94 for (i = 0; i < MAXVARS; i++) {
95 p_header = &var_headers[i];
96 var_ptrs[p_header->var_id] = p_header;
97 p_header->data = NULL;
98 }
99 }
100 p_header = var_ptrs[var->var_id];
101 if (p_header->data != NULL)
102 return;
103 p_header->data = var;
104 switch (p_header->var_type) {
105 case VAR_STRING:
106 set_string_var(nothing, p_header, 0);
107 break;
108 case VAR_NUM:
109 case VAR_TIME:
110 set_num_var(0, p_header, E_DEFAULT);
111 break;
112 default:
113 break;
114 }
115 return;
116}
117
118void speakup_unregister_var(enum var_id_t var_id)
119{
120 struct st_var_header *p_header;
121 BUG_ON(var_id < 0 || var_id >= MAXVARS);
122 p_header = var_ptrs[var_id];
123 p_header->data = NULL;
124}
125
126struct st_var_header *get_var_header(enum var_id_t var_id)
127{
128 struct st_var_header *p_header;
129 if (var_id < 0 || var_id >= MAXVARS)
130 return NULL;
131 p_header = var_ptrs[var_id];
132 if (p_header->data == NULL)
133 return NULL;
134 return p_header;
135}
136
137struct st_var_header *var_header_by_name(const char *name)
138{
139 int i;
140 struct st_var_header *where = NULL;
141
142 if (name != NULL) {
143 i = 0;
144 while ((i < MAXVARS) && (where == NULL)) {
145 if (strcmp(name, var_ptrs[i]->name) == 0)
146 where = var_ptrs[i];
147 else
148 i++;
149 }
150 }
151 return where;
152}
153
154struct var_t *get_var(enum var_id_t var_id)
155{
156 BUG_ON(var_id < 0 || var_id >= MAXVARS);
157 BUG_ON(! var_ptrs[var_id]);
158 return (var_ptrs[var_id]->data);
159}
160EXPORT_SYMBOL_GPL(get_var);
161
162struct punc_var_t *get_punc_var(enum var_id_t var_id)
163{
164 struct punc_var_t *rv = NULL;
165 struct punc_var_t *where;
166
167 where = punc_vars;
168 while ((where->var_id != -1) && (rv == NULL)) {
169 if (where->var_id == var_id)
170 rv = where;
171 else
172 where++;
173 }
174 return rv;
175}
176
177/* handlers for setting vars */
178int set_num_var(int input, struct st_var_header *var, int how)
179{
180 int val;
181 short ret = 0;
182 int *p_val = var->p_val;
183 int l;
184 char buf[32];
185 char *cp;
186 struct var_t *var_data = var->data;
187 if (var_data == NULL)
188 return E_UNDEF;
189
190 if (how == E_NEW_DEFAULT) {
191 if (input < var_data->u.n.low || input > var_data->u.n.high)
192 ret = E_RANGE;
193 else
194 var_data->u.n.default_val = input;
195 return ret;
196 }
197 if (how == E_DEFAULT) {
198 val = var_data->u.n.default_val;
199 ret = SET_DEFAULT;
200 } else {
201 if (how == E_SET)
202 val = input;
203 else
204 val = var_data->u.n.value;
205 if (how == E_INC)
206 val += input;
207 else if (how == E_DEC)
208 val -= input;
209 if (val < var_data->u.n.low || val > var_data->u.n.high)
210 return E_RANGE;
211 }
212 var_data->u.n.value = val;
213 if (var->var_type == VAR_TIME && p_val != NULL) {
214 *p_val = msecs_to_jiffies(val);
215 return ret;
216 }
217 if (p_val != NULL)
218 *p_val = val;
219 if (var->var_id == PUNC_LEVEL) {
220 punc_mask = punc_masks[val];
221 return ret;
222 }
223 if (var_data->u.n.multiplier != 0)
224 val *= var_data->u.n.multiplier;
225 val += var_data->u.n.offset;
226 if (var->var_id < FIRST_SYNTH_VAR || synth == NULL)
227 return ret;
228 if (synth->synth_adjust != NULL) {
229 int status = synth->synth_adjust(var);
230 return (status != 0) ? status : ret;
231 }
232 if (!var_data->u.n.synth_fmt)
233 return ret;
234 if (var->var_id == PITCH)
235 cp = pitch_buff;
236 else
237 cp = buf;
238 if (!var_data->u.n.out_str)
239 l = sprintf(cp, var_data->u.n.synth_fmt, (int)val);
240 else
241 l = sprintf(cp, var_data->u.n.synth_fmt, var_data->u.n.out_str[val]);
242 synth_printf("%s", cp);
243 return ret;
244}
245
246int set_string_var(const char *page, struct st_var_header *var, int len)
247{
248 int ret = 0;
249 struct var_t *var_data = var->data;
250 if (var_data == NULL)
251 return E_UNDEF;
252 if (len > MAXVARLEN)
253 return -E_TOOLONG;
254 if (!len) {
255 if (!var_data->u.s.default_val)
256 return 0;
257 ret = SET_DEFAULT;
258 if (!var->p_val)
259 var->p_val = var_data->u.s.default_val;
260 if (var->p_val != var_data->u.s.default_val)
261 strcpy((char *)var->p_val, var_data->u.s.default_val);
262 } else if (var->p_val)
263 strcpy((char *)var->p_val, page);
264 else
265 return -E_TOOLONG;
266 return ret;
267}
268
269/* set_mask_bits sets or clears the punc/delim/repeat bits,
270 * if input is null uses the defaults.
271 * values for how: 0 clears bits of chars supplied,
272 * 1 clears allk, 2 sets bits for chars */
273int set_mask_bits(const char *input, const int which, const int how)
274{
275 u_char *cp;
276 short mask = punc_info[which].mask;
277 if (how&1) {
278 for (cp = (u_char *)punc_info[3].value; *cp; cp++)
279 spk_chartab[*cp] &= ~mask;
280 }
281 cp = (u_char *)input;
282 if (cp == 0)
283 cp = punc_info[which].value;
284 else {
285 for ( ; *cp; cp++) {
286 if (*cp < SPACE)
287 break;
288 if (mask < PUNC) {
289 if (!(spk_chartab[*cp]&PUNC))
290 break;
291 } else if (spk_chartab[*cp]&B_NUM)
292 break;
293 }
294 if (*cp)
295 return -EINVAL;
296 cp = (u_char *)input;
297 }
298 if (how&2) {
299 for ( ; *cp; cp++)
300 if (*cp > SPACE)
301 spk_chartab[*cp] |= mask;
302 } else {
303 for ( ; *cp; cp++)
304 if (*cp > SPACE)
305 spk_chartab[*cp] &= ~mask;
306 }
307 return 0;
308}
309
310char *strlwr(char *s)
311{
312 char *p;
313 if (s == NULL)
314 return NULL;
315
316 for (p = s; *p; p++)
317 *p = tolower(*p);
318 return s;
319}
320
321char *speakup_s2i(char *start, int *dest)
322{
323 int val;
324 char ch = *start;
325 if (ch == '-' || ch == '+')
326 start++;
327 if (*start < '0' || *start > '9')
328 return start;
329 val = (*start) - '0';
330 start++;
331 while (*start >= '0' && *start <= '9') {
332 val *= 10;
333 val += (*start) - '0';
334 start++;
335 }
336 if (ch == '-')
337 *dest = -val;
338 else
339 *dest = val;
340 return start;
341}
342
343char *s2uchar(char *start, char *dest)
344{
345 int val = 0;
346 while (*start && *start <= SPACE)
347 start++;
348 while (*start >= '0' && *start <= '9') {
349 val *= 10;
350 val += (*start) - '0';
351 start++;
352 }
353 if (*start == ',')
354 start++;
355 *dest = (u_char)val;
356 return start;
357}
358
359char *xlate(char *s)
360{
361 static const char finds[] = "nrtvafe";
362 static const char subs[] = "\n\r\t\013\001\014\033";
363 static const char hx[] = "0123456789abcdefABCDEF";
364 char *p = s, *p1, *p2, c;
365 int num;
366 while ((p = strchr(p, '\\'))) {
367 p1 = p+1;
368 p2 = strchr(finds, *p1);
369 if (p2) {
370 *p++ = subs[p2-finds];
371 p1++;
372 } else if (*p1 >= '0' && *p1 <= '7') {
373 num = (*p1++)&7;
374 while (num < 256 && *p1 >= '0' && *p1 <= '7') {
375 num <<= 3;
376 num = (*p1++)&7;
377 }
378 *p++ = num;
379 } else if (*p1 == 'x' &&
380 strchr(hx, p1[1]) && strchr(hx, p1[2])) {
381 p1++;
382 c = *p1++;
383 if (c > '9')
384 c = (c - '7') & 0x0f;
385 else
386 c -= '0';
387 num = c << 4;
388 c = *p1++;
389 if (c > '9')
390 c = (c-'7')&0x0f;
391 else
392 c -= '0';
393 num += c;
394 *p++ = num;
395 } else
396 *p++ = *p1++;
397 p2 = p;
398 while (*p1)
399 *p2++ = *p1++;
400 *p2 = '\0';
401 }
402 return s;
403}