staging/speakup: Move out of staging
authorSamuel Thibault <samuel.thibault@ens-lyon.org>
Wed, 29 Jul 2020 00:35:31 +0000 (02:35 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 29 Jul 2020 12:02:41 +0000 (14:02 +0200)
The nasty TODO items are done.

Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Link: https://lore.kernel.org/r/20200729003531.907370-1-samuel.thibault@ens-lyon.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
93 files changed:
Documentation/ABI/stable/sysfs-driver-speakup [new file with mode: 0644]
Documentation/admin-guide/spkguide.txt [new file with mode: 0644]
MAINTAINERS
drivers/accessibility/Kconfig
drivers/accessibility/Makefile
drivers/accessibility/speakup/DefaultKeyAssignments [new file with mode: 0644]
drivers/accessibility/speakup/Kconfig [new file with mode: 0644]
drivers/accessibility/speakup/Makefile [new file with mode: 0644]
drivers/accessibility/speakup/TODO [new file with mode: 0644]
drivers/accessibility/speakup/buffers.c [new file with mode: 0644]
drivers/accessibility/speakup/devsynth.c [new file with mode: 0644]
drivers/accessibility/speakup/fakekey.c [new file with mode: 0644]
drivers/accessibility/speakup/i18n.c [new file with mode: 0644]
drivers/accessibility/speakup/i18n.h [new file with mode: 0644]
drivers/accessibility/speakup/keyhelp.c [new file with mode: 0644]
drivers/accessibility/speakup/kobjects.c [new file with mode: 0644]
drivers/accessibility/speakup/main.c [new file with mode: 0644]
drivers/accessibility/speakup/selection.c [new file with mode: 0644]
drivers/accessibility/speakup/serialio.c [new file with mode: 0644]
drivers/accessibility/speakup/serialio.h [new file with mode: 0644]
drivers/accessibility/speakup/speakup.h [new file with mode: 0644]
drivers/accessibility/speakup/speakup_acnt.h [new file with mode: 0644]
drivers/accessibility/speakup/speakup_acntpc.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_acntsa.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_apollo.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_audptr.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_bns.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_decext.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_decpc.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_dectlk.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_dtlk.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_dtlk.h [new file with mode: 0644]
drivers/accessibility/speakup/speakup_dummy.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_keypc.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_ltlk.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_soft.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_spkout.c [new file with mode: 0644]
drivers/accessibility/speakup/speakup_txprt.c [new file with mode: 0644]
drivers/accessibility/speakup/speakupmap.h [new file with mode: 0644]
drivers/accessibility/speakup/speakupmap.map [new file with mode: 0644]
drivers/accessibility/speakup/spk_priv.h [new file with mode: 0644]
drivers/accessibility/speakup/spk_priv_keyinfo.h [new file with mode: 0644]
drivers/accessibility/speakup/spk_ttyio.c [new file with mode: 0644]
drivers/accessibility/speakup/spk_types.h [new file with mode: 0644]
drivers/accessibility/speakup/synth.c [new file with mode: 0644]
drivers/accessibility/speakup/thread.c [new file with mode: 0644]
drivers/accessibility/speakup/varhandlers.c [new file with mode: 0644]
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/speakup/DefaultKeyAssignments [deleted file]
drivers/staging/speakup/Kconfig [deleted file]
drivers/staging/speakup/Makefile [deleted file]
drivers/staging/speakup/TODO [deleted file]
drivers/staging/speakup/buffers.c [deleted file]
drivers/staging/speakup/devsynth.c [deleted file]
drivers/staging/speakup/fakekey.c [deleted file]
drivers/staging/speakup/i18n.c [deleted file]
drivers/staging/speakup/i18n.h [deleted file]
drivers/staging/speakup/keyhelp.c [deleted file]
drivers/staging/speakup/kobjects.c [deleted file]
drivers/staging/speakup/main.c [deleted file]
drivers/staging/speakup/selection.c [deleted file]
drivers/staging/speakup/serialio.c [deleted file]
drivers/staging/speakup/serialio.h [deleted file]
drivers/staging/speakup/speakup.h [deleted file]
drivers/staging/speakup/speakup_acnt.h [deleted file]
drivers/staging/speakup/speakup_acntpc.c [deleted file]
drivers/staging/speakup/speakup_acntsa.c [deleted file]
drivers/staging/speakup/speakup_apollo.c [deleted file]
drivers/staging/speakup/speakup_audptr.c [deleted file]
drivers/staging/speakup/speakup_bns.c [deleted file]
drivers/staging/speakup/speakup_decext.c [deleted file]
drivers/staging/speakup/speakup_decpc.c [deleted file]
drivers/staging/speakup/speakup_dectlk.c [deleted file]
drivers/staging/speakup/speakup_dtlk.c [deleted file]
drivers/staging/speakup/speakup_dtlk.h [deleted file]
drivers/staging/speakup/speakup_dummy.c [deleted file]
drivers/staging/speakup/speakup_keypc.c [deleted file]
drivers/staging/speakup/speakup_ltlk.c [deleted file]
drivers/staging/speakup/speakup_soft.c [deleted file]
drivers/staging/speakup/speakup_spkout.c [deleted file]
drivers/staging/speakup/speakup_txprt.c [deleted file]
drivers/staging/speakup/speakupmap.h [deleted file]
drivers/staging/speakup/speakupmap.map [deleted file]
drivers/staging/speakup/spk_priv.h [deleted file]
drivers/staging/speakup/spk_priv_keyinfo.h [deleted file]
drivers/staging/speakup/spk_ttyio.c [deleted file]
drivers/staging/speakup/spk_types.h [deleted file]
drivers/staging/speakup/spkguide.txt [deleted file]
drivers/staging/speakup/synth.c [deleted file]
drivers/staging/speakup/sysfs-driver-speakup [deleted file]
drivers/staging/speakup/thread.c [deleted file]
drivers/staging/speakup/varhandlers.c [deleted file]

diff --git a/Documentation/ABI/stable/sysfs-driver-speakup b/Documentation/ABI/stable/sysfs-driver-speakup
new file mode 100644 (file)
index 0000000..c6a32c4
--- /dev/null
@@ -0,0 +1,375 @@
+What:          /sys/accessibility/speakup/attrib_bleep
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Beeps the PC speaker when there is an attribute change such as
+               foreground or background color when using speakup review
+               commands. One = on, zero = off.
+
+What:          /sys/accessibility/speakup/bell_pos
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This works much like a typewriter bell. If for example 72 is
+               echoed to bell_pos, it will beep the PC speaker when typing on
+               a line past character 72.
+
+What:          /sys/accessibility/speakup/bleeps
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This controls whether one hears beeps through the PC speaker
+               when using speakup's review commands.
+               TODO: what values does it accept?
+
+What:          /sys/accessibility/speakup/bleep_time
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This controls the duration of the PC speaker beeps speakup
+               produces.
+               TODO: What are the units? Jiffies?
+
+What:          /sys/accessibility/speakup/cursor_time
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This controls cursor delay when using arrow keys. When a
+               connection is very slow, with the default setting, when moving
+               with  the arrows, or backspacing etc. speakup says the incorrect
+               characters. Set this to a higher value to adjust for the delay
+               and better synchronisation between cursor position and speech.
+
+What:          /sys/accessibility/speakup/delimiters
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Delimit a word from speakup.
+               TODO: add more info
+
+What:          /sys/accessibility/speakup/ex_num
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   TODO:
+
+What:          /sys/accessibility/speakup/key_echo
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Controls if speakup speaks keys when they are typed. One = on,
+               zero = off or don't echo keys.
+
+What:          /sys/accessibility/speakup/keymap
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Speakup keymap remaps keys to Speakup functions.
+               It uses a binary
+               format. A special program called genmap is needed to compile a
+               textual  keymap into the binary format which is then loaded into
+               /sys/accessibility/speakup/keymap.
+
+What:          /sys/accessibility/speakup/no_interrupt
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Controls if typing interrupts output from speakup. With
+               no_interrupt set to zero, typing on the keyboard will interrupt
+               speakup if for example
+               the say screen command is used before the
+               entire screen  is read.
+               With no_interrupt set to one, if the say
+               screen command is used, and one then types on the keyboard,
+               speakup will continue to say the whole screen regardless until
+               it finishes.
+
+What:          /sys/accessibility/speakup/punc_all
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This is a list of all the punctuation speakup should speak when
+               punc_level is set to four.
+
+What:          /sys/accessibility/speakup/punc_level
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Controls the level of punctuation spoken as the screen is
+               displayed, not reviewed. Levels range from zero no punctuation,
+               to four, all punctuation. One corresponds to punc_some, two
+               corresponds to punc_most, and three as well as four both
+               correspond to punc_all. Some hardware synthesizers may have
+               different levels each corresponding to  three and four for
+               punc_level. Also note that if punc_level is set to zero, and
+               key_echo is set to one, typed punctuation is still spoken as it
+               is typed.
+
+What:          /sys/accessibility/speakup/punc_most
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This is a list of all the punctuation speakup should speak when
+               punc_level is set to two.
+
+What:          /sys/accessibility/speakup/punc_some
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This is a list of all the punctuation speakup should speak when
+               punc_level is set to one.
+
+What:          /sys/accessibility/speakup/reading_punc
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Almost the same as punc_level, the differences being that
+               reading_punc controls the level of punctuation when reviewing
+               the screen with speakup's screen review commands. The other
+               difference is that reading_punc set to three speaks punc_all,
+               and reading_punc set to four speaks all punctuation, including
+               spaces.
+
+What:          /sys/accessibility/speakup/repeats
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   A list of characters speakup repeats. Normally, when there are
+               more than three characters in a row, speakup
+               just reads three of
+               those characters. For example, "......" would be read as dot,
+               dot, dot. If a . is added to the list of characters in repeats,
+               "......" would be read as dot, dot, dot, times six.
+
+What:          /sys/accessibility/speakup/say_control
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   If set to one, speakup speaks shift, alt and control when those
+               keys are pressed. If say_control is set to zero, shift, ctrl,
+               and alt are not spoken when they are pressed.
+
+What:          /sys/accessibility/speakup/say_word_ctl
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   TODO:
+
+What:          /sys/accessibility/speakup/silent
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   TODO:
+
+What:          /sys/accessibility/speakup/spell_delay
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This controls how fast a word is spelled
+               when speakup's say word
+               review command is pressed twice quickly to speak the current
+               word being reviewed. Zero just speaks the letters one after
+               another, while values one through four
+               seem to introduce more of
+               a pause between the spelling of each letter by speakup.
+
+What:          /sys/accessibility/speakup/synth
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Gets or sets the synthesizer driver currently in use. Reading
+               synth returns the synthesizer driver currently in use. Writing
+               synth switches to the given synthesizer driver, provided it is
+               either built into the kernel, or already loaded as a module.
+
+What:          /sys/accessibility/speakup/synth_direct
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Sends whatever is written to synth_direct
+               directly to the speech synthesizer in use, bypassing speakup.
+               This could be used to make the synthesizer speak
+               a string, or to
+               send control sequences to the synthesizer to change how the
+               synthesizer behaves.
+
+What:          /sys/accessibility/speakup/version
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Reading version returns the version of speakup, and the version
+               of the synthesizer driver currently in use.
+
+What:          /sys/accessibility/speakup/i18n/announcements
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This file contains various general announcements, most of which
+               cannot be categorized.  You will find messages such as "You
+               killed Speakup", "I'm alive", "leaving help", "parked",
+               "unparked", and others. You will also find the names of the
+               screen edges and cursor tracking modes here.
+
+What:          /sys/accessibility/speakup/i18n/chartab
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   TODO
+
+What:          /sys/accessibility/speakup/i18n/ctl_keys
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Here, you will find names of control keys.  These are used with
+               Speakup's say_control feature.
+
+What:          /sys/accessibility/speakup/i18n/function_names
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Here, you will find a list of names for Speakup functions.
+               These are used by the help system.  For example, suppose that
+               you have activated help mode, and you pressed
+               keypad 3.  Speakup
+               says: "keypad 3 is character, say next."
+               The message "character, say next" names a Speakup function, and
+               it comes from this function_names file.
+
+What:          /sys/accessibility/speakup/i18n/states
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This file contains names for key states.
+               Again, these are part of the help system.  For instance, if you
+               had pressed speakup + keypad 3, you would hear:
+               "speakup keypad 3 is go to bottom edge."
+               The speakup key is depressed, so the name of the key state is
+               speakup.
+               This part of the message comes from the states collection.
+
+What:          /sys/accessibility/speakup/i18n/characters
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Through this sys entry, Speakup gives you the ability to change
+               how Speakup pronounces a given character. You could, for
+               example, change how some punctuation characters are spoken. You
+               can even change how Speakup will pronounce certain letters. For
+               further details see '12.  Changing the Pronunciation of
+               Characters' in Speakup User's Guide (file spkguide.txt in
+               source).
+
+What:          /sys/accessibility/speakup/i18n/colors
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   When you use the "say attributes" function, Speakup says the
+               name of the foreground and background colors.  These names come
+               from the i18n/colors file.
+
+What:          /sys/accessibility/speakup/i18n/formatted
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This group of messages contains embedded formatting codes, to
+               specify the type and width of displayed data.  If you change
+               these, you must preserve all of the formatting codes, and they
+               must appear in the order used by the default messages.
+
+What:          /sys/accessibility/speakup/i18n/key_names
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Again, key_names is used by Speakup's help system.  In the
+               previous example, Speakup said that you pressed "keypad 3."
+               This name came from the key_names file.
+
+What:          /sys/accessibility/speakup/<synth-name>/
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   In `/sys/accessibility/speakup` is a directory corresponding to
+               the synthesizer driver currently in use (E.G) `soft` for the
+               soft driver. This directory contains files which control the
+               speech synthesizer itself,
+               as opposed to controlling the speakup
+               screen reader. The parameters in this directory have the same
+               names and functions across all
+               supported synthesizers. The range
+               of values for freq, pitch, rate, and vol is the same for all
+               supported synthesizers, with the given range being internally
+               mapped by the driver to  more or less fit the range of values
+               supported for a given parameter by the individual synthesizer.
+               Below is a description of values and  parameters for soft
+               synthesizer, which is currently the most commonly used.
+
+What:          /sys/accessibility/speakup/soft/caps_start
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This is the string that is sent to the synthesizer to cause it
+               to start speaking uppercase letters. For the soft synthesizer
+               and most others, this causes the pitch of the voice to rise
+               above the currently set pitch.
+
+What:          /sys/accessibility/speakup/soft/caps_stop
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This is the string sent to the synthesizer to cause it to stop
+               speaking uppercase letters. In the case of the soft synthesizer
+               and most others, this returns the pitch of the voice
+               down to the
+               currently set pitch.
+
+What:          /sys/accessibility/speakup/soft/delay_time
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   TODO:
+
+What:          /sys/accessibility/speakup/soft/direct
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Controls if punctuation is spoken by speakup, or by the
+               synthesizer.
+               For example, speakup speaks ">" as "greater", while
+               the espeak synthesizer used by the soft driver speaks "greater
+               than". Zero lets speakup speak the punctuation. One lets the
+               synthesizer itself speak punctuation.
+
+What:          /sys/accessibility/speakup/soft/freq
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Gets or sets the frequency of the speech synthesizer. Range is
+               0-9.
+
+What:          /sys/accessibility/speakup/soft/full_time
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   TODO:
+
+What:          /sys/accessibility/speakup/soft/jiffy_delta
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   This controls how many jiffys the kernel gives to the
+               synthesizer. Setting this too high can make a system unstable,
+               or even crash it.
+
+What:          /sys/accessibility/speakup/soft/pitch
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Gets or sets the pitch of the synthesizer. The range is 0-9.
+
+What:          /sys/accessibility/speakup/soft/inflection
+KernelVersion: 5.8
+Contact:       speakup@linux-speakup.org
+Description:   Gets or sets the inflection of the synthesizer, i.e. the pitch
+               range. The range is 0-9.
+
+What:          /sys/accessibility/speakup/soft/punct
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Gets or sets the amount of punctuation spoken by the
+               synthesizer. The range for the soft driver seems to be 0-2.
+               TODO: How is this related to speakup's punc_level, or
+               reading_punc.
+
+What:          /sys/accessibility/speakup/soft/rate
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Gets or sets the rate of the synthesizer. Range is from zero
+               slowest, to nine fastest.
+
+What:          /sys/accessibility/speakup/soft/tone
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Gets or sets the tone of the speech synthesizer. The range for
+               the soft driver seems to be 0-2. This seems to make no
+               difference if using espeak and the espeakup connector.
+               TODO: does espeakup support different tonalities?
+
+What:          /sys/accessibility/speakup/soft/trigger_time
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   TODO:
+
+What:          /sys/accessibility/speakup/soft/voice
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Gets or sets the voice used by the synthesizer if the
+               synthesizer can speak in more than one voice. The range for the
+               soft driver is 0-7. Note that while espeak supports multiple
+               voices, this parameter will not set the voice when the espeakup
+               connector is used  between speakup and espeak.
+
+What:          /sys/accessibility/speakup/soft/vol
+KernelVersion: 2.6
+Contact:       speakup@linux-speakup.org
+Description:   Gets or sets the volume of the speech synthesizer. Range is 0-9,
+               with zero being the softest, and nine being the loudest.
+
diff --git a/Documentation/admin-guide/spkguide.txt b/Documentation/admin-guide/spkguide.txt
new file mode 100644 (file)
index 0000000..3782f6a
--- /dev/null
@@ -0,0 +1,1575 @@
+
+The Speakup User's Guide
+For Speakup 3.1.2 and Later
+By Gene Collins
+Updated by others
+Last modified on Mon Sep 27 14:26:31 2010
+Document version 1.3
+
+Copyright (c) 2005  Gene Collins
+Copyright (c) 2008  Samuel Thibault
+Copyright (c) 2009, 2010  the Speakup Team
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.2 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
+copy of the license is included in the section entitled "GNU Free
+Documentation License".
+
+Preface
+
+The purpose of this document is to familiarize users with the user
+interface to Speakup, a Linux Screen Reader.  If you need instructions
+for installing or obtaining Speakup, visit the web site at
+http://linux-speakup.org/.  Speakup is a set of patches to the standard
+Linux kernel source tree.  It can be built as a series of modules, or as
+a part of a monolithic kernel.  These details are beyond the scope of
+this manual, but the user may need to be aware of the module
+capabilities, depending on how your system administrator has installed
+Speakup.  If Speakup is built as a part of a monolithic kernel, and the
+user is using a hardware synthesizer, then Speakup will be able to
+provide speech access from the time the kernel is loaded, until the time
+the system is shutdown.  This means that if you have obtained Linux
+installation media for a distribution which includes Speakup as a part
+of its kernel, you will be able, as a blind person, to install Linux
+with speech access unaided by a sighted person.  Again, these details
+are beyond the scope of this manual, but the user should be aware of
+them.  See the web site mentioned above for further details.
+
+1.  Starting Speakup
+
+If your system administrator has installed Speakup to work with your
+specific synthesizer by default, then all you need to do to use Speakup
+is to boot your system, and Speakup should come up talking.  This
+assumes of course  that your synthesizer is a supported hardware
+synthesizer, and that it is either installed in or connected to your
+system, and is if necessary powered on.
+
+It is possible, however, that Speakup may have been compiled into the
+kernel with no default synthesizer.  It is even possible that your
+kernel has been compiled with support for some of the supported
+synthesizers and not others.  If you find that this is the case, and
+your synthesizer is supported but not available, complain to the person
+who compiled and installed your kernel.  Or better yet, go to the web
+site, and learn how to patch Speakup into your own kernel source, and
+build and install your own kernel.
+
+If your kernel has been compiled with Speakup, and has no default
+synthesizer set, or you would like to use a different synthesizer than
+the default one, then you may issue the following command at the boot
+prompt of your boot loader.
+
+linux speakup.synth=ltlk
+
+This command would tell Speakup to look for and use a LiteTalk or
+DoubleTalk LT at boot up.  You may replace the ltlk synthesizer keyword
+with the keyword for whatever synthesizer you wish to use.  The
+speakup.synth parameter will accept the following keywords, provided
+that support for the related synthesizers has been built into the
+kernel.
+
+acntsa -- Accent SA
+acntpc -- Accent PC
+apollo -- Apollo
+audptr -- Audapter
+bns -- Braille 'n Speak
+dectlk -- DecTalk Express (old and new, db9 serial only)
+decext -- DecTalk (old) External
+dtlk -- DoubleTalk PC
+keypc -- Keynote Gold PC
+ltlk -- DoubleTalk LT, LiteTalk, or external Tripletalk (db9 serial only)
+spkout -- Speak Out
+txprt -- Transport
+dummy -- Plain text terminal
+
+Note: Speakup does * NOT * support usb connections!  Speakup also does *
+NOT * support the internal Tripletalk!
+
+Speakup does support two other synthesizers, but because they work in
+conjunction with other software, they must be loaded as modules after
+their related software is loaded, and so are not available at boot up.
+These are as follows:
+
+decpc -- DecTalk PC (not available at boot up)
+soft -- One of several software synthesizers (not available at boot up)
+
+See the sections on loading modules and software synthesizers later in
+this manual for further details.  It should be noted here that the
+speakup.synth boot parameter will have no effect if Speakup has been
+compiled as modules.  In order for Speakup modules to be loaded during
+the boot process, such action must be configured by your system
+administrator.  This will mean that you will hear some, but not all,  of
+the bootup messages.
+
+2.  Basic operation
+
+Once you have booted the system, and if necessary, have supplied the
+proper bootup parameter for your synthesizer, Speakup will begin
+talking as soon as the kernel is loaded.  In fact, it will talk a lot!
+It will speak all the boot up messages that the kernel prints on the
+screen during the boot process.  This is because Speakup is not a
+separate screen reader, but is actually built into the operating
+system.  Since almost all console applications must print text on the
+screen using the kernel, and must get their keyboard input through the
+kernel, they are automatically handled properly by Speakup.  There are a
+few exceptions, but we'll come to those later.
+
+Note:  In this guide I will refer to the numeric keypad as the keypad.
+This is done because the speakupmap.map file referred to later in this
+manual uses the term keypad instead of numeric keypad.  Also I'm lazy
+and would rather only type one word.  So keypad it is.  Got it?  Good.
+
+Most of the Speakup review keys are located on the keypad at the far
+right of the keyboard.  The numlock key should be off, in order for these
+to work.  If you toggle the numlock on, the keypad will produce numbers,
+which is exactly what you want for spreadsheets and such.  For the
+purposes of this guide, you should have the numlock turned off, which is
+its default state at bootup.
+
+You probably won't want to listen to all the bootup messages every time
+you start your system, though it's a good idea to listen to them at
+least once, just so you'll know what kind of information is available to
+you during the boot process.  You can always review these messages after
+bootup with the command:
+
+dmesg | more
+
+In order to speed the boot process, and to silence the speaking of the
+bootup messages, just press the keypad enter key.  This key is located
+in the bottom right corner of the keypad.  Speakup will shut up and stay
+that way, until you press another key.
+
+You can check to see if the boot process has completed by pressing the 8
+key on the keypad, which reads the current line.  This also has the
+effect of starting Speakup talking again, so you can press keypad enter
+to silence it again if the boot process has not completed.
+
+When the boot process is complete, you will arrive at a "login" prompt.
+At this point, you'll need to type in your user id and password, as
+provided by your system administrator.  You will hear Speakup speak the
+letters of your user id as you type it, but not the password.  This is
+because the password is not displayed on the screen for security
+reasons.  This has nothing to do with Speakup, it's a Linux security
+feature.
+
+Once you've logged in, you can run any Linux command or program which is
+allowed by your user id.  Normal users will not be able to run programs
+which require root privileges.
+
+When you are running a program or command, Speakup will automatically
+speak new text as it arrives on the screen.  You can at any time silence
+the speech with keypad enter, or use any of the Speakup review keys.
+
+Here are some basic Speakup review keys, and a short description of what
+they do.
+
+keypad 1 -- read previous character
+keypad 2 -- read current character (pressing keypad 2 twice rapidly will speak
+       the current character phonetically)
+keypad 3 -- read next character
+keypad 4 -- read previous word
+keypad 5 -- read current word (press twice rapidly to spell the current word)
+keypad 6 -- read next word
+keypad 7 -- read previous line
+keypad 8 -- read current line (press twice rapidly to hear how much the
+       text on the current line is indented)
+keypad 9 -- read next line
+keypad period -- speak current cursor position and announce current
+       virtual console
+
+It's also worth noting that the insert key on the keypad is mapped
+as the speakup key.  Instead of pressing and releasing this key, as you
+do under DOS or Windows, you hold it like a shift key, and press other
+keys in combination with it.  For example, repeatedly holding keypad
+insert, from now on called speakup, and keypad enter will toggle the
+speaking of new text on the screen on and off.  This is not the same as
+just pressing keypad enter by itself, which just silences the speech
+until you hit another key.  When you hit speakup plus keypad enter,
+Speakup will say, "You turned me off.", or "Hey, that's better."  When
+Speakup is turned off, no new text on the screen will be spoken.  You
+can still use the reading controls to review the screen however.
+
+3.  Using the Speakup Help System
+
+In order to enter the Speakup help system, press and hold the speakup
+key (remember that this is the keypad insert key), and press the f1 key.
+You will hear the message:
+
+"Press space to leave help, cursor up or down to scroll, or a letter to
+go to commands in list."
+
+When you press the spacebar to leave the help system, you will hear:
+
+"Leaving help."
+
+While you are in the Speakup help system, you can scroll up or down
+through the list of available commands using the cursor keys.  The list
+of commands is arranged in alphabetical order.  If you wish to jump to
+commands in a specific part of the alphabet, you may press the letter of
+the alphabet you wish to jump to.
+
+You can also just explore by typing keyboard keys.  Pressing keys will
+cause Speakup to speak the command associated with that key.  For
+example, if you press the keypad 8 key, you will hear:
+
+"Keypad 8 is line, say current."
+
+You'll notice that some commands do not have keys assigned to them.
+This is because they are very infrequently used commands, and are also
+accessible through the sys system.  We'll discuss the sys system later
+in this manual.
+
+You'll also notice that some commands have two keys assigned to them.
+This is because Speakup has a built in set of alternative key bindings
+for laptop users.  The alternate speakup key is the caps lock key.  You
+can press and hold the caps lock key, while pressing an alternate
+speakup command key to activate the command.  On most laptops, the
+numeric keypad is defined as the keys in the j k l area of the keyboard.
+
+There is usually a function key which turns this keypad function on and
+off, and some other key which controls the numlock state.  Toggling the
+keypad functionality on and off can become a royal pain.  So, Speakup
+gives you a simple way to get at an alternative set of key mappings for
+your laptop.  These are also available by default on desktop systems,
+because Speakup does not know whether it is running on a desktop or
+laptop.  So you may choose which set of Speakup keys to use.  Some
+system administrators may have chosen to compile Speakup for a desktop
+system without this set of alternate key bindings, but these details are
+beyond the scope of this manual.  To use the caps lock for its normal
+purpose, hold the shift key while toggling the caps lock on and off.  We
+should note here, that holding the caps lock key and pressing the z key
+will toggle the alternate j k l keypad on and off.
+
+4.  Keys and Their Assigned Commands
+
+In this section, we'll go through a list of all the speakup keys and
+commands.  You can also get a list of commands and assigned keys from
+the help system.
+
+The following list was taken from the speakupmap.map file.  Key
+assignments are on the left of the equal sign, and the associated
+Speakup commands are on the right.  The designation "spk" means to press
+and hold the speakup key, a.k.a. keypad insert, a.k.a. caps lock, while
+pressing the other specified key.
+
+spk key_f9 = punc_level_dec
+spk key_f10 = punc_level_inc
+spk key_f11 = reading_punc_dec
+spk key_f12 = reading_punc_inc
+spk key_1 = vol_dec
+spk key_2 =  vol_inc
+spk key_3 = pitch_dec
+spk key_4 = pitch_inc
+spk key_5 = rate_dec
+spk key_6 = rate_inc
+key_kpasterisk = toggle_cursoring
+spk key_kpasterisk = speakup_goto
+spk key_f1 = speakup_help
+spk key_f2 = set_win
+spk key_f3 = clear_win
+spk key_f4 = enable_win
+spk key_f5 = edit_some
+spk key_f6 = edit_most
+spk key_f7 = edit_delim
+spk key_f8 = edit_repeat
+shift spk key_f9 = edit_exnum
+ key_kp7 = say_prev_line
+spk key_kp7 = left_edge
+ key_kp8 = say_line
+double  key_kp8 = say_line_indent
+spk key_kp8 = say_from_top
+ key_kp9 = say_next_line
+spk  key_kp9 = top_edge
+ key_kpminus = speakup_parked
+spk key_kpminus = say_char_num
+ key_kp4 = say_prev_word
+spk key_kp4 = say_from_left
+ key_kp5 = say_word
+double key_kp5 = spell_word
+spk key_kp5 = spell_phonetic
+ key_kp6 = say_next_word
+spk key_kp6 = say_to_right
+ key_kpplus = say_screen
+spk key_kpplus = say_win
+ key_kp1 = say_prev_char
+spk key_kp1 = right_edge
+ key_kp2 = say_char
+spk key_kp2 = say_to_bottom
+double key_kp2 = say_phonetic_char
+ key_kp3 = say_next_char
+spk  key_kp3 = bottom_edge
+ key_kp0 = spk_key
+ key_kpdot = say_position
+spk key_kpdot = say_attributes
+key_kpenter = speakup_quiet
+spk key_kpenter = speakup_off
+key_sysrq = speech_kill
+ key_kpslash = speakup_cut
+spk key_kpslash = speakup_paste
+spk key_pageup = say_first_char
+spk key_pagedown = say_last_char
+key_capslock = spk_key
+ spk key_z = spk_lock
+key_leftmeta = spk_key
+ctrl spk key_0 = speakup_goto
+spk key_u = say_prev_line
+spk key_i = say_line
+double spk key_i = say_line_indent
+spk key_o = say_next_line
+spk key_minus = speakup_parked
+shift spk key_minus = say_char_num
+spk key_j = say_prev_word
+spk key_k = say_word
+double spk key_k = spell_word
+spk key_l = say_next_word
+spk key_m = say_prev_char
+spk key_comma = say_char
+double spk key_comma = say_phonetic_char
+spk key_dot = say_next_char
+spk key_n = say_position
+ ctrl spk key_m = left_edge
+ ctrl spk key_y = top_edge
+ ctrl spk key_dot = right_edge
+ctrl spk key_p = bottom_edge
+spk key_apostrophe = say_screen
+spk key_h = say_from_left
+spk key_y = say_from_top
+spk key_semicolon = say_to_right
+spk key_p = say_to_bottom
+spk key_slash = say_attributes
+ spk key_enter = speakup_quiet
+ ctrl  spk key_enter = speakup_off
+ spk key_9 = speakup_cut
+spk key_8 = speakup_paste
+shift spk key_m = say_first_char
+ ctrl spk key_semicolon = say_last_char
+
+5.  The Speakup Sys System
+
+The Speakup screen reader also creates a speakup subdirectory as a part
+of the sys system.
+
+As a convenience, run as root
+
+ln -s /sys/accessibility/speakup /speakup
+
+to directly access speakup parameters from /speakup.
+You can see these entries by typing the command:
+
+ls -1 /speakup/*
+
+If you issue the above ls command, you will get back something like
+this:
+
+/speakup/attrib_bleep
+/speakup/bell_pos
+/speakup/bleep_time
+/speakup/bleeps
+/speakup/cursor_time
+/speakup/delimiters
+/speakup/ex_num
+/speakup/key_echo
+/speakup/keymap
+/speakup/no_interrupt
+/speakup/punc_all
+/speakup/punc_level
+/speakup/punc_most
+/speakup/punc_some
+/speakup/reading_punc
+/speakup/repeats
+/speakup/say_control
+/speakup/say_word_ctl
+/speakup/silent
+/speakup/spell_delay
+/speakup/synth
+/speakup/synth_direct
+/speakup/version
+
+/speakup/i18n:
+announcements
+characters
+chartab
+colors
+ctl_keys
+formatted
+function_names
+key_names
+states
+
+/speakup/soft:
+caps_start
+caps_stop
+delay_time
+direct
+freq
+full_time
+jiffy_delta
+pitch
+inflection
+punct
+rate
+tone
+trigger_time
+voice
+vol
+
+Notice the two subdirectories of /speakup: /speakup/i18n and
+/speakup/soft.
+The i18n subdirectory is described in a later section.
+The files under /speakup/soft represent settings that are specific to the
+driver for the software synthesizer.  If you use the LiteTalk, your
+synthesizer-specific settings would be found in /speakup/ltlk.  In other words,
+a subdirectory named /speakup/KWD is created to hold parameters specific
+to the device whose keyword is KWD.
+These parameters include volume, rate, pitch, and others.
+
+In addition to using the Speakup hot keys to change such things as
+volume, pitch, and rate, you can also echo values to the appropriate
+entry in the /speakup directory.  This is very useful, since it
+lets you control Speakup parameters from within a script.  How you
+would write such scripts is somewhat beyond the scope of this manual,
+but I will include a couple of simple examples here to give you a
+general idea of what such scripts can do.
+
+Suppose for example, that you wanted to control both the punctuation
+level and the reading punctuation level at the same time.  For
+simplicity, we'll call them punc0, punc1, punc2, and punc3.  The scripts
+might look something like this:
+
+#!/bin/bash
+# punc0
+# set punc and reading punc levels to 0
+echo 0 >/speakup/punc_level
+echo 0 >/speakup/reading_punc
+echo Punctuation level set to 0.
+
+#!/bin/bash
+# punc1
+# set punc and reading punc levels to 1
+echo 1 >/speakup/punc_level
+echo 1 >/speakup/reading_punc
+echo Punctuation level set to 1.
+
+#!/bin/bash
+# punc2
+# set punc and reading punc levels to 2
+echo 2 >/speakup/punc_level
+echo 2 >/speakup/reading_punc
+echo Punctuation level set to 2.
+
+#!/bin/bash
+# punc3
+# set punc and reading punc levels to 3
+echo 3 >/speakup/punc_level
+echo 3 >/speakup/reading_punc
+echo Punctuation level set to 3.
+
+If you were to store these four small scripts in a directory in your
+path, perhaps /usr/local/bin, and set the permissions to 755 with the
+chmod command, then you could change the default reading punc and
+punctuation levels at the same time by issuing just one command.  For
+example, if you were to execute the punc3 command at your shell prompt,
+then the reading punc and punc level would both get set to 3.
+
+I should note that the above scripts were written to work with bash, but
+regardless of which shell you use, you should be able to do something
+similar.
+
+The Speakup sys system also has another interesting use.  You can echo
+Speakup parameters into the sys system in a script during system
+startup, and speakup will return to your preferred parameters every time
+the system is rebooted.
+
+Most of the Speakup sys parameters can be manipulated by a regular user
+on the system.  However, there are a few parameters that are dangerous
+enough that they should only be manipulated by the root user on your
+system.  There are even some parameters that are read only, and cannot
+be written to at all.  For example, the version entry in the Speakup
+sys system is read only.  This is because there is no reason for a user
+to tamper with the version number which is reported by Speakup.  Doing
+an ls -l on /speakup/version will return this:
+
+-r--r--r--    1 root     root            0 Mar 21 13:46 /speakup/version
+
+As you can see, the version entry in the Speakup sys system is read
+only, is owned by root, and belongs to the root group.  Doing a cat of
+/speakup/version will display the Speakup version number, like
+this:
+
+cat /speakup/version
+Speakup v-2.00 CVS: Thu Oct 21 10:38:21 EDT 2004
+synth dtlk version 1.1
+
+The display shows the Speakup version number, along with the version
+number of the driver for the current synthesizer.
+
+Looking at entries in the Speakup sys system can be useful in many
+ways.  For example, you might wish to know what level your volume is set
+at.  You could type:
+
+cat /speakup/KWD/vol
+# Replace KWD with the keyword for your synthesizer, E.G., ltlk for LiteTalk.
+5
+
+The number five which comes back is the level at which the synthesizer
+volume is set at.
+
+All the entries in the Speakup sys system are readable, some are
+writable by root only, and some are writable by everyone.  Unless you
+know what you are doing, you should probably leave the ones that are
+writable by root only alone.  Most of the names are self explanatory.
+Vol for controlling volume, pitch for pitch, inflection for pitch range, rate
+for controlling speaking rate, etc.  If you find one you aren't sure about, you
+can post a query on the Speakup list.
+
+6.  Changing Synthesizers
+
+It is possible to change to a different synthesizer while speakup is
+running.  In other words, it is not necessary to reboot the system
+in order to use a different synthesizer.  You can simply echo the
+synthesizer keyword to the /speakup/synth sys entry.
+Depending on your situation, you may wish to echo none to the synth
+sys entry, to disable speech while one synthesizer is disconnected and
+a second one is connected in its place.  Then echo the keyword for the
+new synthesizer into the synth sys entry in order to start speech
+with the newly connected synthesizer.  See the list of synthesizer
+keywords in section 1 to find the keyword which matches your synth.
+
+7.  Loading modules
+
+As mentioned earlier, Speakup can either be completely compiled into the
+kernel, with the exception of the help module, or it can be compiled as
+a series of modules.   When compiled as modules, Speakup will only be
+able to speak some of the bootup messages if your system administrator
+has configured the system to load the modules at boo time. The modules
+can  be loaded after the file systems have been checked and mounted, or
+from an initrd.  There is a third possibility.  Speakup can be compiled
+with some components built into the kernel, and others as modules.  As
+we'll see in the next section, this is particularly useful when you are
+working with software synthesizers.
+
+If Speakup is completely compiled as modules, then you must use the
+modprobe command to load Speakup.  You do this by loading the module for
+the synthesizer driver you wish to use.  The driver modules are all
+named speakup_<keyword>, where <keyword> is the keyword for the
+synthesizer you want.  So, in order to load the driver for the DecTalk
+Express, you would type the following command:
+
+modprobe speakup_dectlk
+
+Issuing this command would load the DecTalk Express driver and all other
+related Speakup modules necessary to get Speakup up and running.
+
+To completely unload Speakup, again presuming that it is entirely built
+as modules, you would give the command:
+
+modprobe -r speakup_dectlk
+
+The above command assumes you were running a DecTalk Express.  If you
+were using a different synth, then you would substitute its keyword in
+place of dectlk.
+
+If you have multiple drivers loaded, you need to unload all of them, in
+order to completely unload Speakup.
+For example, if you have loaded both the dectlk and ltlk drivers, use the
+command:
+modprobe -r speakup_dectlk speakup_ltlk
+
+You cannot unload the driver for software synthesizers when a user-space
+daemon is using /dev/softsynth.  First, kill the daemon.  Next, remove
+the driver with the command:
+modprobe -r speakup_soft
+
+Now, suppose we have a situation where the main Speakup component
+is built into the kernel, and some or all of the drivers are built as
+modules.  Since the main part of Speakup is compiled into the kernel, a
+partial Speakup sys system has been created which we can take advantage
+of by simply echoing the synthesizer keyword into the
+/speakup/synth sys entry.  This will cause the kernel to
+automatically load the appropriate driver module, and start Speakup
+talking.  To switch to another synth, just echo a new keyword to the
+synth sys entry.  For example, to load the DoubleTalk LT driver,
+you would type:
+
+echo ltlk >/speakup/synth
+
+You can use the modprobe -r command to unload driver modules, regardless
+of whether the main part of Speakup has been built into the kernel or
+not.
+
+8.  Using Software Synthesizers
+
+Using a software synthesizer requires that some other software be
+installed and running on your system.  For this reason, software
+synthesizers are not available for use at bootup, or during a system
+installation process.
+There are two freely-available solutions for software speech: Espeakup and
+Speech Dispatcher.
+These are described in subsections 8.1 and 8.2, respectively.
+
+During the rest of this section, we assume that speakup_soft is either
+built in to your kernel, or loaded as a module.
+
+If your system does not have udev installed , before you can use a
+software synthesizer, you must have created the /dev/softsynth device.
+If you have not already done so, issue the following commands as root:
+
+cd /dev
+mknod softsynth c 10 26
+
+While we are at it, we might just as well create the /dev/synth device,
+which can be used to let user space programs send information to your
+synthesizer.  To create /dev/synth, change to the /dev directory, and
+issue the following command as root:
+
+mknod synth c 10 25
+
+of both.
+
+8.1. Espeakup
+
+Espeakup is a connector between Speakup and the eSpeak software synthesizer.
+Espeakup may already be available as a package for your distribution
+of Linux.  If it is not packaged, you need to install it manually.
+You can find it in the contrib/ subdirectory of the Speakup sources.
+The filename is espeakup-$VERSION.tar.bz2, where $VERSION
+depends on the current release of Espeakup.  The Speakup 3.1.2 source
+ships with version 0.71 of Espeakup.
+The README file included with the Espeakup sources describes the process
+of manual installation.
+
+Assuming that Espeakup is installed, either by the user or by the distributor,
+follow these steps to use it.
+
+Tell Speakup to use the "soft driver:
+echo soft > /speakup/synth
+
+Finally, start the espeakup program.  There are two ways to do it.
+Both require root privileges.
+
+If Espeakup was installed as a package for your Linux distribution,
+you probably have a distribution-specific script that controls the operation
+of the daemon.  Look for a file named espeakup under /etc/init.d or
+/etc/rc.d.  Execute the following command with root privileges:
+/etc/init.d/espeakup start
+Replace init.d with rc.d, if your distribution uses scripts located under
+/etc/rc.d.
+Your distribution will also have a procedure for starting daemons at
+boot-time, so it is possible to have software speech as soon as user-space
+daemons are started by the bootup scripts.
+These procedures are not described in this document.
+
+If you built Espeakup manually, the "make install" step placed the binary
+under /usr/bin.
+Run the following command as root:
+/usr/bin/espeakup
+Espeakup should start speaking.
+
+8.2. Speech Dispatcher
+
+For this option, you must have a package called
+Speech Dispatcher running on your system, and it must be configured to
+work with one of its supported software synthesizers.
+
+Two open source synthesizers you might use are Flite and Festival.  You
+might also choose to purchase the Software DecTalk from Fonix Sales Inc.
+If you run a google search for Fonix, you'll find their web site.
+
+You can obtain a copy of Speech Dispatcher from free(b)soft at
+http://www.freebsoft.org/.  Follow the installation instructions that
+come with Speech Dispatcher in order to install and configure Speech
+Dispatcher.  You can check out the web site for your Linux distribution
+in order to get a copy of either Flite or Festival.  Your Linux
+distribution may also have a precompiled Speech Dispatcher package.
+
+Once you've installed, configured, and tested Speech Dispatcher with your
+chosen software synthesizer, you still need one more piece of software
+in order to make things work.  You need a package called speechd-up.
+You get it from the free(b)soft web site mentioned above.  After you've
+compiled and installed speechd-up, you are almost ready to begin using
+your software synthesizer.
+
+Now you can begin using your software synthesizer.  In order to do so,
+echo the soft keyword to the synth sys entry like this:
+
+echo soft >/speakup/synth
+
+Next run the speechd_up command like this:
+
+speechd_up &
+
+Your synth should now start talking, and you should be able to adjust
+the pitch, rate, etc.
+
+9.  Using The DecTalk PC Card
+
+The DecTalk PC card is an ISA card that is inserted into one of the ISA
+slots in your computer.  It requires that the DecTalk PC software be
+installed on your computer, and that the software be loaded onto the
+Dectalk PC card before it can be used.
+
+You can get the dec_pc.tgz file from the linux-speakup.org site.  The
+dec_pc.tgz file is in the ~ftp/pub/linux/speakup directory.
+
+After you have downloaded the dec_pc.tgz file, untar it in your home
+directory, and read the Readme file in the newly created dec_pc
+directory.
+
+The easiest way to get the software working is to copy the entire dec_pc
+directory into /user/local/lib.  To do this, su to root in your home
+directory, and issue the command:
+
+cp dec_pc /usr/local/lib
+
+You will need to copy the dtload command from the dec_pc directory to a
+directory in your path.  Either /usr/bin or /usr/local/bin is a good
+choice.
+
+You can now run the dtload command in order to load the DecTalk PC
+software onto the card.  After you have done this, echo the decpc
+keyword to the synth entry in the sys system like this:
+
+echo decpc >/speakup/synth
+
+Your DecTalk PC should start talking, and then you can adjust the pitch,
+rate, volume, voice, etc.  The voice entry in the Speakup sys system
+will accept a number from 0 through 7 for the DecTalk PC synthesizer,
+which will give you access to some of the DecTalk voices.
+
+10.  Using Cursor Tracking
+
+In Speakup version 2.0 and later, cursor tracking is turned on by
+default.  This means that when you are using an editor, Speakup will
+automatically speak characters as you move left and right with the
+cursor keys, and lines as you move up and down with the cursor keys.
+This is the traditional sort of cursor tracking.
+Recent versions of Speakup provide two additional ways to control the
+text that is spoken when the cursor is moved:
+"highlight tracking" and "read window."
+They are described later in this section.
+Sometimes, these modes get in your way, so you can disable cursor tracking
+altogether.
+
+You may select among the various forms of cursor tracking using the keypad
+asterisk key.
+Each time you press this key, a new mode is selected, and Speakup speaks
+the name of the new mode.  The names for the four possible states of cursor
+tracking are: "cursoring on", "highlight tracking", "read window",
+and "cursoring off."  The keypad asterisk key moves through the list of
+modes in a circular fashion.
+
+If highlight tracking is enabled, Speakup tracks highlighted text,
+rather than the cursor itself. When you move the cursor with the arrow keys,
+Speakup speaks the currently highlighted information.
+This is useful when moving through various menus and dialog boxes.
+If cursor tracking isn't helping you while navigating a menu,
+try highlight tracking.
+
+With the "read window" variety of cursor tracking, you can limit the text
+that Speakup speaks by specifying a window of interest on the screen.
+See section 15 for a description of the process of defining windows.
+When you move the cursor via the arrow keys, Speakup only speaks
+the contents of the window.  This is especially helpful when you are hearing
+superfluous speech.  Consider the following example.
+
+Suppose that you are at a shell prompt.  You use bash, and you want to
+explore your command history using the up and down arrow keys.  If you
+have enabled cursor tracking, you will hear two pieces of information.
+Speakup speaks both your shell prompt and the current entry from the
+command history.  You may not want to hear the prompt repeated
+each time you move, so you can silence it by specifying a window.  Find
+the last line of text on the screen.  Clear the current window by pressing
+the key combination speakup f3.  Use the review cursor to find the first
+character that follows your shell prompt.  Press speakup + f2 twice, to
+define a one-line window.  The boundaries of the window are the
+character following the shell prompt and the end of the line.  Now, cycle
+through the cursor tracking modes using keypad asterisk, until Speakup
+says "read window."  Move through your history using your arrow keys.
+You will notice that Speakup no longer speaks the redundant prompt.
+
+Some folks like to turn cursor tracking off while they are using the
+lynx web browser.  You definitely want to turn cursor tracking off when
+you are using the alsamixer application.  Otherwise, you won't be able
+to hear your mixer settings while you are using the arrow keys.
+
+11.  Cut and Paste
+
+One of Speakup's more useful features is the ability to cut and paste
+text on the screen.  This means that you can capture information from a
+program, and paste that captured text into a different place in the
+program, or into an entirely different program, which may even be
+running on a different console.
+
+For example, in this manual, we have made references to several web
+sites.  It would be nice if you could cut and paste these urls into your
+web browser.  Speakup does this quite nicely.  Suppose you wanted to
+past the following url into your browser:
+
+http://linux-speakup.org/
+
+Use the speakup review keys to position the reading cursor on the first
+character of the above url.  When the reading cursor is in position,
+press the keypad slash key once.  Speakup will say, "mark".  Next,
+position the reading cursor on the rightmost character of the above
+url. Press the keypad slash key once again to actually cut the text
+from the screen.  Speakup will say, "cut".  Although we call this
+cutting, Speakup does not actually delete the cut text from the screen.
+It makes a copy of the text in a special buffer for later pasting.
+
+Now that you have the url cut from the screen, you can paste it into
+your browser, or even paste the url on a command line as an argument to
+your browser.
+
+Suppose you want to start lynx and go to the Speakup site.
+
+You can switch to a different console with the alt left and right
+arrows, or you can switch to a specific console by typing alt and a
+function key.  These are not Speakup commands, just standard Linux
+console capabilities.
+
+Once you've changed to an appropriate console, and are at a shell prompt,
+type the word lynx, followed by a space.  Now press and hold the speakup
+key, while you type the keypad slash character.  The url will be pasted
+onto the command line, just as though you had typed it in.  Press the
+enter key to execute the command.
+
+The paste buffer will continue to hold the cut information, until a new
+mark and cut operation is carried out.  This means you can paste the cut
+information as many times as you like before doing another cut
+operation.
+
+You are not limited to cutting and pasting only one line on the screen.
+You can also cut and paste rectangular regions of the screen.  Just
+position the reading cursor at the top left corner of the text to be
+cut, mark it with the keypad slash key, then position the reading cursor
+at the bottom right corner of the region to be cut, and cut it with the
+keypad slash key.
+
+12.  Changing the Pronunciation of Characters
+
+Through the /speakup/i18n/characters sys entry, Speakup gives you the
+ability to change how Speakup pronounces a given character.  You could,
+for example, change how some punctuation characters are spoken.  You can
+even change how Speakup will pronounce certain letters.
+
+You may, for example, wish to change how Speakup pronounces the z
+character.  The author of Speakup, Kirk Reiser, is Canadian, and thus
+believes that the z should be pronounced zed.  If you are an American,
+you might wish to use the zee pronunciation instead of zed.  You can
+change the pronunciation of both the upper and lower case z with the
+following two commands:
+
+echo 90 zee >/speakup/characters
+echo 122 zee >/speakup/characters
+
+Let's examine the parts of the two previous commands.  They are issued
+at the shell prompt, and could be placed in a startup script.
+
+The word echo tells the shell that you want to have it display the
+string of characters that follow the word echo.  If you were to just
+type:
+
+echo hello.
+
+You would get the word hello printed on your screen as soon as you
+pressed the enter key.  In this case, we are echoing strings that we
+want to be redirected into the sys system.
+
+The numbers 90 and 122 in the above echo commands are the ascii numeric
+values for the upper and lower case z, the characters we wish to change.
+
+The string zee is the pronunciation that we want Speakup to use for the
+upper and lower case z.
+
+The > symbol redirects the output of the echo command to a file, just
+like in DOS, or at the Windows command prompt.
+
+And finally, /speakup/i18n/characters is the file entry in the sys system
+where we want the output to be directed.  Speakup looks at the numeric
+value of the character we want to change, and inserts the pronunciation
+string into an internal table.
+
+You can look at the whole table with the following command:
+
+cat /speakup/i18n/characters
+
+Speakup will then print out the entire character pronunciation table.  I
+won't display it here, but leave you to look at it at your convenience.
+
+13.  Mapping Keys
+
+Speakup has the capability of allowing you to assign or "map" keys to
+internal Speakup commands.  This section necessarily assumes you have a
+Linux kernel source tree installed, and that it has been patched and
+configured with Speakup.  How you do this is beyond the scope of this
+manual.  For this information, visit the Speakup web site at
+http://linux-speakup.org/.  The reason you'll need the kernel source
+tree patched with Speakup is that the genmap utility you'll need for
+processing keymaps is in the
+/usr/src/linux-<version_number>/drivers/char/speakup directory.  The
+<version_number> in the above directory path is the version number of
+the Linux source tree you are working with.
+
+So ok, you've gone off and gotten your kernel source tree, and patched
+and configured it.  Now you can start manipulating keymaps.
+
+You can either use the
+/usr/src/linux-<version_number>/drivers/char/speakup/speakupmap.map file
+included with the Speakup source, or you can cut and paste the copy in
+section 4 into a separate file.  If you use the one in the Speakup
+source tree, make sure you make a backup of it before you start making
+changes.  You have been warned!
+
+Suppose that you want to swap the key assignments for the Speakup
+say_last_char and the Speakup say_first_char commands.  The
+speakupmap.map lists the key mappings for these two commands as follows:
+
+spk key_pageup = say_first_char
+spk key_pagedown = say_last_char
+
+You can edit your copy of the speakupmap.map file and swap the command
+names on the right side of the = (equals) sign.  You did make a backup,
+right?  The new keymap lines would look like this:
+
+spk key_pageup = say_last_char
+spk key_pagedown = say_first_char
+
+After you edit your copy of the speakupmap.map file, save it under a new
+file name, perhaps newmap.map.  Then exit your editor and return to the
+shell prompt.
+
+You are now ready to load your keymap with your swapped key assignments.
+ Assuming that you saved your new keymap as the file newmap.map, you
+would load your keymap into the sys system like this:
+
+/usr/src/linux-<version_number>/drivers/char/speakup/genmap newmap.map
+>/speakup/keymap
+
+Remember to substitute your kernel version number for the
+<version_number> in the above command.  Also note that although the
+above command wrapped onto two lines in this document, you should type
+it all on one line.
+
+Your say first and say last characters should now be swapped.  Pressing
+speakup pagedown should read you the first non-whitespace character on
+the line your reading cursor is in, and pressing speakup pageup should
+read you the last character on the line your reading cursor is in.
+
+You should note that these new mappings will only stay in effect until
+you reboot, or until you load another keymap.
+
+One final warning.  If you try to load a partial map, you will quickly
+find that all the mappings you didn't include in your file got deleted
+from the working map.  Be extremely careful, and always make a backup!
+You have been warned!
+
+14.  Internationalizing Speakup
+
+Speakup indicates various conditions to the user by speaking messages.
+For instance, when you move to the left edge of the screen with the
+review keys, Speakup says, "left."
+Prior to version 3.1.0 of Speakup, all of these messages were in English,
+and they could not be changed.  If you used a non-English synthesizer,
+you still heard English messages, such as "left" and "cursoring on."
+In version 3.1.0 or higher, one may load translations for the various
+messages via the /sys filesystem.
+
+The directory /speakup/i18n contains several collections of messages.
+Each group of messages is stored in its own file.
+The following section lists all of these files, along with a brief description
+of each.
+
+14.1.  Files Under the i18n Subdirectory
+
+* announcements:
+This file contains various general announcements, most of which cannot
+be categorized.  You will find messages such as "You killed Speakup",
+"I'm alive", "leaving help", "parked", "unparked", and others.
+You will also find the names of the screen edges and cursor tracking modes
+here.
+
+* characters:
+See section 12 for a description of this file.
+
+* chartab:
+See section 12.  Unlike the rest of the files in the i18n subdirectory,
+this one does not contain messages to be spoken.
+
+* colors:
+When you use the "say attributes" function, Speakup says the name of the
+foreground and background colors.  These names come from the i18n/colors
+file.
+
+* ctl_keys:
+Here, you will find names of control keys.  These are used with Speakup's
+say_control feature.
+
+* formatted:
+This group of messages contains embedded formatting codes, to specify
+the type and width of displayed data.  If you change these, you must
+preserve all of the formatting codes, and they must appear in the order
+used by the default messages.
+
+* function_names:
+Here, you will find a list of names for Speakup functions.  These are used
+by the help system.  For example, suppose that you have activated help mode,
+and you pressed keypad 3.  Speakup says:
+"keypad 3 is character, say next."
+The message "character, say next" names a Speakup function, and it
+comes from this function_names file.
+
+* key_names:
+Again, key_names is used by Speakup's help system.  In the previous
+example, Speakup said that you pressed "keypad 3."
+This name came from the key_names file.
+
+* states:
+This file contains names for key states.
+Again, these are part of the help system.  For instance, if you had pressed
+speakup + keypad 3, you would hear:
+"speakup keypad 3 is go to bottom edge."
+The speakup key is depressed, so the name of the key state is speakup.
+This part of the message comes from the states collection.
+
+14.2.  Loading Your Own Messages
+
+The files under the i18n subdirectory all follow the same format.
+They consist of lines, with one message per line.
+Each message is represented by a number, followed by the text of the message.
+The number is the position of the message in the given collection.
+For example, if you view the file /speakup/i18n/colors, you will see the
+following list:
+
+0      black
+1      blue
+2      green
+3      cyan
+4      red
+5      magenta
+6      yellow
+7      white
+8      grey
+
+You can change one message, or you can change a whole group.
+To load a whole collection of messages from a new source, simply use
+the cp command:
+cp ~/my_colors /speakup/i18n/colors
+You can change an individual message with the echo command,
+as shown in the following example.
+
+The Spanish name for the color blue is azul.
+Looking at the colors file, we see that the name "blue" is at position 1
+within the colors group.  Let's change blue to azul:
+echo '1 azul' > /speakup/i18n/colors
+The next time that Speakup says message 1 from the colors group, it will
+say "azul", rather than "blue."
+
+In the future, translations into various languages will be made available,
+and most users will just load the files necessary for their language.
+
+14.3.  No Support for Non-Western-European Languages
+
+As of the current release, Speakup only supports Western European languages.
+Support for the extended characters used by languages outside of the Western
+European family of languages is a work in progress.
+
+15.  Using Speakup's Windowing Capability
+
+Speakup has the capability of defining and manipulating windows on the
+screen.  Speakup uses the term "Window", to mean a user defined area of
+the screen.  The key strokes for defining and manipulating Speakup
+windows are as follows:
+
+speakup + f2 -- Set the bounds of the window.
+Speakup + f3 -- clear the current window definition.
+speakup + f4 -- Toggle window silence on and off.
+speakup + keypad plus -- Say the currently defined window.
+
+These capabilities are useful for tracking a certain part of the screen
+without rereading the whole screen, or for silencing a part of the
+screen that is constantly changing, such as a clock or status line.
+
+There is no way to save these window settings, and you can only have one
+window defined for each virtual console.  There is also no way to have
+windows automatically defined for specific applications.
+
+In order to define a window, use the review keys to move your reading
+cursor to the beginning of the area you want to define.  Then press
+speakup + f2.  Speakup will tell you that the window starts at the
+indicated row and column position.  Then move the reading cursor to the
+end of the area to be defined as a window, and press speakup + f2 again.
+ If there is more than one line in the window, Speakup will tell you
+that the window ends at the indicated row and column position.  If there
+is only one line in the window, then Speakup will tell you that the
+window is the specified line on the screen.  If you are only defining a
+one line window, you can just press speakup + f2 twice after placing the
+reading cursor on the line you want to define as a window.  It is not
+necessary to position the reading cursor at the end of the line in order
+to define the whole line as a window.
+
+16.  Tools for Controlling Speakup
+
+The speakup distribution includes extra tools (in the tools directory)
+which were written to make speakup easier to use.  This section will
+briefly describe the use of these tools.
+
+16.1.  Speakupconf
+
+speakupconf began life as a contribution from Steve Holmes, a member of
+the speakup community.  We would like to thank him for his work on the
+early versions of this project.
+
+This script may be installed as part of your linux distribution, but if
+it isn't, the recommended places to put it are /usr/local/bin or
+/usr/bin.  This script can be run by any user, so it does not require
+root privileges.
+
+Speakupconf allows you to save and load your Speakup settings.  It works
+by reading and writing the /sys files described above.
+
+The directory that speakupconf uses to store your settings depends on
+whether it is run from the root account.  If you execute speakupconf as
+root, it uses the directory /etc/speakup.  Otherwise, it uses the directory
+~/.speakup, where ~ is your home directory.
+Anyone who needs to use Speakup from your console can load his own custom
+settings with this script.
+
+speakupconf takes one required argument: load or save.
+Use the command
+speakupconf save
+to save your Speakup settings, and
+speakupconf load
+to load them into Speakup.
+A second argument may be specified to use an alternate directory to
+load or save the speakup parameters.
+
+16.2.  Talkwith
+
+Charles Hallenbeck, another member of the speakup community, wrote the
+initial versions of this script, and we would also like to thank him for
+his work on it.
+
+This script needs root privileges to run, so if it is not installed as
+part of your linux distribution, the recommended places to install it
+are /usr/local/sbin or /usr/sbin.
+
+Talkwith allows you to switch synthesizers on the fly.  It takes a synthesizer
+name as an argument.  For instance,
+talkwith dectlk
+causes Speakup to use the DecTalk Express.  If you wish to switch to a
+software synthesizer, you must also indicate which daemon you wish to
+use.  There are two possible choices:
+spd and espeakup.  spd is an abbreviation for speechd-up.
+If you wish to use espeakup for software synthesis, give the command
+talkwith soft espeakup
+To use speechd-up, type:
+talkwith soft spd
+Any arguments that follow the name of the daemon are passed to the daemon
+when it is invoked.  For instance:
+talkwith espeakup --default-voice=fr
+causes espeakup to use the French voice.
+Note that talkwith must always be executed with root privileges.
+
+Talkwith does not attempt to load your settings after the new
+synthesizer is activated.  You can use speakupconf to load your settings
+if desired.
+
+                GNU Free Documentation License
+                  Version 1.2, November 2002
+
+
+ Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The "Document", below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as "you".  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject.  (Thus, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification.  Examples of
+transparent image formats include PNG, XCF and JPG.  Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".)  To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+   from that of the Document, and from those of previous versions
+   (which should, if there were any, be listed in the History section
+   of the Document).  You may use the same title as a previous version
+   if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+   responsible for authorship of the modifications in the Modified
+   Version, together with at least five of the principal authors of the
+   Document (all of its principal authors, if it has fewer than five),
+   unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+   Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+   adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+   giving the public permission to use the Modified Version under the
+   terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+   and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+   to it an item stating at least the title, year, new authors, and
+   publisher of the Modified Version as given on the Title Page.  If
+   there is no section Entitled "History" in the Document, create one
+   stating the title, year, authors, and publisher of the Document as
+   given on its Title Page, then add an item describing the Modified
+   Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+   public access to a Transparent copy of the Document, and likewise
+   the network locations given in the Document for previous versions
+   it was based on.  These may be placed in the "History" section.
+   You may omit a network location for a work that was published at
+   least four years before the Document itself, or if the original
+   publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+   Preserve the Title of the section, and preserve in the section all
+   the substance and tone of each of the contributor acknowledgements
+   and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+   unaltered in their text and in their titles.  Section numbers
+   or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements".  Such a section
+   may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+   or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications".  You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License.  Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License.  However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time.  Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.  See
+https://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+    Copyright (c)  YEAR  YOUR NAME.
+    Permission is granted to copy, distribute and/or modify this document
+    under the terms of the GNU Free Documentation License, Version 1.2
+    or any later version published by the Free Software Foundation;
+    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+    A copy of the license is included in the section entitled "GNU
+    Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+    with the Invariant Sections being LIST THEIR TITLES, with the
+    Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+
+The End.
index 8d5294b..49a29c5 100644 (file)
@@ -16100,6 +16100,16 @@ Q:     https://patchwork.kernel.org/project/linux-sparse/list/
 B:     https://bugzilla.kernel.org/enter_bug.cgi?component=Sparse&product=Tools
 F:     include/linux/compiler.h
 
+SPEAKUP CONSOLE SPEECH DRIVER
+M:     William Hubbs <w.d.hubbs@gmail.com>
+M:     Chris Brannon <chris@the-brannons.com>
+M:     Kirk Reiser <kirk@reisers.ca>
+M:     Samuel Thibault <samuel.thibault@ens-lyon.org>
+L:     speakup@linux-speakup.org
+S:     Odd Fixes
+W:     http://www.linux-speakup.org/
+F:     drivers/accessibility/speakup/
+
 SPEAR CLOCK FRAMEWORK SUPPORT
 M:     Viresh Kumar <vireshk@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -16287,16 +16297,6 @@ L:     linux-fbdev@vger.kernel.org
 S:     Maintained
 F:     drivers/staging/sm750fb/
 
-STAGING - SPEAKUP CONSOLE SPEECH DRIVER
-M:     William Hubbs <w.d.hubbs@gmail.com>
-M:     Chris Brannon <chris@the-brannons.com>
-M:     Kirk Reiser <kirk@reisers.ca>
-M:     Samuel Thibault <samuel.thibault@ens-lyon.org>
-L:     speakup@linux-speakup.org
-S:     Odd Fixes
-W:     http://www.linux-speakup.org/
-F:     drivers/staging/speakup/
-
 STAGING - VIA VT665X DRIVERS
 M:     Forest Bond <forest@alittletooquiet.net>
 S:     Odd Fixes
index f10c17d..6b2f79d 100644 (file)
@@ -31,4 +31,6 @@ config A11Y_BRAILLE_CONSOLE
 
          If unsure, say N.
 
+source "drivers/accessibility/speakup/Kconfig"
+
 endif # ACCESSIBILITY
index e8c182f..8336030 100644 (file)
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-y                          += braille/
+obj-$(CONFIG_SPEAKUP)          += speakup/
diff --git a/drivers/accessibility/speakup/DefaultKeyAssignments b/drivers/accessibility/speakup/DefaultKeyAssignments
new file mode 100644 (file)
index 0000000..101c803
--- /dev/null
@@ -0,0 +1,46 @@
+This file is intended to give you an overview of the default keys used
+by speakup for it's review functions.  You may change them to be
+anything you want but that will take some familiarity with key
+mapping.
+
+We have remapped the insert or zero key on the keypad to act as a
+shift key.  Well, actually as an altgr key.  So in the following list
+InsKeyPad-period means hold down the insert key like a shift key and
+hit the keypad period.
+
+KeyPad-8               Say current Line
+InsKeyPad-8            say from top of screen to reading cursor.
+KeyPad-7               Say Previous Line (UP one line)
+KeyPad-9               Say Next Line (down one line)
+KeyPad-5               Say Current Word
+InsKeyPad-5            Spell Current Word
+KeyPad-4               Say Previous Word (left one word)
+InsKeyPad-4            say from left edge of line to reading cursor.
+KeyPad-6               Say Next Word (right one word)
+InsKeyPad-6            Say from reading cursor to right edge of line.
+KeyPad-2               Say Current Letter
+InsKeyPad-2            say current letter phonetically
+KeyPad-1               Say Previous Character (left one letter)
+KeyPad-3               Say Next Character (right one letter)
+KeyPad-plus            Say Entire Screen
+InsKeyPad-plus         Say from reading cursor line to bottom of screen.
+KeyPad-Minus           Park reading cursor (toggle)
+InsKeyPad-minus                Say character hex and decimal value.
+KeyPad-period          Say Position (current line, position and console)
+InsKeyPad-period       say colour attributes of current position.
+InsKeyPad-9            Move reading cursor to top of screen (insert pgup)
+InsKeyPad-3            Move reading cursor to bottom of screen (insert pgdn)
+InsKeyPad-7            Move reading cursor to left edge of screen (insert home)
+InsKeyPad-1            Move reading cursor to right edge of screen (insert end)
+ControlKeyPad-1                Move reading cursor to last character on current line.
+KeyPad-Enter           Shut Up (until another key is hit) and sync reading cursor
+InsKeyPad-Enter                Shut Up (until toggled back on).
+InsKeyPad-star n<x|y>  go to line (y) or column (x). Where 'n' is any
+               allowed value for the row or column for your current screen.
+KeyPad-/               Mark and Cut screen region.
+InsKeyPad-/            Paste screen region into any console.
+
+Hitting any key while speakup is outputting speech will quiet the
+synth until it has caught up with what is being printed on the
+console.
+
diff --git a/drivers/accessibility/speakup/Kconfig b/drivers/accessibility/speakup/Kconfig
new file mode 100644 (file)
index 0000000..0803c20
--- /dev/null
@@ -0,0 +1,200 @@
+# SPDX-License-Identifier: GPL-2.0
+menu "Speakup console speech"
+
+config SPEAKUP
+       depends on VT
+       tristate "Speakup core"
+       help
+               This is the Speakup screen reader.  Think of it as a
+               video console for blind people.  If built in to the
+               kernel, it can speak everything on the text console from
+               boot up to shutdown.  For more information on Speakup,
+               point your browser at <http://www.linux-speakup.org/>.
+               There is also a mailing list at the above url that you
+               can subscribe to.
+
+               Supported synthesizers are accent sa, accent pc,
+               appollo II., Auddapter, Braille 'n Speak, Dectalk
+               external (old), Dectalk PC (full length isa board),
+               Dectalk express, Doubletalk, Doubletalk LT or
+               Litetalk, Keynote Gold internal PC, software
+               synthesizers, Speakout, transport, and a dummy module
+               that can be used with a plain text terminal.
+
+               Speakup can either be built in or compiled as a module
+               by answering y or m.  If you answer y here, then you
+               must answer either y or m to at least one of the
+               synthesizer drivers below.  If you answer m here, then
+               the synthesizer drivers below can only be built as
+               modules.
+
+               These drivers are not standalone drivers, but must be
+               used in conjunction with Speakup.  Think of them as
+               video cards for blind people.
+
+
+               The Dectalk pc driver can only be built as a module, and
+               requires software to be pre-loaded on to the card before
+               the module can be loaded.  See the decpc choice below
+               for more details.
+
+               If you are not a blind person, or don't have access to
+               one of the listed synthesizers, you should say n.
+
+if SPEAKUP
+config SPEAKUP_SYNTH_ACNTSA
+       tristate "Accent SA synthesizer support"
+       help
+               This is the Speakup driver for the Accent SA
+               synthesizer.  You can say y to build it into the kernel,
+               or m to build it as a module.  See the configuration
+               help on the Speakup choice above for more info.
+
+config SPEAKUP_SYNTH_ACNTPC
+       tristate "Accent PC synthesizer support"
+       depends on ISA || COMPILE_TEST
+       help
+               This is the Speakup driver for the accent pc
+               synthesizer.  You can say y to build it into the kernel,
+               or m to build it as a module.  See the configuration
+               help on the Speakup choice above for more info.
+
+config SPEAKUP_SYNTH_APOLLO
+       tristate "Apollo II synthesizer support"
+       help
+               This is the Speakup driver for the Apollo II
+               synthesizer.  You can say y to build it into the kernel,
+               or m to build it as a module.  See the configuration
+               help on the Speakup choice above for more info.
+
+config SPEAKUP_SYNTH_AUDPTR
+       tristate "Audapter synthesizer support"
+       help
+               This is the Speakup driver for the Audapter synthesizer.
+                You can say y to build it into the kernel, or m to
+               build it as a module.  See the configuration help on the
+               Speakup choice above for more info.
+
+config SPEAKUP_SYNTH_BNS
+       tristate "Braille 'n' Speak synthesizer support"
+       help
+               This is the Speakup driver for the Braille 'n' Speak
+               synthesizer.  You can say y to build it into the kernel,
+               or m to build it as a module.  See the configuration
+               help on the Speakup choice above for more info.
+
+config SPEAKUP_SYNTH_DECTLK
+       tristate "DECtalk Express synthesizer support"
+       help
+
+               This is the Speakup driver for the DecTalk Express
+               synthesizer.  You can say y to build it into the kernel,
+               or m to build it as a module.  See the configuration
+               help on the Speakup choice above for more info.
+
+config SPEAKUP_SYNTH_DECEXT
+       tristate "DECtalk External (old) synthesizer support"
+       help
+
+               This is the Speakup driver for the DecTalk External
+               (old) synthesizer.  You can say y to build it into the
+               kernel, or m to build it as a module.  See the
+               configuration help on the Speakup choice above for more
+               info.
+
+config SPEAKUP_SYNTH_DECPC
+       depends on m
+       depends on ISA || COMPILE_TEST
+       tristate "DECtalk PC (big ISA card) synthesizer support"
+       help
+
+               This is the Speakup driver for the DecTalk PC (full
+               length ISA) synthesizer.  You can say m to build it as
+               a module.  See the configuration help on the Speakup
+               choice above for more info.
+
+               In order to use the DecTalk PC driver, you must download
+               the dec_pc.tgz file from linux-speakup.org.  It is in
+               the pub/linux/goodies directory.  The dec_pc.tgz file
+               contains the software which must be pre-loaded on to the
+               DecTalk PC board in order to use it with this driver.
+               This driver must be built as a module, and can not be
+               loaded until the file system is mounted and the DecTalk
+               PC software has been pre-loaded on to the board.
+
+               See the README file in the dec_pc.tgz file for more
+               details.
+
+config SPEAKUP_SYNTH_DTLK
+       tristate "DoubleTalk PC synthesizer support"
+       depends on ISA || COMPILE_TEST
+       help
+
+               This is the Speakup driver for the internal DoubleTalk
+               PC synthesizer.  You can say y to build it into the
+               kernel, or m to build it as a module.  See the
+               configuration help on the Speakup choice above for more
+               info.
+
+config SPEAKUP_SYNTH_KEYPC
+       tristate "Keynote Gold PC synthesizer support"
+       depends on ISA || COMPILE_TEST
+       help
+
+               This is the Speakup driver for the Keynote Gold
+               PC synthesizer.  You can say y to build it into the
+               kernel, or m to build it as a module.  See the
+               configuration help on the Speakup choice above for more
+               info.
+
+config SPEAKUP_SYNTH_LTLK
+       tristate "DoubleTalk LT/LiteTalk synthesizer support"
+help
+
+               This is the Speakup driver for the LiteTalk/DoubleTalk
+               LT synthesizer.  You can say y to build it into the
+               kernel, or m to build it as a module.  See the
+               configuration help on the Speakup choice above for more
+               info.
+
+config SPEAKUP_SYNTH_SOFT
+       tristate "Userspace software synthesizer support"
+       help
+
+               This is the software synthesizer device node.  It will
+               register a device /dev/softsynth which midware programs
+               and speech daemons may open and read to provide kernel
+               output to software synths such as espeak, festival,
+               flite and so forth.  You can select 'y' or 'm' to have
+               it built-in to the kernel or loaded as a module.
+
+config SPEAKUP_SYNTH_SPKOUT
+       tristate "Speak Out synthesizer support"
+       help
+
+               This is the Speakup driver for the Speakout synthesizer.
+                You can say y to build it into the kernel, or m to
+               build it as a module.  See the configuration help on the
+               Speakup choice above for more info.
+
+config SPEAKUP_SYNTH_TXPRT
+       tristate "Transport synthesizer support"
+       help
+
+               This is the Speakup driver for the Transport
+               synthesizer.  You can say y to build it into the kernel,
+               or m to build it as a module.  See the configuration
+               help on the Speakup choice above for more info.
+
+config SPEAKUP_SYNTH_DUMMY
+       tristate "Dummy synthesizer driver (for testing)"
+       help
+
+               This is a dummy Speakup driver for plugging a mere serial
+               terminal.  This is handy if you want to test speakup but
+               don't have the hardware.  You can say y to build it into
+               the kernel, or m to build it as a module.  See the
+               configuration help on the Speakup choice above for more info.
+
+endif  # SPEAKUP
+endmenu
diff --git a/drivers/accessibility/speakup/Makefile b/drivers/accessibility/speakup/Makefile
new file mode 100644 (file)
index 0000000..5befb49
--- /dev/null
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_SPEAKUP_SYNTH_ACNTSA) += speakup_acntsa.o
+obj-$(CONFIG_SPEAKUP_SYNTH_ACNTPC) += speakup_acntpc.o
+obj-$(CONFIG_SPEAKUP_SYNTH_APOLLO) += speakup_apollo.o
+obj-$(CONFIG_SPEAKUP_SYNTH_AUDPTR) += speakup_audptr.o
+obj-$(CONFIG_SPEAKUP_SYNTH_BNS) += speakup_bns.o
+obj-$(CONFIG_SPEAKUP_SYNTH_DECTLK) += speakup_dectlk.o
+obj-$(CONFIG_SPEAKUP_SYNTH_DECEXT) += speakup_decext.o
+obj-$(CONFIG_SPEAKUP_SYNTH_DECPC) += speakup_decpc.o
+obj-$(CONFIG_SPEAKUP_SYNTH_DTLK) += speakup_dtlk.o
+obj-$(CONFIG_SPEAKUP_SYNTH_KEYPC) += speakup_keypc.o
+obj-$(CONFIG_SPEAKUP_SYNTH_LTLK) += speakup_ltlk.o
+obj-$(CONFIG_SPEAKUP_SYNTH_SOFT) += speakup_soft.o
+obj-$(CONFIG_SPEAKUP_SYNTH_SPKOUT) += speakup_spkout.o
+obj-$(CONFIG_SPEAKUP_SYNTH_TXPRT) += speakup_txprt.o
+obj-$(CONFIG_SPEAKUP_SYNTH_DUMMY) += speakup_dummy.o
+
+obj-$(CONFIG_SPEAKUP) += speakup.o
+speakup-y := \
+       buffers.o \
+       devsynth.o \
+       i18n.o \
+       fakekey.o \
+       main.o \
+       keyhelp.o \
+       kobjects.o \
+       selection.o \
+       serialio.o \
+       spk_ttyio.o \
+       synth.o \
+       thread.o \
+       varhandlers.o
diff --git a/drivers/accessibility/speakup/TODO b/drivers/accessibility/speakup/TODO
new file mode 100644 (file)
index 0000000..d4ca093
--- /dev/null
@@ -0,0 +1,22 @@
+Speakup project home:  http://www.linux-speakup.org
+
+Mailing List:  speakup@linux-speakup.org
+
+Speakup is a kernel based screen review package for the linux operating
+system.  It allows blind users to interact with applications on the
+linux console by means of synthetic speech.
+
+Currently, speakup has one issue we know of.
+
+It seems to only happen on SMP systems. It seems that text in the output buffer
+gets garbled because a lock is not set. This bug happens regularly, but no one
+has been able to find a situation which produces it consistently.
+
+Patches, suggestions, corrections, etc, are definitely welcome.
+
+We prefer that you contact us on the mailing list; however, if you do
+not want to subscribe to a mailing list, send your email to all of the
+following:
+
+okash.khawaja@gmail.com, w.d.hubbs@gmail.com, chris@the-brannons.com,
+kirk@reisers.ca and samuel.thibault@ens-lyon.org.
diff --git a/drivers/accessibility/speakup/buffers.c b/drivers/accessibility/speakup/buffers.c
new file mode 100644 (file)
index 0000000..1371ced
--- /dev/null
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/console.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include "speakup.h"
+#include "spk_priv.h"
+
+#define SYNTH_BUF_SIZE 8192    /* currently 8K bytes */
+
+static u16 synth_buffer[SYNTH_BUF_SIZE];       /* guess what this is for! */
+static u16 *buff_in = synth_buffer;
+static u16 *buff_out = synth_buffer;
+static u16 *buffer_end = synth_buffer + SYNTH_BUF_SIZE - 1;
+
+/* These try to throttle applications by stopping the TTYs
+ * Note: we need to make sure that we will restart them eventually, which is
+ * usually not possible to do from the notifiers. TODO: it should be possible
+ * starting from linux 2.6.26.
+ *
+ * So we only stop when we know alive == 1 (else we discard the data anyway),
+ * and the alive synth will eventually call start_ttys from the thread context.
+ */
+void speakup_start_ttys(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (speakup_console[i] && speakup_console[i]->tty_stopped)
+                       continue;
+               if (vc_cons[i].d && vc_cons[i].d->port.tty)
+                       start_tty(vc_cons[i].d->port.tty);
+       }
+}
+EXPORT_SYMBOL_GPL(speakup_start_ttys);
+
+static void speakup_stop_ttys(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               if (vc_cons[i].d && vc_cons[i].d->port.tty)
+                       stop_tty(vc_cons[i].d->port.tty);
+}
+
+static int synth_buffer_free(void)
+{
+       int chars_free;
+
+       if (buff_in >= buff_out)
+               chars_free = SYNTH_BUF_SIZE - (buff_in - buff_out);
+       else
+               chars_free = buff_out - buff_in;
+       return chars_free;
+}
+
+int synth_buffer_empty(void)
+{
+       return (buff_in == buff_out);
+}
+EXPORT_SYMBOL_GPL(synth_buffer_empty);
+
+void synth_buffer_add(u16 ch)
+{
+       if (!synth->alive) {
+               /* This makes sure that we won't stop TTYs if there is no synth
+                * to restart them
+                */
+               return;
+       }
+       if (synth_buffer_free() <= 100) {
+               synth_start();
+               speakup_stop_ttys();
+       }
+       if (synth_buffer_free() <= 1)
+               return;
+       *buff_in++ = ch;
+       if (buff_in > buffer_end)
+               buff_in = synth_buffer;
+       /* We have written something to the speech synthesis, so we are not
+        * paused any more.
+        */
+       spk_paused = false;
+}
+
+u16 synth_buffer_getc(void)
+{
+       u16 ch;
+
+       if (buff_out == buff_in)
+               return 0;
+       ch = *buff_out++;
+       if (buff_out > buffer_end)
+               buff_out = synth_buffer;
+       return ch;
+}
+EXPORT_SYMBOL_GPL(synth_buffer_getc);
+
+u16 synth_buffer_peek(void)
+{
+       if (buff_out == buff_in)
+               return 0;
+       return *buff_out;
+}
+EXPORT_SYMBOL_GPL(synth_buffer_peek);
+
+void synth_buffer_skip_nonlatin1(void)
+{
+       while (buff_out != buff_in) {
+               if (*buff_out < 0x100)
+                       return;
+               buff_out++;
+               if (buff_out > buffer_end)
+                       buff_out = synth_buffer;
+       }
+}
+EXPORT_SYMBOL_GPL(synth_buffer_skip_nonlatin1);
+
+void synth_buffer_clear(void)
+{
+       buff_in = synth_buffer;
+       buff_out = synth_buffer;
+}
+EXPORT_SYMBOL_GPL(synth_buffer_clear);
diff --git a/drivers/accessibility/speakup/devsynth.c b/drivers/accessibility/speakup/devsynth.c
new file mode 100644 (file)
index 0000000..d305716
--- /dev/null
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/errno.h>
+#include <linux/miscdevice.h>  /* for misc_register, and MISC_DYNAMIC_MINOR */
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+#include "speakup.h"
+#include "spk_priv.h"
+
+static int misc_registered;
+static int dev_opened;
+
+static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,
+                                 size_t nbytes, loff_t *ppos)
+{
+       size_t count = nbytes;
+       const char __user *ptr = buffer;
+       size_t bytes;
+       unsigned long flags;
+       u_char buf[256];
+
+       if (!synth)
+               return -ENODEV;
+       while (count > 0) {
+               bytes = min(count, sizeof(buf));
+               if (copy_from_user(buf, ptr, bytes))
+                       return -EFAULT;
+               count -= bytes;
+               ptr += bytes;
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               synth_write(buf, bytes);
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       }
+       return (ssize_t)nbytes;
+}
+
+static ssize_t speakup_file_read(struct file *fp, char __user *buf,
+                                size_t nbytes, loff_t *ppos)
+{
+       return 0;
+}
+
+static int speakup_file_open(struct inode *ip, struct file *fp)
+{
+       if (!synth)
+               return -ENODEV;
+       if (xchg(&dev_opened, 1))
+               return -EBUSY;
+       return 0;
+}
+
+static int speakup_file_release(struct inode *ip, struct file *fp)
+{
+       dev_opened = 0;
+       return 0;
+}
+
+static const struct file_operations synth_fops = {
+       .read = speakup_file_read,
+       .write = speakup_file_write,
+       .open = speakup_file_open,
+       .release = speakup_file_release,
+};
+
+static struct miscdevice synth_device = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "synth",
+       .fops = &synth_fops,
+};
+
+void speakup_register_devsynth(void)
+{
+       if (misc_registered != 0)
+               return;
+/* zero it so if register fails, deregister will not ref invalid ptrs */
+       if (misc_register(&synth_device)) {
+               pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
+       } else {
+               pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
+                       MISC_MAJOR, synth_device.minor);
+               misc_registered = 1;
+       }
+}
+
+void speakup_unregister_devsynth(void)
+{
+       if (!misc_registered)
+               return;
+       pr_info("speakup: unregistering synth device /dev/synth\n");
+       misc_deregister(&synth_device);
+       misc_registered = 0;
+}
diff --git a/drivers/accessibility/speakup/fakekey.c b/drivers/accessibility/speakup/fakekey.c
new file mode 100644 (file)
index 0000000..cd02996
--- /dev/null
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* fakekey.c
+ * Functions for simulating keypresses.
+ *
+ * Copyright (C) 2010 the Speakup Team
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/preempt.h>
+#include <linux/percpu.h>
+#include <linux/input.h>
+
+#include "speakup.h"
+
+#define PRESSED 1
+#define RELEASED 0
+
+static DEFINE_PER_CPU(int, reporting_keystroke);
+
+static struct input_dev *virt_keyboard;
+
+int speakup_add_virtual_keyboard(void)
+{
+       int err;
+
+       virt_keyboard = input_allocate_device();
+
+       if (!virt_keyboard)
+               return -ENOMEM;
+
+       virt_keyboard->name = "Speakup";
+       virt_keyboard->id.bustype = BUS_VIRTUAL;
+       virt_keyboard->phys = "speakup/input0";
+       virt_keyboard->dev.parent = NULL;
+
+       __set_bit(EV_KEY, virt_keyboard->evbit);
+       __set_bit(KEY_DOWN, virt_keyboard->keybit);
+
+       err = input_register_device(virt_keyboard);
+       if (err) {
+               input_free_device(virt_keyboard);
+               virt_keyboard = NULL;
+       }
+
+       return err;
+}
+
+void speakup_remove_virtual_keyboard(void)
+{
+       if (virt_keyboard) {
+               input_unregister_device(virt_keyboard);
+               virt_keyboard = NULL;
+       }
+}
+
+/*
+ * Send a simulated down-arrow to the application.
+ */
+void speakup_fake_down_arrow(void)
+{
+       unsigned long flags;
+
+       /* disable keyboard interrupts */
+       local_irq_save(flags);
+       /* don't change CPU */
+       preempt_disable();
+
+       __this_cpu_write(reporting_keystroke, true);
+       input_report_key(virt_keyboard, KEY_DOWN, PRESSED);
+       input_report_key(virt_keyboard, KEY_DOWN, RELEASED);
+       input_sync(virt_keyboard);
+       __this_cpu_write(reporting_keystroke, false);
+
+       /* reenable preemption */
+       preempt_enable();
+       /* reenable keyboard interrupts */
+       local_irq_restore(flags);
+}
+
+/*
+ * Are we handling a simulated keypress on the current CPU?
+ * Returns a boolean.
+ */
+bool speakup_fake_key_pressed(void)
+{
+       return this_cpu_read(reporting_keystroke);
+}
diff --git a/drivers/accessibility/speakup/i18n.c b/drivers/accessibility/speakup/i18n.c
new file mode 100644 (file)
index 0000000..ee240d3
--- /dev/null
@@ -0,0 +1,625 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Internationalization implementation.  Includes definitions of English
+ * string arrays, and the i18n pointer.
+ */
+
+#include <linux/slab.h>                /* For kmalloc. */
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include "speakup.h"
+#include "spk_priv.h"
+
+static char *speakup_msgs[MSG_LAST_INDEX];
+static char *speakup_default_msgs[MSG_LAST_INDEX] = {
+       [MSG_BLANK] = "blank",
+       [MSG_IAM_ALIVE] = "I'm aLive!",
+       [MSG_YOU_KILLED_SPEAKUP] = "You killed speakup!",
+       [MSG_HEY_THATS_BETTER] = "hey. That's better!",
+       [MSG_YOU_TURNED_ME_OFF] = "You turned me off!",
+       [MSG_PARKED] = "parked!",
+       [MSG_UNPARKED] = "unparked!",
+       [MSG_MARK] = "mark",
+       [MSG_CUT] = "cut",
+       [MSG_MARK_CLEARED] = "mark, cleared",
+       [MSG_PASTE] = "paste",
+       [MSG_BRIGHT] = "bright",
+       [MSG_ON_BLINKING] = "on blinking",
+       [MSG_OFF] = "off",
+       [MSG_ON] = "on",
+       [MSG_NO_WINDOW] = "no window",
+       [MSG_CURSORING_OFF] = "cursoring off",
+       [MSG_CURSORING_ON] = "cursoring on",
+       [MSG_HIGHLIGHT_TRACKING] = "highlight tracking",
+       [MSG_READ_WINDOW] = "read windo",
+       [MSG_READ_ALL] = "read all",
+       [MSG_EDIT_DONE] = "edit done",
+       [MSG_WINDOW_ALREADY_SET] = "window already set, clear then reset",
+       [MSG_END_BEFORE_START] = "error end before start",
+       [MSG_WINDOW_CLEARED] = "window cleared",
+       [MSG_WINDOW_SILENCED] = "window silenced",
+       [MSG_WINDOW_SILENCE_DISABLED] = "window silence disabled",
+       [MSG_ERROR] = "error",
+       [MSG_GOTO_CANCELED] = "goto canceled",
+       [MSG_GOTO] = "go to?",
+       [MSG_LEAVING_HELP] = "leaving help",
+       [MSG_IS_UNASSIGNED] = "is unassigned",
+       [MSG_HELP_INFO] =
+       "press space to exit, up or down to scroll, or a letter to go to a command",
+       [MSG_EDGE_TOP] = "top,",
+       [MSG_EDGE_BOTTOM] = "bottom,",
+       [MSG_EDGE_LEFT] = "left,",
+       [MSG_EDGE_RIGHT] = "right,",
+       [MSG_NUMBER] = "number",
+       [MSG_SPACE] = "space",
+       [MSG_START] = "start",
+       [MSG_END] = "end",
+       [MSG_CTRL] = "control-",
+       [MSG_DISJUNCTION] = "or",
+
+/* Messages with embedded format specifiers. */
+       [MSG_POS_INFO] = "line %ld, col %ld, t t y %d",
+       [MSG_CHAR_INFO] = "hex %02x, decimal %d",
+       [MSG_REPEAT_DESC] = "times %d .",
+       [MSG_REPEAT_DESC2] = "repeated %d .",
+       [MSG_WINDOW_LINE] = "window is line %d",
+       [MSG_WINDOW_BOUNDARY] = "%s at line %d, column %d",
+       [MSG_EDIT_PROMPT] = "edit  %s, press space when done",
+       [MSG_NO_COMMAND] = "no commands for %c",
+       [MSG_KEYDESC] = "is %s",
+
+       /* Control keys. */
+       /* Most of these duplicate the entries in state names. */
+       [MSG_CTL_SHIFT] = "shift",
+       [MSG_CTL_ALTGR] = "altgr",
+       [MSG_CTL_CONTROL] = "control",
+       [MSG_CTL_ALT] = "alt",
+       [MSG_CTL_LSHIFT] = "l shift",
+       [MSG_CTL_SPEAKUP] = "speakup",
+       [MSG_CTL_LCONTROL] = "l control",
+       [MSG_CTL_RCONTROL] = "r control",
+       [MSG_CTL_CAPSSHIFT] = "caps shift",
+
+       /* Color names. */
+       [MSG_COLOR_BLACK] = "black",
+       [MSG_COLOR_BLUE] = "blue",
+       [MSG_COLOR_GREEN] = "green",
+       [MSG_COLOR_CYAN] = "cyan",
+       [MSG_COLOR_RED] = "red",
+       [MSG_COLOR_MAGENTA] = "magenta",
+       [MSG_COLOR_YELLOW] = "yellow",
+       [MSG_COLOR_WHITE] = "white",
+       [MSG_COLOR_GREY] = "grey",
+
+       /* Names of key states. */
+       [MSG_STATE_DOUBLE] = "double",
+       [MSG_STATE_SPEAKUP] = "speakup",
+       [MSG_STATE_ALT] = "alt",
+       [MSG_STATE_CONTROL] = "ctrl",
+       [MSG_STATE_ALTGR] = "altgr",
+       [MSG_STATE_SHIFT] = "shift",
+
+       /* Key names. */
+       [MSG_KEYNAME_ESC] = "escape",
+       [MSG_KEYNAME_1] = "1",
+       [MSG_KEYNAME_2] = "2",
+       [MSG_KEYNAME_3] = "3",
+       [MSG_KEYNAME_4] = "4",
+       [MSG_KEYNAME_5] = "5",
+       [MSG_KEYNAME_6] = "6",
+       [MSG_KEYNAME_7] = "7",
+       [MSG_KEYNAME_8] = "8",
+       [MSG_KEYNAME_9] = "9",
+       [MSG_KEYNAME_0] = "0",
+       [MSG_KEYNAME_DASH] = "minus",
+       [MSG_KEYNAME_EQUAL] = "equal",
+       [MSG_KEYNAME_BS] = "back space",
+       [MSG_KEYNAME_TAB] = "tab",
+       [MSG_KEYNAME_Q] = "q",
+       [MSG_KEYNAME_W] = "w",
+       [MSG_KEYNAME_E] = "e",
+       [MSG_KEYNAME_R] = "r",
+       [MSG_KEYNAME_T] = "t",
+       [MSG_KEYNAME_Y] = "y",
+       [MSG_KEYNAME_U] = "u",
+       [MSG_KEYNAME_I] = "i",
+       [MSG_KEYNAME_O] = "o",
+       [MSG_KEYNAME_P] = "p",
+       [MSG_KEYNAME_LEFTBRACE] = "left brace",
+       [MSG_KEYNAME_RIGHTBRACE] = "right brace",
+       [MSG_KEYNAME_ENTER] = "enter",
+       [MSG_KEYNAME_LEFTCTRL] = "left control",
+       [MSG_KEYNAME_A] = "a",
+       [MSG_KEYNAME_S] = "s",
+       [MSG_KEYNAME_D] = "d",
+       [MSG_KEYNAME_F] = "f",
+       [MSG_KEYNAME_G] = "g",
+       [MSG_KEYNAME_H] = "h",
+       [MSG_KEYNAME_J] = "j",
+       [MSG_KEYNAME_K] = "k",
+       [MSG_KEYNAME_L] = "l",
+       [MSG_KEYNAME_SEMICOLON] = "semicolon",
+       [MSG_KEYNAME_SINGLEQUOTE] = "apostrophe",
+       [MSG_KEYNAME_GRAVE] = "accent",
+       [MSG_KEYNAME_LEFTSHFT] = "left shift",
+       [MSG_KEYNAME_BACKSLASH] = "back slash",
+       [MSG_KEYNAME_Z] = "z",
+       [MSG_KEYNAME_X] = "x",
+       [MSG_KEYNAME_C] = "c",
+       [MSG_KEYNAME_V] = "v",
+       [MSG_KEYNAME_B] = "b",
+       [MSG_KEYNAME_N] = "n",
+       [MSG_KEYNAME_M] = "m",
+       [MSG_KEYNAME_COMMA] = "comma",
+       [MSG_KEYNAME_DOT] = "dot",
+       [MSG_KEYNAME_SLASH] = "slash",
+       [MSG_KEYNAME_RIGHTSHFT] = "right shift",
+       [MSG_KEYNAME_KPSTAR] = "keypad asterisk",
+       [MSG_KEYNAME_LEFTALT] = "left alt",
+       [MSG_KEYNAME_SPACE] = "space",
+       [MSG_KEYNAME_CAPSLOCK] = "caps lock",
+       [MSG_KEYNAME_F1] = "f1",
+       [MSG_KEYNAME_F2] = "f2",
+       [MSG_KEYNAME_F3] = "f3",
+       [MSG_KEYNAME_F4] = "f4",
+       [MSG_KEYNAME_F5] = "f5",
+       [MSG_KEYNAME_F6] = "f6",
+       [MSG_KEYNAME_F7] = "f7",
+       [MSG_KEYNAME_F8] = "f8",
+       [MSG_KEYNAME_F9] = "f9",
+       [MSG_KEYNAME_F10] = "f10",
+       [MSG_KEYNAME_NUMLOCK] = "num lock",
+       [MSG_KEYNAME_SCROLLLOCK] = "scroll lock",
+       [MSG_KEYNAME_KP7] = "keypad 7",
+       [MSG_KEYNAME_KP8] = "keypad 8",
+       [MSG_KEYNAME_KP9] = "keypad 9",
+       [MSG_KEYNAME_KPMINUS] = "keypad minus",
+       [MSG_KEYNAME_KP4] = "keypad 4",
+       [MSG_KEYNAME_KP5] = "keypad 5",
+       [MSG_KEYNAME_KP6] = "keypad 6",
+       [MSG_KEYNAME_KPPLUS] = "keypad plus",
+       [MSG_KEYNAME_KP1] = "keypad 1",
+       [MSG_KEYNAME_KP2] = "keypad 2",
+       [MSG_KEYNAME_KP3] = "keypad 3",
+       [MSG_KEYNAME_KP0] = "keypad 0",
+       [MSG_KEYNAME_KPDOT] = "keypad dot",
+       [MSG_KEYNAME_103RD] = "103rd",
+       [MSG_KEYNAME_F13] = "f13",
+       [MSG_KEYNAME_102ND] = "102nd",
+       [MSG_KEYNAME_F11] = "f11",
+       [MSG_KEYNAME_F12] = "f12",
+       [MSG_KEYNAME_F14] = "f14",
+       [MSG_KEYNAME_F15] = "f15",
+       [MSG_KEYNAME_F16] = "f16",
+       [MSG_KEYNAME_F17] = "f17",
+       [MSG_KEYNAME_F18] = "f18",
+       [MSG_KEYNAME_F19] = "f19",
+       [MSG_KEYNAME_F20] = "f20",
+       [MSG_KEYNAME_KPENTER] = "keypad enter",
+       [MSG_KEYNAME_RIGHTCTRL] = "right control",
+       [MSG_KEYNAME_KPSLASH] = "keypad slash",
+       [MSG_KEYNAME_SYSRQ] = "sysrq",
+       [MSG_KEYNAME_RIGHTALT] = "right alt",
+       [MSG_KEYNAME_LF] = "line feed",
+       [MSG_KEYNAME_HOME] = "home",
+       [MSG_KEYNAME_UP] = "up",
+       [MSG_KEYNAME_PGUP] = "page up",
+       [MSG_KEYNAME_LEFT] = "left",
+       [MSG_KEYNAME_RIGHT] = "right",
+       [MSG_KEYNAME_END] = "end",
+       [MSG_KEYNAME_DOWN] = "down",
+       [MSG_KEYNAME_PGDN] = "page down",
+       [MSG_KEYNAME_INS] = "insert",
+       [MSG_KEYNAME_DEL] = "delete",
+       [MSG_KEYNAME_MACRO] = "macro",
+       [MSG_KEYNAME_MUTE] = "mute",
+       [MSG_KEYNAME_VOLDOWN] = "volume down",
+       [MSG_KEYNAME_VOLUP] = "volume up",
+       [MSG_KEYNAME_POWER] = "power",
+       [MSG_KEYNAME_KPEQUAL] = "keypad equal",
+       [MSG_KEYNAME_KPPLUSDASH] = "keypad plusminus",
+       [MSG_KEYNAME_PAUSE] = "pause",
+       [MSG_KEYNAME_F21] = "f21",
+       [MSG_KEYNAME_F22] = "f22",
+       [MSG_KEYNAME_F23] = "f23",
+       [MSG_KEYNAME_F24] = "f24",
+       [MSG_KEYNAME_KPCOMMA] = "keypad comma",
+       [MSG_KEYNAME_LEFTMETA] = "left meta",
+       [MSG_KEYNAME_RIGHTMETA] = "right meta",
+       [MSG_KEYNAME_COMPOSE] = "compose",
+       [MSG_KEYNAME_STOP] = "stop",
+       [MSG_KEYNAME_AGAIN] = "again",
+       [MSG_KEYNAME_PROPS] = "props",
+       [MSG_KEYNAME_UNDO] = "undo",
+       [MSG_KEYNAME_FRONT] = "front",
+       [MSG_KEYNAME_COPY] = "copy",
+       [MSG_KEYNAME_OPEN] = "open",
+       [MSG_KEYNAME_PASTE] = "paste",
+       [MSG_KEYNAME_FIND] = "find",
+       [MSG_KEYNAME_CUT] = "cut",
+       [MSG_KEYNAME_HELP] = "help",
+       [MSG_KEYNAME_MENU] = "menu",
+       [MSG_KEYNAME_CALC] = "calc",
+       [MSG_KEYNAME_SETUP] = "setup",
+       [MSG_KEYNAME_SLEEP] = "sleep",
+       [MSG_KEYNAME_WAKEUP] = "wakeup",
+       [MSG_KEYNAME_FILE] = "file",
+       [MSG_KEYNAME_SENDFILE] = "send file",
+       [MSG_KEYNAME_DELFILE] = "delete file",
+       [MSG_KEYNAME_XFER] = "transfer",
+       [MSG_KEYNAME_PROG1] = "prog1",
+       [MSG_KEYNAME_PROG2] = "prog2",
+       [MSG_KEYNAME_WWW] = "www",
+       [MSG_KEYNAME_MSDOS] = "msdos",
+       [MSG_KEYNAME_COFFEE] = "coffee",
+       [MSG_KEYNAME_DIRECTION] = "direction",
+       [MSG_KEYNAME_CYCLEWINDOWS] = "cycle windows",
+       [MSG_KEYNAME_MAIL] = "mail",
+       [MSG_KEYNAME_BOOKMARKS] = "bookmarks",
+       [MSG_KEYNAME_COMPUTER] = "computer",
+       [MSG_KEYNAME_BACK] = "back",
+       [MSG_KEYNAME_FORWARD] = "forward",
+       [MSG_KEYNAME_CLOSECD] = "close cd",
+       [MSG_KEYNAME_EJECTCD] = "eject cd",
+       [MSG_KEYNAME_EJECTCLOSE] = "eject close cd",
+       [MSG_KEYNAME_NEXTSONG] = "next song",
+       [MSG_KEYNAME_PLAYPAUSE] = "play pause",
+       [MSG_KEYNAME_PREVSONG] = "previous song",
+       [MSG_KEYNAME_STOPCD] = "stop cd",
+       [MSG_KEYNAME_RECORD] = "record",
+       [MSG_KEYNAME_REWIND] = "rewind",
+       [MSG_KEYNAME_PHONE] = "phone",
+       [MSG_KEYNAME_ISO] = "iso",
+       [MSG_KEYNAME_CONFIG] = "config",
+       [MSG_KEYNAME_HOMEPG] = "home page",
+       [MSG_KEYNAME_REFRESH] = "refresh",
+       [MSG_KEYNAME_EXIT] = "exit",
+       [MSG_KEYNAME_MOVE] = "move",
+       [MSG_KEYNAME_EDIT] = "edit",
+       [MSG_KEYNAME_SCROLLUP] = "scroll up",
+       [MSG_KEYNAME_SCROLLDN] = "scroll down",
+       [MSG_KEYNAME_KPLEFTPAR] = "keypad left paren",
+       [MSG_KEYNAME_KPRIGHTPAR] = "keypad right paren",
+
+       /* Function names. */
+       [MSG_FUNCNAME_ATTRIB_BLEEP_DEC] = "attribute bleep decrement",
+       [MSG_FUNCNAME_ATTRIB_BLEEP_INC] = "attribute bleep increment",
+       [MSG_FUNCNAME_BLEEPS_DEC] = "bleeps decrement",
+       [MSG_FUNCNAME_BLEEPS_INC] = "bleeps increment",
+       [MSG_FUNCNAME_CHAR_FIRST] = "character, first",
+       [MSG_FUNCNAME_CHAR_LAST] = "character, last",
+       [MSG_FUNCNAME_CHAR_CURRENT] = "character, say current",
+       [MSG_FUNCNAME_CHAR_HEX_AND_DEC] = "character, say hex and decimal",
+       [MSG_FUNCNAME_CHAR_NEXT] = "character, say next",
+       [MSG_FUNCNAME_CHAR_PHONETIC] = "character, say phonetic",
+       [MSG_FUNCNAME_CHAR_PREVIOUS] = "character, say previous",
+       [MSG_FUNCNAME_CURSOR_PARK] = "cursor park",
+       [MSG_FUNCNAME_CUT] = "cut",
+       [MSG_FUNCNAME_EDIT_DELIM] = "edit delimiters",
+       [MSG_FUNCNAME_EDIT_EXNUM] = "edit exnum",
+       [MSG_FUNCNAME_EDIT_MOST] = "edit most",
+       [MSG_FUNCNAME_EDIT_REPEATS] = "edit repeats",
+       [MSG_FUNCNAME_EDIT_SOME] = "edit some",
+       [MSG_FUNCNAME_GOTO] = "go to",
+       [MSG_FUNCNAME_GOTO_BOTTOM] = "go to bottom edge",
+       [MSG_FUNCNAME_GOTO_LEFT] = "go to left edge",
+       [MSG_FUNCNAME_GOTO_RIGHT] = "go to right edge",
+       [MSG_FUNCNAME_GOTO_TOP] = "go to top edge",
+       [MSG_FUNCNAME_HELP] = "help",
+       [MSG_FUNCNAME_LINE_SAY_CURRENT] = "line, say current",
+       [MSG_FUNCNAME_LINE_SAY_NEXT] = "line, say next",
+       [MSG_FUNCNAME_LINE_SAY_PREVIOUS] = "line, say previous",
+       [MSG_FUNCNAME_LINE_SAY_WITH_INDENT] = "line, say with indent",
+       [MSG_FUNCNAME_PASTE] = "paste",
+       [MSG_FUNCNAME_PITCH_DEC] = "pitch decrement",
+       [MSG_FUNCNAME_PITCH_INC] = "pitch increment",
+       [MSG_FUNCNAME_PUNC_DEC] = "punctuation decrement",
+       [MSG_FUNCNAME_PUNC_INC] = "punctuation increment",
+       [MSG_FUNCNAME_PUNC_LEVEL_DEC] = "punc level decrement",
+       [MSG_FUNCNAME_PUNC_LEVEL_INC] = "punc level increment",
+       [MSG_FUNCNAME_QUIET] = "quiet",
+       [MSG_FUNCNAME_RATE_DEC] = "rate decrement",
+       [MSG_FUNCNAME_RATE_INC] = "rate increment",
+       [MSG_FUNCNAME_READING_PUNC_DEC] = "reading punctuation decrement",
+       [MSG_FUNCNAME_READING_PUNC_INC] = "reading punctuation increment",
+       [MSG_FUNCNAME_SAY_ATTRIBUTES] = "say attributes",
+       [MSG_FUNCNAME_SAY_FROM_LEFT] = "say from left",
+       [MSG_FUNCNAME_SAY_FROM_TOP] = "say from top",
+       [MSG_FUNCNAME_SAY_POSITION] = "say position",
+       [MSG_FUNCNAME_SAY_SCREEN] = "say screen",
+       [MSG_FUNCNAME_SAY_TO_BOTTOM] = "say to bottom",
+       [MSG_FUNCNAME_SAY_TO_RIGHT] = "say to right",
+       [MSG_FUNCNAME_SPEAKUP] = "speakup",
+       [MSG_FUNCNAME_SPEAKUP_LOCK] = "speakup lock",
+       [MSG_FUNCNAME_SPEAKUP_OFF] = "speakup off",
+       [MSG_FUNCNAME_SPEECH_KILL] = "speech kill",
+       [MSG_FUNCNAME_SPELL_DELAY_DEC] = "spell delay decrement",
+       [MSG_FUNCNAME_SPELL_DELAY_INC] = "spell delay increment",
+       [MSG_FUNCNAME_SPELL_WORD] = "spell word",
+       [MSG_FUNCNAME_SPELL_WORD_PHONETICALLY] = "spell word phonetically",
+       [MSG_FUNCNAME_TONE_DEC] = "tone decrement",
+       [MSG_FUNCNAME_TONE_INC] = "tone increment",
+       [MSG_FUNCNAME_VOICE_DEC] = "voice decrement",
+       [MSG_FUNCNAME_VOICE_INC] = "voice increment",
+       [MSG_FUNCNAME_VOLUME_DEC] = "volume decrement",
+       [MSG_FUNCNAME_VOLUME_INC] = "volume increment",
+       [MSG_FUNCNAME_WINDOW_CLEAR] = "window, clear",
+       [MSG_FUNCNAME_WINDOW_SAY] = "window, say",
+       [MSG_FUNCNAME_WINDOW_SET] = "window, set",
+       [MSG_FUNCNAME_WINDOW_SILENCE] = "window, silence",
+       [MSG_FUNCNAME_WORD_SAY_CURRENT] = "word, say current",
+       [MSG_FUNCNAME_WORD_SAY_NEXT] = "word, say next",
+       [MSG_FUNCNAME_WORD_SAY_PREVIOUS] = "word, say previous",
+};
+
+static struct msg_group_t all_groups[] = {
+       {
+               .name = "ctl_keys",
+               .start = MSG_CTL_START,
+               .end = MSG_CTL_END,
+       },
+       {
+               .name = "colors",
+               .start = MSG_COLORS_START,
+               .end = MSG_COLORS_END,
+       },
+       {
+               .name = "formatted",
+               .start = MSG_FORMATTED_START,
+               .end = MSG_FORMATTED_END,
+       },
+       {
+               .name = "function_names",
+               .start = MSG_FUNCNAMES_START,
+               .end = MSG_FUNCNAMES_END,
+       },
+       {
+               .name = "key_names",
+               .start = MSG_KEYNAMES_START,
+               .end = MSG_KEYNAMES_END,
+       },
+       {
+               .name = "announcements",
+               .start = MSG_ANNOUNCEMENTS_START,
+               .end = MSG_ANNOUNCEMENTS_END,
+       },
+       {
+               .name = "states",
+               .start = MSG_STATES_START,
+               .end = MSG_STATES_END,
+       },
+};
+
+static const  int num_groups = ARRAY_SIZE(all_groups);
+
+char *spk_msg_get(enum msg_index_t index)
+{
+       return speakup_msgs[index];
+}
+
+/*
+ * Function: next_specifier
+ * Finds the start of the next format specifier in the argument string.
+ * Return value: pointer to start of format
+ * specifier, or NULL if no specifier exists.
+ */
+static char *next_specifier(char *input)
+{
+       int found = 0;
+       char *next_percent = input;
+
+       while (next_percent && !found) {
+               next_percent = strchr(next_percent, '%');
+               if (next_percent) {
+                       /* skip over doubled percent signs */
+                       while (next_percent[0] == '%' &&
+                              next_percent[1] == '%')
+                               next_percent += 2;
+                       if (*next_percent == '%')
+                               found = 1;
+                       else if (*next_percent == '\0')
+                               next_percent = NULL;
+               }
+       }
+
+       return next_percent;
+}
+
+/* Skip over 0 or more flags. */
+static char *skip_flags(char *input)
+{
+       while ((*input != '\0') && strchr(" 0+-#", *input))
+               input++;
+       return input;
+}
+
+/* Skip over width.precision, if it exists. */
+static char *skip_width(char *input)
+{
+       while (isdigit(*input))
+               input++;
+       if (*input == '.') {
+               input++;
+               while (isdigit(*input))
+                       input++;
+       }
+       return input;
+}
+
+/*
+ * Skip past the end of the conversion part.
+ * Note that this code only accepts a handful of conversion specifiers:
+ * c d s x and ld.  Not accidental; these are exactly the ones used in
+ * the default group of formatted messages.
+ */
+static char *skip_conversion(char *input)
+{
+       if ((input[0] == 'l') && (input[1] == 'd'))
+               input += 2;
+       else if ((*input != '\0') && strchr("cdsx", *input))
+               input++;
+       return input;
+}
+
+/*
+ * Function: find_specifier_end
+ * Return a pointer to the end of the format specifier.
+ */
+static char *find_specifier_end(char *input)
+{
+       input++;                /* Advance over %. */
+       input = skip_flags(input);
+       input = skip_width(input);
+       input = skip_conversion(input);
+       return input;
+}
+
+/*
+ * Function: compare_specifiers
+ * Compare the format specifiers pointed to by *input1 and *input2.
+ * Return true if they are the same, false otherwise.
+ * Advance *input1 and *input2 so that they point to the character following
+ * the end of the specifier.
+ */
+static bool compare_specifiers(char **input1, char **input2)
+{
+       bool same = false;
+       char *end1 = find_specifier_end(*input1);
+       char *end2 = find_specifier_end(*input2);
+       size_t length1 = end1 - *input1;
+       size_t length2 = end2 - *input2;
+
+       if ((length1 == length2) && !memcmp(*input1, *input2, length1))
+               same = true;
+
+       *input1 = end1;
+       *input2 = end2;
+       return same;
+}
+
+/*
+ * Function: fmt_validate
+ * Check that two format strings contain the same number of format specifiers,
+ * and that the order of specifiers is the same in both strings.
+ * Return true if the condition holds, false if it doesn't.
+ */
+static bool fmt_validate(char *template, char *user)
+{
+       bool valid = true;
+       bool still_comparing = true;
+       char *template_ptr = template;
+       char *user_ptr = user;
+
+       while (still_comparing && valid) {
+               template_ptr = next_specifier(template_ptr);
+               user_ptr = next_specifier(user_ptr);
+               if (template_ptr && user_ptr) {
+                       /* Both have at least one more specifier. */
+                       valid = compare_specifiers(&template_ptr, &user_ptr);
+               } else {
+                       /* No more format specifiers in one or both strings. */
+                       still_comparing = false;
+                       /* See if one has more specifiers than the other. */
+                       if (template_ptr || user_ptr)
+                               valid = false;
+               }
+       }
+       return valid;
+}
+
+/*
+ * Function: msg_set
+ * Description: Add a user-supplied message to the user_messages array.
+ * The message text is copied to a memory area allocated with kmalloc.
+ * If the function fails, then user_messages is untouched.
+ * Arguments:
+ * - index: a message number, as found in i18n.h.
+ * - text:  text of message.  Not NUL-terminated.
+ * - length: number of bytes in text.
+ * Failure conditions:
+ * -EINVAL -  Invalid format specifiers in formatted message or illegal index.
+ * -ENOMEM -  Unable to allocate memory.
+ */
+ssize_t spk_msg_set(enum msg_index_t index, char *text, size_t length)
+{
+       char *newstr = NULL;
+       unsigned long flags;
+
+       if ((index < MSG_FIRST_INDEX) || (index >= MSG_LAST_INDEX))
+               return -EINVAL;
+
+       newstr = kmalloc(length + 1, GFP_KERNEL);
+       if (!newstr)
+               return -ENOMEM;
+
+       memcpy(newstr, text, length);
+       newstr[length] = '\0';
+       if (index >= MSG_FORMATTED_START &&
+           index <= MSG_FORMATTED_END &&
+           !fmt_validate(speakup_default_msgs[index], newstr)) {
+               kfree(newstr);
+               return -EINVAL;
+       }
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       if (speakup_msgs[index] != speakup_default_msgs[index])
+               kfree(speakup_msgs[index]);
+       speakup_msgs[index] = newstr;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return 0;
+}
+
+/*
+ * Find a message group, given its name.  Return a pointer to the structure
+ * if found, or NULL otherwise.
+ */
+struct msg_group_t *spk_find_msg_group(const char *group_name)
+{
+       struct msg_group_t *group = NULL;
+       int i;
+
+       for (i = 0; i < num_groups; i++) {
+               if (!strcmp(all_groups[i].name, group_name)) {
+                       group = &all_groups[i];
+                       break;
+               }
+       }
+       return group;
+}
+
+void spk_reset_msg_group(struct msg_group_t *group)
+{
+       unsigned long flags;
+       enum msg_index_t i;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+
+       for (i = group->start; i <= group->end; i++) {
+               if (speakup_msgs[i] != speakup_default_msgs[i])
+                       kfree(speakup_msgs[i]);
+               speakup_msgs[i] = speakup_default_msgs[i];
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+}
+
+/* Called at initialization time, to establish default messages. */
+void spk_initialize_msgs(void)
+{
+       memcpy(speakup_msgs, speakup_default_msgs,
+              sizeof(speakup_default_msgs));
+}
+
+/* Free user-supplied strings when module is unloaded: */
+void spk_free_user_msgs(void)
+{
+       enum msg_index_t index;
+       unsigned long flags;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       for (index = MSG_FIRST_INDEX; index < MSG_LAST_INDEX; index++) {
+               if (speakup_msgs[index] != speakup_default_msgs[index]) {
+                       kfree(speakup_msgs[index]);
+                       speakup_msgs[index] = speakup_default_msgs[index];
+               }
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+}
diff --git a/drivers/accessibility/speakup/i18n.h b/drivers/accessibility/speakup/i18n.h
new file mode 100644 (file)
index 0000000..2ec6e65
--- /dev/null
@@ -0,0 +1,235 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef I18N_H
+#define I18N_H
+/* Internationalization declarations */
+
+enum msg_index_t {
+       MSG_FIRST_INDEX,
+       MSG_ANNOUNCEMENTS_START = MSG_FIRST_INDEX,
+       MSG_BLANK = MSG_ANNOUNCEMENTS_START,
+       MSG_IAM_ALIVE,
+       MSG_YOU_KILLED_SPEAKUP,
+       MSG_HEY_THATS_BETTER,
+       MSG_YOU_TURNED_ME_OFF,
+       MSG_PARKED,
+       MSG_UNPARKED,
+       MSG_MARK,
+       MSG_CUT,
+       MSG_MARK_CLEARED,
+       MSG_PASTE,
+       MSG_BRIGHT,
+       MSG_ON_BLINKING,
+       MSG_STATUS_START,
+       MSG_OFF = MSG_STATUS_START,
+       MSG_ON,
+       MSG_NO_WINDOW,
+       MSG_CURSOR_MSGS_START,
+       MSG_CURSORING_OFF = MSG_CURSOR_MSGS_START,
+       MSG_CURSORING_ON,
+       MSG_HIGHLIGHT_TRACKING,
+       MSG_READ_WINDOW,
+       MSG_READ_ALL,
+       MSG_EDIT_DONE,
+       MSG_WINDOW_ALREADY_SET,
+       MSG_END_BEFORE_START,
+       MSG_WINDOW_CLEARED,
+       MSG_WINDOW_SILENCED,
+       MSG_WINDOW_SILENCE_DISABLED,
+       MSG_ERROR,
+       MSG_GOTO_CANCELED,
+       MSG_GOTO,
+       MSG_LEAVING_HELP,
+       MSG_IS_UNASSIGNED,
+       MSG_HELP_INFO,
+       MSG_EDGE_MSGS_START,
+       MSG_EDGE_TOP  = MSG_EDGE_MSGS_START,
+       MSG_EDGE_BOTTOM,
+       MSG_EDGE_LEFT,
+       MSG_EDGE_RIGHT,
+       MSG_NUMBER,
+       MSG_SPACE,
+       MSG_START, /* A little confusing, given our convention. */
+       MSG_END, /* A little confusing, given our convention. */
+       MSG_CTRL,
+
+/* A message containing the single word "or". */
+       MSG_DISJUNCTION,
+       MSG_ANNOUNCEMENTS_END = MSG_DISJUNCTION,
+
+/* Messages with format specifiers. */
+       MSG_FORMATTED_START,
+       MSG_POS_INFO = MSG_FORMATTED_START,
+       MSG_CHAR_INFO,
+       MSG_REPEAT_DESC,
+       MSG_REPEAT_DESC2,
+       MSG_WINDOW_LINE,
+       MSG_WINDOW_BOUNDARY,
+       MSG_EDIT_PROMPT,
+       MSG_NO_COMMAND,
+       MSG_KEYDESC,
+       MSG_FORMATTED_END = MSG_KEYDESC,
+
+       /* Control keys. */
+       MSG_CTL_START,
+       MSG_CTL_SHIFT = MSG_CTL_START,
+       MSG_CTL_ALTGR,
+       MSG_CTL_CONTROL,
+       MSG_CTL_ALT,
+       MSG_CTL_LSHIFT,
+       MSG_CTL_SPEAKUP,
+       MSG_CTL_LCONTROL,
+       MSG_CTL_RCONTROL,
+       MSG_CTL_CAPSSHIFT,
+       MSG_CTL_END = MSG_CTL_CAPSSHIFT,
+
+       /* Colors. */
+       MSG_COLORS_START,
+       MSG_COLOR_BLACK = MSG_COLORS_START,
+       MSG_COLOR_BLUE,
+       MSG_COLOR_GREEN,
+       MSG_COLOR_CYAN,
+       MSG_COLOR_RED,
+       MSG_COLOR_MAGENTA,
+       MSG_COLOR_YELLOW,
+       MSG_COLOR_WHITE,
+       MSG_COLOR_GREY,
+       MSG_COLORS_END = MSG_COLOR_GREY,
+
+       MSG_STATES_START,
+       MSG_STATE_DOUBLE = MSG_STATES_START,
+       MSG_STATE_SPEAKUP,
+       MSG_STATE_ALT,
+       MSG_STATE_CONTROL,
+       MSG_STATE_ALTGR,
+       MSG_STATE_SHIFT,
+       MSG_STATES_END = MSG_STATE_SHIFT,
+
+       MSG_KEYNAMES_START,
+       MSG_KEYNAME_ESC = MSG_KEYNAMES_START,
+       MSG_KEYNAME_1, MSG_KEYNAME_2, MSG_KEYNAME_3, MSG_KEYNAME_4,
+       MSG_KEYNAME_5, MSG_KEYNAME_6, MSG_KEYNAME_7, MSG_KEYNAME_8,
+       MSG_KEYNAME_9,
+       MSG_KEYNAME_0, MSG_KEYNAME_DASH, MSG_KEYNAME_EQUAL, MSG_KEYNAME_BS,
+       MSG_KEYNAME_TAB,
+       MSG_KEYNAME_Q, MSG_KEYNAME_W, MSG_KEYNAME_E, MSG_KEYNAME_R,
+       MSG_KEYNAME_T, MSG_KEYNAME_Y, MSG_KEYNAME_U, MSG_KEYNAME_I,
+       MSG_KEYNAME_O, MSG_KEYNAME_P,
+       MSG_KEYNAME_LEFTBRACE, MSG_KEYNAME_RIGHTBRACE, MSG_KEYNAME_ENTER,
+       MSG_KEYNAME_LEFTCTRL, MSG_KEYNAME_A,
+       MSG_KEYNAME_S, MSG_KEYNAME_D, MSG_KEYNAME_F, MSG_KEYNAME_G,
+       MSG_KEYNAME_H, MSG_KEYNAME_J, MSG_KEYNAME_K, MSG_KEYNAME_L,
+       MSG_KEYNAME_SEMICOLON,
+       MSG_KEYNAME_SINGLEQUOTE, MSG_KEYNAME_GRAVE,
+       MSG_KEYNAME_LEFTSHFT, MSG_KEYNAME_BACKSLASH, MSG_KEYNAME_Z,
+       MSG_KEYNAME_X, MSG_KEYNAME_C, MSG_KEYNAME_V, MSG_KEYNAME_B,
+       MSG_KEYNAME_N, MSG_KEYNAME_M, MSG_KEYNAME_COMMA, MSG_KEYNAME_DOT,
+       MSG_KEYNAME_SLASH, MSG_KEYNAME_RIGHTSHFT,
+       MSG_KEYNAME_KPSTAR,
+       MSG_KEYNAME_LEFTALT, MSG_KEYNAME_SPACE, MSG_KEYNAME_CAPSLOCK,
+       MSG_KEYNAME_F1, MSG_KEYNAME_F2,
+       MSG_KEYNAME_F3, MSG_KEYNAME_F4, MSG_KEYNAME_F5, MSG_KEYNAME_F6,
+       MSG_KEYNAME_F7,
+       MSG_KEYNAME_F8, MSG_KEYNAME_F9, MSG_KEYNAME_F10, MSG_KEYNAME_NUMLOCK,
+       MSG_KEYNAME_SCROLLLOCK,
+       MSG_KEYNAME_KP7, MSG_KEYNAME_KP8, MSG_KEYNAME_KP9, MSG_KEYNAME_KPMINUS,
+       MSG_KEYNAME_KP4,
+       MSG_KEYNAME_KP5, MSG_KEYNAME_KP6, MSG_KEYNAME_KPPLUS, MSG_KEYNAME_KP1,
+       MSG_KEYNAME_KP2,
+       MSG_KEYNAME_KP3, MSG_KEYNAME_KP0, MSG_KEYNAME_KPDOT, MSG_KEYNAME_103RD,
+       MSG_KEYNAME_F13,
+       MSG_KEYNAME_102ND, MSG_KEYNAME_F11, MSG_KEYNAME_F12, MSG_KEYNAME_F14,
+       MSG_KEYNAME_F15,
+       MSG_KEYNAME_F16, MSG_KEYNAME_F17, MSG_KEYNAME_F18, MSG_KEYNAME_F19,
+       MSG_KEYNAME_F20,
+       MSG_KEYNAME_KPENTER, MSG_KEYNAME_RIGHTCTRL, MSG_KEYNAME_KPSLASH,
+       MSG_KEYNAME_SYSRQ, MSG_KEYNAME_RIGHTALT,
+       MSG_KEYNAME_LF, MSG_KEYNAME_HOME, MSG_KEYNAME_UP, MSG_KEYNAME_PGUP,
+       MSG_KEYNAME_LEFT,
+       MSG_KEYNAME_RIGHT, MSG_KEYNAME_END, MSG_KEYNAME_DOWN, MSG_KEYNAME_PGDN,
+       MSG_KEYNAME_INS,
+       MSG_KEYNAME_DEL, MSG_KEYNAME_MACRO, MSG_KEYNAME_MUTE,
+       MSG_KEYNAME_VOLDOWN, MSG_KEYNAME_VOLUP,
+       MSG_KEYNAME_POWER, MSG_KEYNAME_KPEQUAL, MSG_KEYNAME_KPPLUSDASH,
+       MSG_KEYNAME_PAUSE, MSG_KEYNAME_F21, MSG_KEYNAME_F22, MSG_KEYNAME_F23,
+       MSG_KEYNAME_F24, MSG_KEYNAME_KPCOMMA, MSG_KEYNAME_LEFTMETA,
+       MSG_KEYNAME_RIGHTMETA, MSG_KEYNAME_COMPOSE, MSG_KEYNAME_STOP,
+       MSG_KEYNAME_AGAIN, MSG_KEYNAME_PROPS,
+       MSG_KEYNAME_UNDO, MSG_KEYNAME_FRONT, MSG_KEYNAME_COPY, MSG_KEYNAME_OPEN,
+       MSG_KEYNAME_PASTE,
+       MSG_KEYNAME_FIND, MSG_KEYNAME_CUT, MSG_KEYNAME_HELP, MSG_KEYNAME_MENU,
+       MSG_KEYNAME_CALC,
+       MSG_KEYNAME_SETUP, MSG_KEYNAME_SLEEP, MSG_KEYNAME_WAKEUP,
+       MSG_KEYNAME_FILE, MSG_KEYNAME_SENDFILE,
+       MSG_KEYNAME_DELFILE, MSG_KEYNAME_XFER, MSG_KEYNAME_PROG1,
+       MSG_KEYNAME_PROG2, MSG_KEYNAME_WWW,
+       MSG_KEYNAME_MSDOS, MSG_KEYNAME_COFFEE, MSG_KEYNAME_DIRECTION,
+       MSG_KEYNAME_CYCLEWINDOWS, MSG_KEYNAME_MAIL,
+       MSG_KEYNAME_BOOKMARKS, MSG_KEYNAME_COMPUTER, MSG_KEYNAME_BACK,
+       MSG_KEYNAME_FORWARD, MSG_KEYNAME_CLOSECD,
+       MSG_KEYNAME_EJECTCD, MSG_KEYNAME_EJECTCLOSE, MSG_KEYNAME_NEXTSONG,
+       MSG_KEYNAME_PLAYPAUSE, MSG_KEYNAME_PREVSONG,
+       MSG_KEYNAME_STOPCD, MSG_KEYNAME_RECORD, MSG_KEYNAME_REWIND,
+       MSG_KEYNAME_PHONE, MSG_KEYNAME_ISO,
+       MSG_KEYNAME_CONFIG, MSG_KEYNAME_HOMEPG, MSG_KEYNAME_REFRESH,
+       MSG_KEYNAME_EXIT, MSG_KEYNAME_MOVE,
+       MSG_KEYNAME_EDIT, MSG_KEYNAME_SCROLLUP, MSG_KEYNAME_SCROLLDN,
+       MSG_KEYNAME_KPLEFTPAR, MSG_KEYNAME_KPRIGHTPAR,
+       MSG_KEYNAMES_END = MSG_KEYNAME_KPRIGHTPAR,
+
+       MSG_FUNCNAMES_START,
+       MSG_FUNCNAME_ATTRIB_BLEEP_DEC = MSG_FUNCNAMES_START,
+       MSG_FUNCNAME_ATTRIB_BLEEP_INC,
+       MSG_FUNCNAME_BLEEPS_DEC, MSG_FUNCNAME_BLEEPS_INC,
+       MSG_FUNCNAME_CHAR_FIRST, MSG_FUNCNAME_CHAR_LAST,
+       MSG_FUNCNAME_CHAR_CURRENT, MSG_FUNCNAME_CHAR_HEX_AND_DEC,
+       MSG_FUNCNAME_CHAR_NEXT,
+       MSG_FUNCNAME_CHAR_PHONETIC, MSG_FUNCNAME_CHAR_PREVIOUS,
+       MSG_FUNCNAME_CURSOR_PARK, MSG_FUNCNAME_CUT,
+       MSG_FUNCNAME_EDIT_DELIM, MSG_FUNCNAME_EDIT_EXNUM,
+       MSG_FUNCNAME_EDIT_MOST, MSG_FUNCNAME_EDIT_REPEATS,
+       MSG_FUNCNAME_EDIT_SOME,
+       MSG_FUNCNAME_GOTO, MSG_FUNCNAME_GOTO_BOTTOM, MSG_FUNCNAME_GOTO_LEFT,
+       MSG_FUNCNAME_GOTO_RIGHT, MSG_FUNCNAME_GOTO_TOP, MSG_FUNCNAME_HELP,
+       MSG_FUNCNAME_LINE_SAY_CURRENT, MSG_FUNCNAME_LINE_SAY_NEXT,
+       MSG_FUNCNAME_LINE_SAY_PREVIOUS, MSG_FUNCNAME_LINE_SAY_WITH_INDENT,
+       MSG_FUNCNAME_PASTE, MSG_FUNCNAME_PITCH_DEC, MSG_FUNCNAME_PITCH_INC,
+       MSG_FUNCNAME_PUNC_DEC, MSG_FUNCNAME_PUNC_INC,
+       MSG_FUNCNAME_PUNC_LEVEL_DEC, MSG_FUNCNAME_PUNC_LEVEL_INC,
+       MSG_FUNCNAME_QUIET,
+       MSG_FUNCNAME_RATE_DEC, MSG_FUNCNAME_RATE_INC,
+       MSG_FUNCNAME_READING_PUNC_DEC, MSG_FUNCNAME_READING_PUNC_INC,
+       MSG_FUNCNAME_SAY_ATTRIBUTES,
+       MSG_FUNCNAME_SAY_FROM_LEFT, MSG_FUNCNAME_SAY_FROM_TOP,
+       MSG_FUNCNAME_SAY_POSITION, MSG_FUNCNAME_SAY_SCREEN,
+       MSG_FUNCNAME_SAY_TO_BOTTOM, MSG_FUNCNAME_SAY_TO_RIGHT,
+       MSG_FUNCNAME_SPEAKUP, MSG_FUNCNAME_SPEAKUP_LOCK,
+       MSG_FUNCNAME_SPEAKUP_OFF, MSG_FUNCNAME_SPEECH_KILL,
+       MSG_FUNCNAME_SPELL_DELAY_DEC, MSG_FUNCNAME_SPELL_DELAY_INC,
+       MSG_FUNCNAME_SPELL_WORD, MSG_FUNCNAME_SPELL_WORD_PHONETICALLY,
+       MSG_FUNCNAME_TONE_DEC, MSG_FUNCNAME_TONE_INC,
+       MSG_FUNCNAME_VOICE_DEC, MSG_FUNCNAME_VOICE_INC,
+       MSG_FUNCNAME_VOLUME_DEC, MSG_FUNCNAME_VOLUME_INC,
+       MSG_FUNCNAME_WINDOW_CLEAR, MSG_FUNCNAME_WINDOW_SAY,
+       MSG_FUNCNAME_WINDOW_SET, MSG_FUNCNAME_WINDOW_SILENCE,
+       MSG_FUNCNAME_WORD_SAY_CURRENT, MSG_FUNCNAME_WORD_SAY_NEXT,
+       MSG_FUNCNAME_WORD_SAY_PREVIOUS,
+       MSG_FUNCNAMES_END = MSG_FUNCNAME_WORD_SAY_PREVIOUS,
+
+       /* all valid indices must be above this */
+       MSG_LAST_INDEX
+};
+
+struct msg_group_t {
+       char *name;
+       enum msg_index_t start;
+       enum msg_index_t end;
+};
+
+char *spk_msg_get(enum msg_index_t index);
+ssize_t spk_msg_set(enum msg_index_t index, char *text, size_t length);
+struct msg_group_t *spk_find_msg_group(const char *group_name);
+void spk_reset_msg_group(struct msg_group_t *group);
+void spk_initialize_msgs(void);
+void spk_free_user_msgs(void);
+
+#endif
diff --git a/drivers/accessibility/speakup/keyhelp.c b/drivers/accessibility/speakup/keyhelp.c
new file mode 100644 (file)
index 0000000..822ceac
--- /dev/null
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* speakup_keyhelp.c
+ * help module for speakup
+ *
+ *written by David Borowski.
+ *
+ *  Copyright (C) 2003  David Borowski.
+ */
+
+#include <linux/keyboard.h>
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define MAXFUNCS 130
+#define MAXKEYS 256
+static const int num_key_names = MSG_KEYNAMES_END - MSG_KEYNAMES_START + 1;
+static u_short key_offsets[MAXFUNCS], key_data[MAXKEYS];
+static u_short masks[] = { 32, 16, 8, 4, 2, 1 };
+
+static short letter_offsets[26] = {
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1 };
+
+static u_char funcvals[] = {
+       ATTRIB_BLEEP_DEC, ATTRIB_BLEEP_INC, BLEEPS_DEC, BLEEPS_INC,
+       SAY_FIRST_CHAR, SAY_LAST_CHAR, SAY_CHAR, SAY_CHAR_NUM,
+       SAY_NEXT_CHAR, SAY_PHONETIC_CHAR, SAY_PREV_CHAR, SPEAKUP_PARKED,
+       SPEAKUP_CUT, EDIT_DELIM, EDIT_EXNUM, EDIT_MOST,
+       EDIT_REPEAT, EDIT_SOME, SPEAKUP_GOTO, BOTTOM_EDGE,
+       LEFT_EDGE, RIGHT_EDGE, TOP_EDGE, SPEAKUP_HELP,
+       SAY_LINE, SAY_NEXT_LINE, SAY_PREV_LINE, SAY_LINE_INDENT,
+       SPEAKUP_PASTE, PITCH_DEC, PITCH_INC, PUNCT_DEC,
+       PUNCT_INC, PUNC_LEVEL_DEC, PUNC_LEVEL_INC, SPEAKUP_QUIET,
+       RATE_DEC, RATE_INC, READING_PUNC_DEC, READING_PUNC_INC,
+       SAY_ATTRIBUTES, SAY_FROM_LEFT, SAY_FROM_TOP, SAY_POSITION,
+       SAY_SCREEN, SAY_TO_BOTTOM, SAY_TO_RIGHT, SPK_KEY,
+       SPK_LOCK, SPEAKUP_OFF, SPEECH_KILL, SPELL_DELAY_DEC,
+       SPELL_DELAY_INC, SPELL_WORD, SPELL_PHONETIC, TONE_DEC,
+       TONE_INC, VOICE_DEC, VOICE_INC, VOL_DEC,
+       VOL_INC, CLEAR_WIN, SAY_WIN, SET_WIN,
+       ENABLE_WIN, SAY_WORD, SAY_NEXT_WORD, SAY_PREV_WORD, 0
+};
+
+static u_char *state_tbl;
+static int cur_item, nstates;
+
+static void build_key_data(void)
+{
+       u_char *kp, counters[MAXFUNCS], ch, ch1;
+       u_short *p_key, key;
+       int i, offset = 1;
+
+       nstates = (int)(state_tbl[-1]);
+       memset(counters, 0, sizeof(counters));
+       memset(key_offsets, 0, sizeof(key_offsets));
+       kp = state_tbl + nstates + 1;
+       while (*kp++) {
+               /* count occurrences of each function */
+               for (i = 0; i < nstates; i++, kp++) {
+                       if (!*kp)
+                               continue;
+                       if ((state_tbl[i] & 16) != 0 && *kp == SPK_KEY)
+                               continue;
+                       counters[*kp]++;
+               }
+       }
+       for (i = 0; i < MAXFUNCS; i++) {
+               if (counters[i] == 0)
+                       continue;
+               key_offsets[i] = offset;
+               offset += (counters[i] + 1);
+               if (offset >= MAXKEYS)
+                       break;
+       }
+/* leave counters set so high keycodes come first.
+ * this is done so num pad and other extended keys maps are spoken before
+ * the alpha with speakup type mapping.
+ */
+       kp = state_tbl + nstates + 1;
+       while ((ch = *kp++)) {
+               for (i = 0; i < nstates; i++) {
+                       ch1 = *kp++;
+                       if (!ch1)
+                               continue;
+                       if ((state_tbl[i] & 16) != 0 && ch1 == SPK_KEY)
+                               continue;
+                       key = (state_tbl[i] << 8) + ch;
+                       counters[ch1]--;
+                       offset = key_offsets[ch1];
+                       if (!offset)
+                               continue;
+                       p_key = key_data + offset + counters[ch1];
+                       *p_key = key;
+               }
+       }
+}
+
+static void say_key(int key)
+{
+       int i, state = key >> 8;
+
+       key &= 0xff;
+       for (i = 0; i < 6; i++) {
+               if (state & masks[i])
+                       synth_printf(" %s", spk_msg_get(MSG_STATES_START + i));
+       }
+       if ((key > 0) && (key <= num_key_names))
+               synth_printf(" %s\n",
+                            spk_msg_get(MSG_KEYNAMES_START + (key - 1)));
+}
+
+static int help_init(void)
+{
+       char start = SPACE;
+       int i;
+       int num_funcs = MSG_FUNCNAMES_END - MSG_FUNCNAMES_START + 1;
+
+       state_tbl = spk_our_keys[0] + SHIFT_TBL_SIZE + 2;
+       for (i = 0; i < num_funcs; i++) {
+               char *cur_funcname = spk_msg_get(MSG_FUNCNAMES_START + i);
+
+               if (start == *cur_funcname)
+                       continue;
+               start = *cur_funcname;
+               letter_offsets[(start & 31) - 1] = i;
+       }
+       return 0;
+}
+
+int spk_handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key)
+{
+       int i, n;
+       char *name;
+       u_char func, *kp;
+       u_short *p_keys, val;
+
+       if (letter_offsets[0] == -1)
+               help_init();
+       if (type == KT_LATIN) {
+               if (ch == SPACE) {
+                       spk_special_handler = NULL;
+                       synth_printf("%s\n", spk_msg_get(MSG_LEAVING_HELP));
+                       return 1;
+               }
+               ch |= 32; /* lower case */
+               if (ch < 'a' || ch > 'z')
+                       return -1;
+               if (letter_offsets[ch - 'a'] == -1) {
+                       synth_printf(spk_msg_get(MSG_NO_COMMAND), ch);
+                       synth_printf("\n");
+                       return 1;
+               }
+               cur_item = letter_offsets[ch - 'a'];
+       } else if (type == KT_CUR) {
+               if (ch == 0 &&
+                   (MSG_FUNCNAMES_START + cur_item + 1) <= MSG_FUNCNAMES_END)
+                       cur_item++;
+               else if (ch == 3 && cur_item > 0)
+                       cur_item--;
+               else
+                       return -1;
+       } else if (type == KT_SPKUP && ch == SPEAKUP_HELP &&
+                  !spk_special_handler) {
+               spk_special_handler = spk_handle_help;
+               synth_printf("%s\n", spk_msg_get(MSG_HELP_INFO));
+               build_key_data(); /* rebuild each time in case new mapping */
+               return 1;
+       } else {
+               name = NULL;
+               if ((type != KT_SPKUP) && (key > 0) && (key <= num_key_names)) {
+                       synth_printf("%s\n",
+                                    spk_msg_get(MSG_KEYNAMES_START + key - 1));
+                       return 1;
+               }
+               for (i = 0; funcvals[i] != 0 && !name; i++) {
+                       if (ch == funcvals[i])
+                               name = spk_msg_get(MSG_FUNCNAMES_START + i);
+               }
+               if (!name)
+                       return -1;
+               kp = spk_our_keys[key] + 1;
+               for (i = 0; i < nstates; i++) {
+                       if (ch == kp[i])
+                               break;
+               }
+               key += (state_tbl[i] << 8);
+               say_key(key);
+               synth_printf(spk_msg_get(MSG_KEYDESC), name);
+               synth_printf("\n");
+               return 1;
+       }
+       name = spk_msg_get(MSG_FUNCNAMES_START + cur_item);
+       func = funcvals[cur_item];
+       synth_printf("%s", name);
+       if (key_offsets[func] == 0) {
+               synth_printf(" %s\n", spk_msg_get(MSG_IS_UNASSIGNED));
+               return 1;
+       }
+       p_keys = key_data + key_offsets[func];
+       for (n = 0; p_keys[n]; n++) {
+               val = p_keys[n];
+               if (n > 0)
+                       synth_printf("%s ", spk_msg_get(MSG_DISJUNCTION));
+               say_key(val);
+       }
+       return 1;
+}
diff --git a/drivers/accessibility/speakup/kobjects.c b/drivers/accessibility/speakup/kobjects.c
new file mode 100644 (file)
index 0000000..41ae24a
--- /dev/null
@@ -0,0 +1,1056 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Speakup kobject implementation
+ *
+ * Copyright (C) 2009 William Hubbs
+ *
+ * This code is based on kobject-example.c, which came with linux 2.6.x.
+ *
+ * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2007 Novell Inc.
+ *
+ * Released under the GPL version 2 only.
+ *
+ */
+#include <linux/slab.h>                /* For kmalloc. */
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/string_helpers.h>
+#include <linux/sysfs.h>
+#include <linux/ctype.h>
+
+#include "speakup.h"
+#include "spk_priv.h"
+
+/*
+ * This is called when a user reads the characters or chartab sys file.
+ */
+static ssize_t chars_chartab_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buf)
+{
+       int i;
+       int len = 0;
+       char *cp;
+       char *buf_pointer = buf;
+       size_t bufsize = PAGE_SIZE;
+       unsigned long flags;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       *buf_pointer = '\0';
+       for (i = 0; i < 256; i++) {
+               if (bufsize <= 1)
+                       break;
+               if (strcmp("characters", attr->attr.name) == 0) {
+                       len = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
+                                       i, spk_characters[i]);
+               } else {        /* show chartab entry */
+                       if (IS_TYPE(i, B_CTL))
+                               cp = "B_CTL";
+                       else if (IS_TYPE(i, WDLM))
+                               cp = "WDLM";
+                       else if (IS_TYPE(i, A_PUNC))
+                               cp = "A_PUNC";
+                       else if (IS_TYPE(i, PUNC))
+                               cp = "PUNC";
+                       else if (IS_TYPE(i, NUM))
+                               cp = "NUM";
+                       else if (IS_TYPE(i, A_CAP))
+                               cp = "A_CAP";
+                       else if (IS_TYPE(i, ALPHA))
+                               cp = "ALPHA";
+                       else if (IS_TYPE(i, B_CAPSYM))
+                               cp = "B_CAPSYM";
+                       else if (IS_TYPE(i, B_SYM))
+                               cp = "B_SYM";
+                       else
+                               cp = "0";
+                       len =
+                           scnprintf(buf_pointer, bufsize, "%d\t%s\n", i, cp);
+               }
+               bufsize -= len;
+               buf_pointer += len;
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return buf_pointer - buf;
+}
+
+/*
+ * Print informational messages or warnings after updating
+ * character descriptions or chartab entries.
+ */
+static void report_char_chartab_status(int reset, int received, int used,
+                                      int rejected, int do_characters)
+{
+       static char const *object_type[] = {
+               "character class entries",
+               "character descriptions",
+       };
+       int len;
+       char buf[80];
+
+       if (reset) {
+               pr_info("%s reset to defaults\n", object_type[do_characters]);
+       } else if (received) {
+               len = snprintf(buf, sizeof(buf),
+                              " updated %d of %d %s\n",
+                              used, received, object_type[do_characters]);
+               if (rejected)
+                       snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
+                                " with %d reject%s\n",
+                                rejected, rejected > 1 ? "s" : "");
+               pr_info("%s", buf);
+       }
+}
+
+/*
+ * This is called when a user changes the characters or chartab parameters.
+ */
+static ssize_t chars_chartab_store(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  const char *buf, size_t count)
+{
+       char *cp = (char *)buf;
+       char *end = cp + count; /* the null at the end of the buffer */
+       char *linefeed = NULL;
+       char keyword[MAX_DESC_LEN + 1];
+       char *outptr = NULL;    /* Will hold keyword or desc. */
+       char *temp = NULL;
+       char *desc = NULL;
+       ssize_t retval = count;
+       unsigned long flags;
+       unsigned long index = 0;
+       int charclass = 0;
+       int received = 0;
+       int used = 0;
+       int rejected = 0;
+       int reset = 0;
+       int do_characters = !strcmp(attr->attr.name, "characters");
+       size_t desc_length = 0;
+       int i;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       while (cp < end) {
+               while ((cp < end) && (*cp == ' ' || *cp == '\t'))
+                       cp++;
+
+               if (cp == end)
+                       break;
+               if ((*cp == '\n') || strchr("dDrR", *cp)) {
+                       reset = 1;
+                       break;
+               }
+               received++;
+
+               linefeed = strchr(cp, '\n');
+               if (!linefeed) {
+                       rejected++;
+                       break;
+               }
+
+               if (!isdigit(*cp)) {
+                       rejected++;
+                       cp = linefeed + 1;
+                       continue;
+               }
+
+               /*
+                * Do not replace with kstrtoul:
+                * here we need temp to be updated
+                */
+               index = simple_strtoul(cp, &temp, 10);
+               if (index > 255) {
+                       rejected++;
+                       cp = linefeed + 1;
+                       continue;
+               }
+
+               while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
+                       temp++;
+
+               desc_length = linefeed - temp;
+               if (desc_length > MAX_DESC_LEN) {
+                       rejected++;
+                       cp = linefeed + 1;
+                       continue;
+               }
+               if (do_characters) {
+                       desc = kmalloc(desc_length + 1, GFP_ATOMIC);
+                       if (!desc) {
+                               retval = -ENOMEM;
+                               reset = 1;      /* just reset on error. */
+                               break;
+                       }
+                       outptr = desc;
+               } else {
+                       outptr = keyword;
+               }
+
+               for (i = 0; i < desc_length; i++)
+                       outptr[i] = temp[i];
+               outptr[desc_length] = '\0';
+
+               if (do_characters) {
+                       if (spk_characters[index] != spk_default_chars[index])
+                               kfree(spk_characters[index]);
+                       spk_characters[index] = desc;
+                       used++;
+               } else {
+                       charclass = spk_chartab_get_value(keyword);
+                       if (charclass == 0) {
+                               rejected++;
+                               cp = linefeed + 1;
+                               continue;
+                       }
+                       if (charclass != spk_chartab[index]) {
+                               spk_chartab[index] = charclass;
+                               used++;
+                       }
+               }
+               cp = linefeed + 1;
+       }
+
+       if (reset) {
+               if (do_characters)
+                       spk_reset_default_chars();
+               else
+                       spk_reset_default_chartab();
+       }
+
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       report_char_chartab_status(reset, received, used, rejected,
+                                  do_characters);
+       return retval;
+}
+
+/*
+ * This is called when a user reads the keymap parameter.
+ */
+static ssize_t keymap_show(struct kobject *kobj, struct kobj_attribute *attr,
+                          char *buf)
+{
+       char *cp = buf;
+       int i;
+       int n;
+       int num_keys;
+       int nstates;
+       u_char *cp1;
+       u_char ch;
+       unsigned long flags;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       cp1 = spk_key_buf + SHIFT_TBL_SIZE;
+       num_keys = (int)(*cp1);
+       nstates = (int)cp1[1];
+       cp += sprintf(cp, "%d, %d, %d,\n", KEY_MAP_VER, num_keys, nstates);
+       cp1 += 2; /* now pointing at shift states */
+       /* dump num_keys+1 as first row is shift states + flags,
+        * each subsequent row is key + states
+        */
+       for (n = 0; n <= num_keys; n++) {
+               for (i = 0; i <= nstates; i++) {
+                       ch = *cp1++;
+                       cp += sprintf(cp, "%d,", (int)ch);
+                       *cp++ = (i < nstates) ? SPACE : '\n';
+               }
+       }
+       cp += sprintf(cp, "0, %d\n", KEY_MAP_VER);
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return (int)(cp - buf);
+}
+
+/*
+ * This is called when a user changes the keymap parameter.
+ */
+static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr,
+                           const char *buf, size_t count)
+{
+       int i;
+       ssize_t ret = count;
+       char *in_buff = NULL;
+       char *cp;
+       u_char *cp1;
+       unsigned long flags;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       in_buff = kmemdup(buf, count + 1, GFP_ATOMIC);
+       if (!in_buff) {
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return -ENOMEM;
+       }
+       if (strchr("dDrR", *in_buff)) {
+               spk_set_key_info(spk_key_defaults, spk_key_buf);
+               pr_info("keymap set to default values\n");
+               kfree(in_buff);
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return count;
+       }
+       if (in_buff[count - 1] == '\n')
+               in_buff[count - 1] = '\0';
+       cp = in_buff;
+       cp1 = (u_char *)in_buff;
+       for (i = 0; i < 3; i++) {
+               cp = spk_s2uchar(cp, cp1);
+               cp1++;
+       }
+       i = (int)cp1[-2] + 1;
+       i *= (int)cp1[-1] + 1;
+       i += 2; /* 0 and last map ver */
+       if (cp1[-3] != KEY_MAP_VER || cp1[-1] > 10 ||
+           i + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
+               pr_warn("i %d %d %d %d\n", i,
+                       (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
+               kfree(in_buff);
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return -EINVAL;
+       }
+       while (--i >= 0) {
+               cp = spk_s2uchar(cp, cp1);
+               cp1++;
+               if (!(*cp))
+                       break;
+       }
+       if (i != 0 || cp1[-1] != KEY_MAP_VER || cp1[-2] != 0) {
+               ret = -EINVAL;
+               pr_warn("end %d %d %d %d\n", i,
+                       (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
+       } else {
+               if (spk_set_key_info(in_buff, spk_key_buf)) {
+                       spk_set_key_info(spk_key_defaults, spk_key_buf);
+                       ret = -EINVAL;
+                       pr_warn("set key failed\n");
+               }
+       }
+       kfree(in_buff);
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return ret;
+}
+
+/*
+ * This is called when a user changes the value of the silent parameter.
+ */
+static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr,
+                           const char *buf, size_t count)
+{
+       int len;
+       struct vc_data *vc = vc_cons[fg_console].d;
+       char ch = 0;
+       char shut;
+       unsigned long flags;
+
+       len = strlen(buf);
+       if (len > 0 && len < 3) {
+               ch = buf[0];
+               if (ch == '\n')
+                       ch = '0';
+       }
+       if (ch < '0' || ch > '7') {
+               pr_warn("silent value '%c' not in range (0,7)\n", ch);
+               return -EINVAL;
+       }
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       if (ch & 2) {
+               shut = 1;
+               spk_do_flush();
+       } else {
+               shut = 0;
+       }
+       if (ch & 4)
+               shut |= 0x40;
+       if (ch & 1)
+               spk_shut_up |= shut;
+       else
+               spk_shut_up &= ~shut;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return count;
+}
+
+/*
+ * This is called when a user reads the synth setting.
+ */
+static ssize_t synth_show(struct kobject *kobj, struct kobj_attribute *attr,
+                         char *buf)
+{
+       int rv;
+
+       if (!synth)
+               rv = sprintf(buf, "%s\n", "none");
+       else
+               rv = sprintf(buf, "%s\n", synth->name);
+       return rv;
+}
+
+/*
+ * This is called when a user requests to change synthesizers.
+ */
+static ssize_t synth_store(struct kobject *kobj, struct kobj_attribute *attr,
+                          const char *buf, size_t count)
+{
+       int len;
+       char new_synth_name[10];
+
+       len = strlen(buf);
+       if (len < 2 || len > 9)
+               return -EINVAL;
+       memcpy(new_synth_name, buf, len);
+       if (new_synth_name[len - 1] == '\n')
+               len--;
+       new_synth_name[len] = '\0';
+       spk_strlwr(new_synth_name);
+       if (synth && !strcmp(new_synth_name, synth->name)) {
+               pr_warn("%s already in use\n", new_synth_name);
+       } else if (synth_init(new_synth_name) != 0) {
+               pr_warn("failed to init synth %s\n", new_synth_name);
+               return -ENODEV;
+       }
+       return count;
+}
+
+/*
+ * This is called when text is sent to the synth via the synth_direct file.
+ */
+static ssize_t synth_direct_store(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       u_char tmp[256];
+       int len;
+       int bytes;
+       const char *ptr = buf;
+       unsigned long flags;
+
+       if (!synth)
+               return -EPERM;
+
+       len = strlen(buf);
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       while (len > 0) {
+               bytes = min_t(size_t, len, 250);
+               strncpy(tmp, ptr, bytes);
+               tmp[bytes] = '\0';
+               string_unescape_any_inplace(tmp);
+               synth_printf("%s", tmp);
+               ptr += bytes;
+               len -= bytes;
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return count;
+}
+
+/*
+ * This function is called when a user reads the version.
+ */
+static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr,
+                           char *buf)
+{
+       char *cp;
+
+       cp = buf;
+       cp += sprintf(cp, "Speakup version %s\n", SPEAKUP_VERSION);
+       if (synth)
+               cp += sprintf(cp, "%s synthesizer driver version %s\n",
+               synth->name, synth->version);
+       return cp - buf;
+}
+
+/*
+ * This is called when a user reads the punctuation settings.
+ */
+static ssize_t punc_show(struct kobject *kobj, struct kobj_attribute *attr,
+                        char *buf)
+{
+       int i;
+       char *cp = buf;
+       struct st_var_header *p_header;
+       struct punc_var_t *var;
+       struct st_bits_data *pb;
+       short mask;
+       unsigned long flags;
+
+       p_header = spk_var_header_by_name(attr->attr.name);
+       if (!p_header) {
+               pr_warn("p_header is null, attr->attr.name is %s\n",
+                       attr->attr.name);
+               return -EINVAL;
+       }
+
+       var = spk_get_punc_var(p_header->var_id);
+       if (!var) {
+               pr_warn("var is null, p_header->var_id is %i\n",
+                       p_header->var_id);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       pb = (struct st_bits_data *)&spk_punc_info[var->value];
+       mask = pb->mask;
+       for (i = 33; i < 128; i++) {
+               if (!(spk_chartab[i] & mask))
+                       continue;
+               *cp++ = (char)i;
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return cp - buf;
+}
+
+/*
+ * This is called when a user changes the punctuation settings.
+ */
+static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr,
+                         const char *buf, size_t count)
+{
+       int x;
+       struct st_var_header *p_header;
+       struct punc_var_t *var;
+       char punc_buf[100];
+       unsigned long flags;
+
+       x = strlen(buf);
+       if (x < 1 || x > 99)
+               return -EINVAL;
+
+       p_header = spk_var_header_by_name(attr->attr.name);
+       if (!p_header) {
+               pr_warn("p_header is null, attr->attr.name is %s\n",
+                       attr->attr.name);
+               return -EINVAL;
+       }
+
+       var = spk_get_punc_var(p_header->var_id);
+       if (!var) {
+               pr_warn("var is null, p_header->var_id is %i\n",
+                       p_header->var_id);
+               return -EINVAL;
+       }
+
+       memcpy(punc_buf, buf, x);
+
+       while (x && punc_buf[x - 1] == '\n')
+               x--;
+       punc_buf[x] = '\0';
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+
+       if (*punc_buf == 'd' || *punc_buf == 'r')
+               x = spk_set_mask_bits(NULL, var->value, 3);
+       else
+               x = spk_set_mask_bits(punc_buf, var->value, 3);
+
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return count;
+}
+
+/*
+ * This function is called when a user reads one of the variable parameters.
+ */
+ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
+                    char *buf)
+{
+       int rv = 0;
+       struct st_var_header *param;
+       struct var_t *var;
+       char *cp1;
+       char *cp;
+       char ch;
+       unsigned long flags;
+
+       param = spk_var_header_by_name(attr->attr.name);
+       if (!param)
+               return -EINVAL;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       var = (struct var_t *)param->data;
+       switch (param->var_type) {
+       case VAR_NUM:
+       case VAR_TIME:
+               if (var)
+                       rv = sprintf(buf, "%i\n", var->u.n.value);
+               else
+                       rv = sprintf(buf, "0\n");
+               break;
+       case VAR_STRING:
+               if (var) {
+                       cp1 = buf;
+                       *cp1++ = '"';
+                       for (cp = (char *)param->p_val; (ch = *cp); cp++) {
+                               if (ch >= ' ' && ch < '~')
+                                       *cp1++ = ch;
+                               else
+                                       cp1 += sprintf(cp1, "\\x%02x", ch);
+                       }
+                       *cp1++ = '"';
+                       *cp1++ = '\n';
+                       *cp1 = '\0';
+                       rv = cp1 - buf;
+               } else {
+                       rv = sprintf(buf, "\"\"\n");
+               }
+               break;
+       default:
+               rv = sprintf(buf, "Bad parameter  %s, type %i\n",
+                            param->name, param->var_type);
+               break;
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return rv;
+}
+EXPORT_SYMBOL_GPL(spk_var_show);
+
+/*
+ * Used to reset either default_pitch or default_vol.
+ */
+static inline void spk_reset_default_value(char *header_name,
+                                          int *synth_default_value, int idx)
+{
+       struct st_var_header *param;
+
+       if (synth && synth_default_value) {
+               param = spk_var_header_by_name(header_name);
+               if (param)  {
+                       spk_set_num_var(synth_default_value[idx],
+                                       param, E_NEW_DEFAULT);
+                       spk_set_num_var(0, param, E_DEFAULT);
+                       pr_info("%s reset to default value\n", param->name);
+               }
+       }
+}
+
+/*
+ * This function is called when a user echos a value to one of the
+ * variable parameters.
+ */
+ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
+                     const char *buf, size_t count)
+{
+       struct st_var_header *param;
+       int ret;
+       int len;
+       char *cp;
+       struct var_t *var_data;
+       long value;
+       unsigned long flags;
+
+       param = spk_var_header_by_name(attr->attr.name);
+       if (!param)
+               return -EINVAL;
+       if (!param->data)
+               return 0;
+       ret = 0;
+       cp = (char *)buf;
+       string_unescape_any_inplace(cp);
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       switch (param->var_type) {
+       case VAR_NUM:
+       case VAR_TIME:
+               if (*cp == 'd' || *cp == 'r' || *cp == '\0')
+                       len = E_DEFAULT;
+               else if (*cp == '+' || *cp == '-')
+                       len = E_INC;
+               else
+                       len = E_SET;
+               if (kstrtol(cp, 10, &value) == 0)
+                       ret = spk_set_num_var(value, param, len);
+               else
+                       pr_warn("overflow or parsing error has occurred");
+               if (ret == -ERANGE) {
+                       var_data = param->data;
+                       pr_warn("value for %s out of range, expect %d to %d\n",
+                               param->name,
+                               var_data->u.n.low, var_data->u.n.high);
+               }
+
+              /*
+               * If voice was just changed, we might need to reset our default
+               * pitch and volume.
+               */
+               if (param->var_id == VOICE && synth &&
+                   (ret == 0 || ret == -ERESTART)) {
+                       var_data = param->data;
+                       value = var_data->u.n.value;
+                       spk_reset_default_value("pitch", synth->default_pitch,
+                                               value);
+                       spk_reset_default_value("vol", synth->default_vol,
+                                               value);
+               }
+               break;
+       case VAR_STRING:
+               len = strlen(cp);
+               if ((len >= 1) && (cp[len - 1] == '\n'))
+                       --len;
+               if ((len >= 2) && (cp[0] == '"') && (cp[len - 1] == '"')) {
+                       ++cp;
+                       len -= 2;
+               }
+               cp[len] = '\0';
+               ret = spk_set_string_var(cp, param, len);
+               if (ret == -E2BIG)
+                       pr_warn("value too long for %s\n",
+                               param->name);
+               break;
+       default:
+               pr_warn("%s unknown type %d\n",
+                       param->name, (int)param->var_type);
+       break;
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+
+       if (ret == -ERESTART)
+               pr_info("%s reset to default value\n", param->name);
+       return count;
+}
+EXPORT_SYMBOL_GPL(spk_var_store);
+
+/*
+ * Functions for reading and writing lists of i18n messages.  Incomplete.
+ */
+
+static ssize_t message_show_helper(char *buf, enum msg_index_t first,
+                                  enum msg_index_t last)
+{
+       size_t bufsize = PAGE_SIZE;
+       char *buf_pointer = buf;
+       int printed;
+       enum msg_index_t cursor;
+       int index = 0;
+       *buf_pointer = '\0'; /* buf_pointer always looking at a NUL byte. */
+
+       for (cursor = first; cursor <= last; cursor++, index++) {
+               if (bufsize <= 1)
+                       break;
+               printed = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
+                                   index, spk_msg_get(cursor));
+               buf_pointer += printed;
+               bufsize -= printed;
+       }
+
+       return buf_pointer - buf;
+}
+
+static void report_msg_status(int reset, int received, int used,
+                             int rejected, char *groupname)
+{
+       int len;
+       char buf[160];
+
+       if (reset) {
+               pr_info("i18n messages from group %s reset to defaults\n",
+                       groupname);
+       } else if (received) {
+               len = snprintf(buf, sizeof(buf),
+                              " updated %d of %d i18n messages from group %s\n",
+                                      used, received, groupname);
+               if (rejected)
+                       snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
+                                " with %d reject%s\n",
+                                rejected, rejected > 1 ? "s" : "");
+               pr_info("%s", buf);
+       }
+}
+
+static ssize_t message_store_helper(const char *buf, size_t count,
+                                   struct msg_group_t *group)
+{
+       char *cp = (char *)buf;
+       char *end = cp + count;
+       char *linefeed = NULL;
+       char *temp = NULL;
+       ssize_t msg_stored = 0;
+       ssize_t retval = count;
+       size_t desc_length = 0;
+       unsigned long index = 0;
+       int received = 0;
+       int used = 0;
+       int rejected = 0;
+       int reset = 0;
+       enum msg_index_t firstmessage = group->start;
+       enum msg_index_t lastmessage = group->end;
+       enum msg_index_t curmessage;
+
+       while (cp < end) {
+               while ((cp < end) && (*cp == ' ' || *cp == '\t'))
+                       cp++;
+
+               if (cp == end)
+                       break;
+               if (strchr("dDrR", *cp)) {
+                       reset = 1;
+                       break;
+               }
+               received++;
+
+               linefeed = strchr(cp, '\n');
+               if (!linefeed) {
+                       rejected++;
+                       break;
+               }
+
+               if (!isdigit(*cp)) {
+                       rejected++;
+                       cp = linefeed + 1;
+                       continue;
+               }
+
+               /*
+                * Do not replace with kstrtoul:
+                * here we need temp to be updated
+                */
+               index = simple_strtoul(cp, &temp, 10);
+
+               while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
+                       temp++;
+
+               desc_length = linefeed - temp;
+               curmessage = firstmessage + index;
+
+               /*
+                * Note the check (curmessage < firstmessage).  It is not
+                * redundant.  Suppose that the user gave us an index
+                * equal to ULONG_MAX - 1.  If firstmessage > 1, then
+                * firstmessage + index < firstmessage!
+                */
+
+               if ((curmessage < firstmessage) || (curmessage > lastmessage)) {
+                       rejected++;
+                       cp = linefeed + 1;
+                       continue;
+               }
+
+               msg_stored = spk_msg_set(curmessage, temp, desc_length);
+               if (msg_stored < 0) {
+                       retval = msg_stored;
+                       if (msg_stored == -ENOMEM)
+                               reset = 1;
+                       break;
+               }
+
+               used++;
+
+               cp = linefeed + 1;
+       }
+
+       if (reset)
+               spk_reset_msg_group(group);
+
+       report_msg_status(reset, received, used, rejected, group->name);
+       return retval;
+}
+
+static ssize_t message_show(struct kobject *kobj,
+                           struct kobj_attribute *attr, char *buf)
+{
+       ssize_t retval = 0;
+       struct msg_group_t *group = spk_find_msg_group(attr->attr.name);
+       unsigned long flags;
+
+       if (WARN_ON(!group))
+               return -EINVAL;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       retval = message_show_helper(buf, group->start, group->end);
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return retval;
+}
+
+static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct msg_group_t *group = spk_find_msg_group(attr->attr.name);
+
+       if (WARN_ON(!group))
+               return -EINVAL;
+
+       return message_store_helper(buf, count, group);
+}
+
+/*
+ * Declare the attributes.
+ */
+static struct kobj_attribute keymap_attribute =
+       __ATTR_RW(keymap);
+static struct kobj_attribute silent_attribute =
+       __ATTR_WO(silent);
+static struct kobj_attribute synth_attribute =
+       __ATTR_RW(synth);
+static struct kobj_attribute synth_direct_attribute =
+       __ATTR_WO(synth_direct);
+static struct kobj_attribute version_attribute =
+       __ATTR_RO(version);
+
+static struct kobj_attribute delimiters_attribute =
+       __ATTR(delimiters, 0644, punc_show, punc_store);
+static struct kobj_attribute ex_num_attribute =
+       __ATTR(ex_num, 0644, punc_show, punc_store);
+static struct kobj_attribute punc_all_attribute =
+       __ATTR(punc_all, 0644, punc_show, punc_store);
+static struct kobj_attribute punc_most_attribute =
+       __ATTR(punc_most, 0644, punc_show, punc_store);
+static struct kobj_attribute punc_some_attribute =
+       __ATTR(punc_some, 0644, punc_show, punc_store);
+static struct kobj_attribute repeats_attribute =
+       __ATTR(repeats, 0644, punc_show, punc_store);
+
+static struct kobj_attribute attrib_bleep_attribute =
+       __ATTR(attrib_bleep, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute bell_pos_attribute =
+       __ATTR(bell_pos, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute bleep_time_attribute =
+       __ATTR(bleep_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute bleeps_attribute =
+       __ATTR(bleeps, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute cursor_time_attribute =
+       __ATTR(cursor_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute key_echo_attribute =
+       __ATTR(key_echo, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute no_interrupt_attribute =
+       __ATTR(no_interrupt, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute punc_level_attribute =
+       __ATTR(punc_level, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute reading_punc_attribute =
+       __ATTR(reading_punc, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute say_control_attribute =
+       __ATTR(say_control, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute say_word_ctl_attribute =
+       __ATTR(say_word_ctl, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute spell_delay_attribute =
+       __ATTR(spell_delay, 0644, spk_var_show, spk_var_store);
+
+/*
+ * These attributes are i18n related.
+ */
+static struct kobj_attribute announcements_attribute =
+       __ATTR(announcements, 0644, message_show, message_store);
+static struct kobj_attribute characters_attribute =
+       __ATTR(characters, 0644, chars_chartab_show,
+              chars_chartab_store);
+static struct kobj_attribute chartab_attribute =
+       __ATTR(chartab, 0644, chars_chartab_show,
+              chars_chartab_store);
+static struct kobj_attribute ctl_keys_attribute =
+       __ATTR(ctl_keys, 0644, message_show, message_store);
+static struct kobj_attribute colors_attribute =
+       __ATTR(colors, 0644, message_show, message_store);
+static struct kobj_attribute formatted_attribute =
+       __ATTR(formatted, 0644, message_show, message_store);
+static struct kobj_attribute function_names_attribute =
+       __ATTR(function_names, 0644, message_show, message_store);
+static struct kobj_attribute key_names_attribute =
+       __ATTR(key_names, 0644, message_show, message_store);
+static struct kobj_attribute states_attribute =
+       __ATTR(states, 0644, message_show, message_store);
+
+/*
+ * Create groups of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *main_attrs[] = {
+       &keymap_attribute.attr,
+       &silent_attribute.attr,
+       &synth_attribute.attr,
+       &synth_direct_attribute.attr,
+       &version_attribute.attr,
+       &delimiters_attribute.attr,
+       &ex_num_attribute.attr,
+       &punc_all_attribute.attr,
+       &punc_most_attribute.attr,
+       &punc_some_attribute.attr,
+       &repeats_attribute.attr,
+       &attrib_bleep_attribute.attr,
+       &bell_pos_attribute.attr,
+       &bleep_time_attribute.attr,
+       &bleeps_attribute.attr,
+       &cursor_time_attribute.attr,
+       &key_echo_attribute.attr,
+       &no_interrupt_attribute.attr,
+       &punc_level_attribute.attr,
+       &reading_punc_attribute.attr,
+       &say_control_attribute.attr,
+       &say_word_ctl_attribute.attr,
+       &spell_delay_attribute.attr,
+       NULL,
+};
+
+static struct attribute *i18n_attrs[] = {
+       &announcements_attribute.attr,
+       &characters_attribute.attr,
+       &chartab_attribute.attr,
+       &ctl_keys_attribute.attr,
+       &colors_attribute.attr,
+       &formatted_attribute.attr,
+       &function_names_attribute.attr,
+       &key_names_attribute.attr,
+       &states_attribute.attr,
+       NULL,
+};
+
+/*
+ * An unnamed attribute group will put all of the attributes directly in
+ * the kobject directory.  If we specify a name, a subdirectory will be
+ * created for the attributes with the directory being the name of the
+ * attribute group.
+ */
+static const struct attribute_group main_attr_group = {
+       .attrs = main_attrs,
+};
+
+static const struct attribute_group i18n_attr_group = {
+       .attrs = i18n_attrs,
+       .name = "i18n",
+};
+
+static struct kobject *accessibility_kobj;
+struct kobject *speakup_kobj;
+
+int speakup_kobj_init(void)
+{
+       int retval;
+
+       /*
+        * Create a simple kobject with the name of "accessibility",
+        * located under /sys/
+        *
+        * As this is a simple directory, no uevent will be sent to
+        * userspace.  That is why this function should not be used for
+        * any type of dynamic kobjects, where the name and number are
+        * not known ahead of time.
+        */
+       accessibility_kobj = kobject_create_and_add("accessibility", NULL);
+       if (!accessibility_kobj) {
+               retval = -ENOMEM;
+               goto out;
+       }
+
+       speakup_kobj = kobject_create_and_add("speakup", accessibility_kobj);
+       if (!speakup_kobj) {
+               retval = -ENOMEM;
+               goto err_acc;
+       }
+
+       /* Create the files associated with this kobject */
+       retval = sysfs_create_group(speakup_kobj, &main_attr_group);
+       if (retval)
+               goto err_speakup;
+
+       retval = sysfs_create_group(speakup_kobj, &i18n_attr_group);
+       if (retval)
+               goto err_group;
+
+       goto out;
+
+err_group:
+       sysfs_remove_group(speakup_kobj, &main_attr_group);
+err_speakup:
+       kobject_put(speakup_kobj);
+err_acc:
+       kobject_put(accessibility_kobj);
+out:
+       return retval;
+}
+
+void speakup_kobj_exit(void)
+{
+       sysfs_remove_group(speakup_kobj, &i18n_attr_group);
+       sysfs_remove_group(speakup_kobj, &main_attr_group);
+       kobject_put(speakup_kobj);
+       kobject_put(accessibility_kobj);
+}
diff --git a/drivers/accessibility/speakup/main.c b/drivers/accessibility/speakup/main.c
new file mode 100644 (file)
index 0000000..02471d9
--- /dev/null
@@ -0,0 +1,2460 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* speakup.c
+ * review functions for the speakup screen review package.
+ * originally written by: Kirk Reiser and Andy Berdan.
+ *
+ * extensively modified by David Borowski.
+ *
+ ** Copyright (C) 1998  Kirk Reiser.
+ *  Copyright (C) 2003  David Borowski.
+ */
+
+#include <linux/kernel.h>
+#include <linux/vt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>          /* __get_free_page() and friends */
+#include <linux/vt_kern.h>
+#include <linux/ctype.h>
+#include <linux/selection.h>
+#include <linux/unistd.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <linux/keyboard.h>    /* for KT_SHIFT */
+#include <linux/kbd_kern.h>    /* for vc_kbd_* and friends */
+#include <linux/input.h>
+#include <linux/kmod.h>
+
+/* speakup_*_selection */
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/consolemap.h>
+
+#include <linux/spinlock.h>
+#include <linux/notifier.h>
+
+#include <linux/uaccess.h>     /* copy_from|to|user() and others */
+
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define MAX_DELAY msecs_to_jiffies(500)
+#define MINECHOCHAR SPACE
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
+MODULE_DESCRIPTION("Speakup console speech");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SPEAKUP_VERSION);
+
+char *synth_name;
+module_param_named(synth, synth_name, charp, 0444);
+module_param_named(quiet, spk_quiet_boot, bool, 0444);
+
+MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
+MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
+
+special_func spk_special_handler;
+
+short spk_pitch_shift, synth_flags;
+static u16 buf[256];
+int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
+int spk_no_intr, spk_spell_delay;
+int spk_key_echo, spk_say_word_ctl;
+int spk_say_ctrl, spk_bell_pos;
+short spk_punc_mask;
+int spk_punc_level, spk_reading_punc;
+char spk_str_caps_start[MAXVARLEN + 1] = "\0";
+char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
+char spk_str_pause[MAXVARLEN + 1] = "\0";
+bool spk_paused;
+const struct st_bits_data spk_punc_info[] = {
+       {"none", "", 0},
+       {"some", "/$%&@", SOME},
+       {"most", "$%&#()=+*/@^<>|\\", MOST},
+       {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
+       {"delimiters", "", B_WDLM},
+       {"repeats", "()", CH_RPT},
+       {"extended numeric", "", B_EXNUM},
+       {"symbols", "", B_SYM},
+       {NULL, NULL}
+};
+
+static char mark_cut_flag;
+#define MAX_KEY 160
+static u_char *spk_shift_table;
+u_char *spk_our_keys[MAX_KEY];
+u_char spk_key_buf[600];
+const u_char spk_key_defaults[] = {
+#include "speakupmap.h"
+};
+
+/* Speakup Cursor Track Variables */
+static int cursor_track = 1, prev_cursor_track = 1;
+
+/* cursor track modes, must be ordered same as cursor_msgs */
+enum {
+       CT_Off = 0,
+       CT_On,
+       CT_Highlight,
+       CT_Window,
+       CT_Max
+};
+
+#define read_all_mode CT_Max
+
+static struct tty_struct *tty;
+
+static void spkup_write(const u16 *in_buf, int count);
+
+static char *phonetic[] = {
+       "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
+       "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
+           "papa",
+       "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
+       "x ray", "yankee", "zulu"
+};
+
+/* array of 256 char pointers (one for each character description)
+ * initialized to default_chars and user selectable via
+ * /proc/speakup/characters
+ */
+char *spk_characters[256];
+
+char *spk_default_chars[256] = {
+/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
+/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
+/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
+/*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
+           "control",
+/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
+           "tick",
+/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
+           "dot",
+       "slash",
+/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
+       "eight", "nine",
+/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
+/*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
+/*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
+/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
+/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
+           "caret",
+       "line",
+/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
+/*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
+/*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
+/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
+/*127*/ "del", "control", "control", "control", "control", "control",
+           "control", "control", "control", "control", "control",
+/*138*/ "control", "control", "control", "control", "control",
+           "control", "control", "control", "control", "control",
+           "control", "control",
+/*150*/ "control", "control", "control", "control", "control",
+           "control", "control", "control", "control", "control",
+/*160*/ "nbsp", "inverted bang",
+/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
+/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
+/*172*/ "not", "soft hyphen", "registered", "macron",
+/*176*/ "degrees", "plus or minus", "super two", "super three",
+/*180*/ "acute accent", "micro", "pilcrow", "middle dot",
+/*184*/ "cedilla", "super one", "male ordinal", "double right angle",
+/*188*/ "one quarter", "one half", "three quarters",
+           "inverted question",
+/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
+           "A RING",
+/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
+           "E OOMLAUT",
+/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
+           "N TILDE",
+/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
+/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
+           "U CIRCUMFLEX",
+/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
+/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
+/*230*/ "ae", "c cidella", "e grave", "e acute",
+/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
+           "i circumflex",
+/*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
+           "o circumflex",
+/*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
+           "u acute",
+/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
+};
+
+/* array of 256 u_short (one for each character)
+ * initialized to default_chartab and user selectable via
+ * /sys/module/speakup/parameters/chartab
+ */
+u_short spk_chartab[256];
+
+static u_short default_chartab[256] = {
+       B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
+       B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
+       B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
+       B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
+       WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,     /*  !"#$%&' */
+       PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC,   /* ()*+, -./ */
+       NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
+       NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,       /* 89:;<=>? */
+       PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,  /* @ABCDEFG */
+       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
+       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
+       A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC,      /* XYZ[\]^_ */
+       PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,  /* `abcdefg */
+       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
+       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
+       ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
+       B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
+       B_SYM,  /* 135 */
+       B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
+       B_CAPSYM,       /* 143 */
+       B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
+       B_SYM,  /* 151 */
+       B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
+       B_SYM,  /* 159 */
+       WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
+       B_SYM,  /* 167 */
+       B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
+       B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
+       B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
+       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
+       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
+       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
+       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
+       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
+       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
+       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
+       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA  /* 248-255 */
+};
+
+struct task_struct *speakup_task;
+struct bleep spk_unprocessed_sound;
+static int spk_keydown;
+static u16 spk_lastkey;
+static u_char spk_close_press, keymap_flags;
+static u_char last_keycode, this_speakup_key;
+static u_long last_spk_jiffy;
+
+struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
+
+DEFINE_MUTEX(spk_mutex);
+
+static int keyboard_notifier_call(struct notifier_block *,
+                                 unsigned long code, void *param);
+
+static struct notifier_block keyboard_notifier_block = {
+       .notifier_call = keyboard_notifier_call,
+};
+
+static int vt_notifier_call(struct notifier_block *,
+                           unsigned long code, void *param);
+
+static struct notifier_block vt_notifier_block = {
+       .notifier_call = vt_notifier_call,
+};
+
+static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
+{
+       pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
+       return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
+}
+
+static void speakup_date(struct vc_data *vc)
+{
+       spk_x = spk_cx = vc->vc_x;
+       spk_y = spk_cy = vc->vc_y;
+       spk_pos = spk_cp = vc->vc_pos;
+       spk_old_attr = spk_attr;
+       spk_attr = get_attributes(vc, (u_short *)spk_pos);
+}
+
+static void bleep(u_short val)
+{
+       static const short vals[] = {
+               350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
+       };
+       short freq;
+       int time = spk_bleep_time;
+
+       freq = vals[val % 12];
+       if (val > 11)
+               freq *= (1 << (val / 12));
+       spk_unprocessed_sound.freq = freq;
+       spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
+       spk_unprocessed_sound.active = 1;
+       /* We can only have 1 active sound at a time. */
+}
+
+static void speakup_shut_up(struct vc_data *vc)
+{
+       if (spk_killed)
+               return;
+       spk_shut_up |= 0x01;
+       spk_parked &= 0xfe;
+       speakup_date(vc);
+       if (synth)
+               spk_do_flush();
+}
+
+static void speech_kill(struct vc_data *vc)
+{
+       char val = synth->is_alive(synth);
+
+       if (val == 0)
+               return;
+
+       /* re-enables synth, if disabled */
+       if (val == 2 || spk_killed) {
+               /* dead */
+               spk_shut_up &= ~0x40;
+               synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
+       } else {
+               synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
+               spk_shut_up |= 0x40;
+       }
+}
+
+static void speakup_off(struct vc_data *vc)
+{
+       if (spk_shut_up & 0x80) {
+               spk_shut_up &= 0x7f;
+               synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
+       } else {
+               spk_shut_up |= 0x80;
+               synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
+       }
+       speakup_date(vc);
+}
+
+static void speakup_parked(struct vc_data *vc)
+{
+       if (spk_parked & 0x80) {
+               spk_parked = 0;
+               synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
+       } else {
+               spk_parked |= 0x80;
+               synth_printf("%s\n", spk_msg_get(MSG_PARKED));
+       }
+}
+
+static void speakup_cut(struct vc_data *vc)
+{
+       static const char err_buf[] = "set selection failed";
+       int ret;
+
+       if (!mark_cut_flag) {
+               mark_cut_flag = 1;
+               spk_xs = (u_short)spk_x;
+               spk_ys = (u_short)spk_y;
+               spk_sel_cons = vc;
+               synth_printf("%s\n", spk_msg_get(MSG_MARK));
+               return;
+       }
+       spk_xe = (u_short)spk_x;
+       spk_ye = (u_short)spk_y;
+       mark_cut_flag = 0;
+       synth_printf("%s\n", spk_msg_get(MSG_CUT));
+
+       speakup_clear_selection();
+       ret = speakup_set_selection(tty);
+
+       switch (ret) {
+       case 0:
+               break;          /* no error */
+       case -EFAULT:
+               pr_warn("%sEFAULT\n", err_buf);
+               break;
+       case -EINVAL:
+               pr_warn("%sEINVAL\n", err_buf);
+               break;
+       case -ENOMEM:
+               pr_warn("%sENOMEM\n", err_buf);
+               break;
+       }
+}
+
+static void speakup_paste(struct vc_data *vc)
+{
+       if (mark_cut_flag) {
+               mark_cut_flag = 0;
+               synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
+       } else {
+               synth_printf("%s\n", spk_msg_get(MSG_PASTE));
+               speakup_paste_selection(tty);
+       }
+}
+
+static void say_attributes(struct vc_data *vc)
+{
+       int fg = spk_attr & 0x0f;
+       int bg = spk_attr >> 4;
+
+       if (fg > 8) {
+               synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
+               fg -= 8;
+       }
+       synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
+       if (bg > 7) {
+               synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
+               bg -= 8;
+       } else {
+               synth_printf(" %s ", spk_msg_get(MSG_ON));
+       }
+       synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
+}
+
+enum {
+       edge_top = 1,
+       edge_bottom,
+       edge_left,
+       edge_right,
+       edge_quiet
+};
+
+static void announce_edge(struct vc_data *vc, int msg_id)
+{
+       if (spk_bleeps & 1)
+               bleep(spk_y);
+       if ((spk_bleeps & 2) && (msg_id < edge_quiet))
+               synth_printf("%s\n",
+                            spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
+}
+
+static void speak_char(u16 ch)
+{
+       char *cp;
+       struct var_t *direct = spk_get_var(DIRECT);
+
+       if (ch >= 0x100 || (direct && direct->u.n.value)) {
+               if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
+                       spk_pitch_shift++;
+                       synth_printf("%s", spk_str_caps_start);
+               }
+               synth_putwc_s(ch);
+               if (ch < 0x100 && IS_CHAR(ch, B_CAP))
+                       synth_printf("%s", spk_str_caps_stop);
+               return;
+       }
+
+       cp = spk_characters[ch];
+       if (!cp) {
+               pr_info("%s: cp == NULL!\n", __func__);
+               return;
+       }
+       if (IS_CHAR(ch, B_CAP)) {
+               spk_pitch_shift++;
+               synth_printf("%s %s %s",
+                            spk_str_caps_start, cp, spk_str_caps_stop);
+       } else {
+               if (*cp == '^') {
+                       cp++;
+                       synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
+               } else {
+                       synth_printf(" %s ", cp);
+               }
+       }
+}
+
+static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
+{
+       u16 ch = ' ';
+
+       if (vc && pos) {
+               u16 w;
+               u16 c;
+
+               pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
+               w = scr_readw(pos);
+               c = w & 0xff;
+
+               if (w & vc->vc_hi_font_mask) {
+                       w &= ~vc->vc_hi_font_mask;
+                       c |= 0x100;
+               }
+
+               ch = inverse_translate(vc, c, 1);
+               *attribs = (w & 0xff00) >> 8;
+       }
+       return ch;
+}
+
+static void say_char(struct vc_data *vc)
+{
+       u16 ch;
+
+       spk_old_attr = spk_attr;
+       ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
+       if (spk_attr != spk_old_attr) {
+               if (spk_attrib_bleep & 1)
+                       bleep(spk_y);
+               if (spk_attrib_bleep & 2)
+                       say_attributes(vc);
+       }
+       speak_char(ch);
+}
+
+static void say_phonetic_char(struct vc_data *vc)
+{
+       u16 ch;
+
+       spk_old_attr = spk_attr;
+       ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
+       if (ch <= 0x7f && isalpha(ch)) {
+               ch &= 0x1f;
+               synth_printf("%s\n", phonetic[--ch]);
+       } else {
+               if (ch < 0x100 && IS_CHAR(ch, B_NUM))
+                       synth_printf("%s ", spk_msg_get(MSG_NUMBER));
+               speak_char(ch);
+       }
+}
+
+static void say_prev_char(struct vc_data *vc)
+{
+       spk_parked |= 0x01;
+       if (spk_x == 0) {
+               announce_edge(vc, edge_left);
+               return;
+       }
+       spk_x--;
+       spk_pos -= 2;
+       say_char(vc);
+}
+
+static void say_next_char(struct vc_data *vc)
+{
+       spk_parked |= 0x01;
+       if (spk_x == vc->vc_cols - 1) {
+               announce_edge(vc, edge_right);
+               return;
+       }
+       spk_x++;
+       spk_pos += 2;
+       say_char(vc);
+}
+
+/* get_word - will first check to see if the character under the
+ * reading cursor is a space and if spk_say_word_ctl is true it will
+ * return the word space.  If spk_say_word_ctl is not set it will check to
+ * see if there is a word starting on the next position to the right
+ * and return that word if it exists.  If it does not exist it will
+ * move left to the beginning of any previous word on the line or the
+ * beginning off the line whichever comes first..
+ */
+
+static u_long get_word(struct vc_data *vc)
+{
+       u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
+       u16 ch;
+       u16 attr_ch;
+       u_char temp;
+
+       spk_old_attr = spk_attr;
+       ch = get_char(vc, (u_short *)tmp_pos, &temp);
+
+/* decided to take out the sayword if on a space (mis-information */
+       if (spk_say_word_ctl && ch == SPACE) {
+               *buf = '\0';
+               synth_printf("%s\n", spk_msg_get(MSG_SPACE));
+               return 0;
+       } else if (tmpx < vc->vc_cols - 2 &&
+                  (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
+                  get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
+               tmp_pos += 2;
+               tmpx++;
+       } else {
+               while (tmpx > 0) {
+                       ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
+                       if ((ch == SPACE || ch == 0 ||
+                            (ch < 0x100 && IS_WDLM(ch))) &&
+                           get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
+                               break;
+                       tmp_pos -= 2;
+                       tmpx--;
+               }
+       }
+       attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
+       buf[cnt++] = attr_ch;
+       while (tmpx < vc->vc_cols - 1) {
+               tmp_pos += 2;
+               tmpx++;
+               ch = get_char(vc, (u_short *)tmp_pos, &temp);
+               if (ch == SPACE || ch == 0 ||
+                   (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
+                    ch > SPACE))
+                       break;
+               buf[cnt++] = ch;
+       }
+       buf[cnt] = '\0';
+       return cnt;
+}
+
+static void say_word(struct vc_data *vc)
+{
+       u_long cnt = get_word(vc);
+       u_short saved_punc_mask = spk_punc_mask;
+
+       if (cnt == 0)
+               return;
+       spk_punc_mask = PUNC;
+       buf[cnt++] = SPACE;
+       spkup_write(buf, cnt);
+       spk_punc_mask = saved_punc_mask;
+}
+
+static void say_prev_word(struct vc_data *vc)
+{
+       u_char temp;
+       u16 ch;
+       u_short edge_said = 0, last_state = 0, state = 0;
+
+       spk_parked |= 0x01;
+
+       if (spk_x == 0) {
+               if (spk_y == 0) {
+                       announce_edge(vc, edge_top);
+                       return;
+               }
+               spk_y--;
+               spk_x = vc->vc_cols;
+               edge_said = edge_quiet;
+       }
+       while (1) {
+               if (spk_x == 0) {
+                       if (spk_y == 0) {
+                               edge_said = edge_top;
+                               break;
+                       }
+                       if (edge_said != edge_quiet)
+                               edge_said = edge_left;
+                       if (state > 0)
+                               break;
+                       spk_y--;
+                       spk_x = vc->vc_cols - 1;
+               } else {
+                       spk_x--;
+               }
+               spk_pos -= 2;
+               ch = get_char(vc, (u_short *)spk_pos, &temp);
+               if (ch == SPACE || ch == 0)
+                       state = 0;
+               else if (ch < 0x100 && IS_WDLM(ch))
+                       state = 1;
+               else
+                       state = 2;
+               if (state < last_state) {
+                       spk_pos += 2;
+                       spk_x++;
+                       break;
+               }
+               last_state = state;
+       }
+       if (spk_x == 0 && edge_said == edge_quiet)
+               edge_said = edge_left;
+       if (edge_said > 0 && edge_said < edge_quiet)
+               announce_edge(vc, edge_said);
+       say_word(vc);
+}
+
+static void say_next_word(struct vc_data *vc)
+{
+       u_char temp;
+       u16 ch;
+       u_short edge_said = 0, last_state = 2, state = 0;
+
+       spk_parked |= 0x01;
+       if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
+               announce_edge(vc, edge_bottom);
+               return;
+       }
+       while (1) {
+               ch = get_char(vc, (u_short *)spk_pos, &temp);
+               if (ch == SPACE || ch == 0)
+                       state = 0;
+               else if (ch < 0x100 && IS_WDLM(ch))
+                       state = 1;
+               else
+                       state = 2;
+               if (state > last_state)
+                       break;
+               if (spk_x >= vc->vc_cols - 1) {
+                       if (spk_y == vc->vc_rows - 1) {
+                               edge_said = edge_bottom;
+                               break;
+                       }
+                       state = 0;
+                       spk_y++;
+                       spk_x = 0;
+                       edge_said = edge_right;
+               } else {
+                       spk_x++;
+               }
+               spk_pos += 2;
+               last_state = state;
+       }
+       if (edge_said > 0)
+               announce_edge(vc, edge_said);
+       say_word(vc);
+}
+
+static void spell_word(struct vc_data *vc)
+{
+       static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
+       u16 *cp = buf;
+       char *cp1;
+       char *str_cap = spk_str_caps_stop;
+       char *last_cap = spk_str_caps_stop;
+       struct var_t *direct = spk_get_var(DIRECT);
+       u16 ch;
+
+       if (!get_word(vc))
+               return;
+       while ((ch = *cp)) {
+               if (cp != buf)
+                       synth_printf(" %s ", delay_str[spk_spell_delay]);
+               /* FIXME: Non-latin1 considered as lower case */
+               if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
+                       str_cap = spk_str_caps_start;
+                       if (*spk_str_caps_stop)
+                               spk_pitch_shift++;
+                       else    /* synth has no pitch */
+                               last_cap = spk_str_caps_stop;
+               } else {
+                       str_cap = spk_str_caps_stop;
+               }
+               if (str_cap != last_cap) {
+                       synth_printf("%s", str_cap);
+                       last_cap = str_cap;
+               }
+               if (ch >= 0x100 || (direct && direct->u.n.value)) {
+                       synth_putwc_s(ch);
+               } else if (this_speakup_key == SPELL_PHONETIC &&
+                   ch <= 0x7f && isalpha(ch)) {
+                       ch &= 0x1f;
+                       cp1 = phonetic[--ch];
+                       synth_printf("%s", cp1);
+               } else {
+                       cp1 = spk_characters[ch];
+                       if (*cp1 == '^') {
+                               synth_printf("%s", spk_msg_get(MSG_CTRL));
+                               cp1++;
+                       }
+                       synth_printf("%s", cp1);
+               }
+               cp++;
+       }
+       if (str_cap != spk_str_caps_stop)
+               synth_printf("%s", spk_str_caps_stop);
+}
+
+static int get_line(struct vc_data *vc)
+{
+       u_long tmp = spk_pos - (spk_x * 2);
+       int i = 0;
+       u_char tmp2;
+
+       spk_old_attr = spk_attr;
+       spk_attr = get_attributes(vc, (u_short *)spk_pos);
+       for (i = 0; i < vc->vc_cols; i++) {
+               buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
+               tmp += 2;
+       }
+       for (--i; i >= 0; i--)
+               if (buf[i] != SPACE)
+                       break;
+       return ++i;
+}
+
+static void say_line(struct vc_data *vc)
+{
+       int i = get_line(vc);
+       u16 *cp;
+       u_short saved_punc_mask = spk_punc_mask;
+
+       if (i == 0) {
+               synth_printf("%s\n", spk_msg_get(MSG_BLANK));
+               return;
+       }
+       buf[i++] = '\n';
+       if (this_speakup_key == SAY_LINE_INDENT) {
+               cp = buf;
+               while (*cp == SPACE)
+                       cp++;
+               synth_printf("%zd, ", (cp - buf) + 1);
+       }
+       spk_punc_mask = spk_punc_masks[spk_reading_punc];
+       spkup_write(buf, i);
+       spk_punc_mask = saved_punc_mask;
+}
+
+static void say_prev_line(struct vc_data *vc)
+{
+       spk_parked |= 0x01;
+       if (spk_y == 0) {
+               announce_edge(vc, edge_top);
+               return;
+       }
+       spk_y--;
+       spk_pos -= vc->vc_size_row;
+       say_line(vc);
+}
+
+static void say_next_line(struct vc_data *vc)
+{
+       spk_parked |= 0x01;
+       if (spk_y == vc->vc_rows - 1) {
+               announce_edge(vc, edge_bottom);
+               return;
+       }
+       spk_y++;
+       spk_pos += vc->vc_size_row;
+       say_line(vc);
+}
+
+static int say_from_to(struct vc_data *vc, u_long from, u_long to,
+                      int read_punc)
+{
+       int i = 0;
+       u_char tmp;
+       u_short saved_punc_mask = spk_punc_mask;
+
+       spk_old_attr = spk_attr;
+       spk_attr = get_attributes(vc, (u_short *)from);
+       while (from < to) {
+               buf[i++] = get_char(vc, (u_short *)from, &tmp);
+               from += 2;
+               if (i >= vc->vc_size_row)
+                       break;
+       }
+       for (--i; i >= 0; i--)
+               if (buf[i] != SPACE)
+                       break;
+       buf[++i] = SPACE;
+       buf[++i] = '\0';
+       if (i < 1)
+               return i;
+       if (read_punc)
+               spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
+       spkup_write(buf, i);
+       if (read_punc)
+               spk_punc_mask = saved_punc_mask;
+       return i - 1;
+}
+
+static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
+                            int read_punc)
+{
+       u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
+       u_long end = start + (to * 2);
+
+       start += from * 2;
+       if (say_from_to(vc, start, end, read_punc) <= 0)
+               if (cursor_track != read_all_mode)
+                       synth_printf("%s\n", spk_msg_get(MSG_BLANK));
+}
+
+/* Sentence Reading Commands */
+
+static int currsentence;
+static int numsentences[2];
+static u16 *sentbufend[2];
+static u16 *sentmarks[2][10];
+static int currbuf;
+static int bn;
+static u16 sentbuf[2][256];
+
+static int say_sentence_num(int num, int prev)
+{
+       bn = currbuf;
+       currsentence = num + 1;
+       if (prev && --bn == -1)
+               bn = 1;
+
+       if (num > numsentences[bn])
+               return 0;
+
+       spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
+       return 1;
+}
+
+static int get_sentence_buf(struct vc_data *vc, int read_punc)
+{
+       u_long start, end;
+       int i, bn;
+       u_char tmp;
+
+       currbuf++;
+       if (currbuf == 2)
+               currbuf = 0;
+       bn = currbuf;
+       start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
+       end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
+
+       numsentences[bn] = 0;
+       sentmarks[bn][0] = &sentbuf[bn][0];
+       i = 0;
+       spk_old_attr = spk_attr;
+       spk_attr = get_attributes(vc, (u_short *)start);
+
+       while (start < end) {
+               sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
+               if (i > 0) {
+                       if (sentbuf[bn][i] == SPACE &&
+                           sentbuf[bn][i - 1] == '.' &&
+                           numsentences[bn] < 9) {
+                               /* Sentence Marker */
+                               numsentences[bn]++;
+                               sentmarks[bn][numsentences[bn]] =
+                                   &sentbuf[bn][i];
+                       }
+               }
+               i++;
+               start += 2;
+               if (i >= vc->vc_size_row)
+                       break;
+       }
+
+       for (--i; i >= 0; i--)
+               if (sentbuf[bn][i] != SPACE)
+                       break;
+
+       if (i < 1)
+               return -1;
+
+       sentbuf[bn][++i] = SPACE;
+       sentbuf[bn][++i] = '\0';
+
+       sentbufend[bn] = &sentbuf[bn][i];
+       return numsentences[bn];
+}
+
+static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
+{
+       u_long start = vc->vc_origin, end;
+
+       if (from > 0)
+               start += from * vc->vc_size_row;
+       if (to > vc->vc_rows)
+               to = vc->vc_rows;
+       end = vc->vc_origin + (to * vc->vc_size_row);
+       for (from = start; from < end; from = to) {
+               to = from + vc->vc_size_row;
+               say_from_to(vc, from, to, 1);
+       }
+}
+
+static void say_screen(struct vc_data *vc)
+{
+       say_screen_from_to(vc, 0, vc->vc_rows);
+}
+
+static void speakup_win_say(struct vc_data *vc)
+{
+       u_long start, end, from, to;
+
+       if (win_start < 2) {
+               synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
+               return;
+       }
+       start = vc->vc_origin + (win_top * vc->vc_size_row);
+       end = vc->vc_origin + (win_bottom * vc->vc_size_row);
+       while (start <= end) {
+               from = start + (win_left * 2);
+               to = start + (win_right * 2);
+               say_from_to(vc, from, to, 1);
+               start += vc->vc_size_row;
+       }
+}
+
+static void top_edge(struct vc_data *vc)
+{
+       spk_parked |= 0x01;
+       spk_pos = vc->vc_origin + 2 * spk_x;
+       spk_y = 0;
+       say_line(vc);
+}
+
+static void bottom_edge(struct vc_data *vc)
+{
+       spk_parked |= 0x01;
+       spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
+       spk_y = vc->vc_rows - 1;
+       say_line(vc);
+}
+
+static void left_edge(struct vc_data *vc)
+{
+       spk_parked |= 0x01;
+       spk_pos -= spk_x * 2;
+       spk_x = 0;
+       say_char(vc);
+}
+
+static void right_edge(struct vc_data *vc)
+{
+       spk_parked |= 0x01;
+       spk_pos += (vc->vc_cols - spk_x - 1) * 2;
+       spk_x = vc->vc_cols - 1;
+       say_char(vc);
+}
+
+static void say_first_char(struct vc_data *vc)
+{
+       int i, len = get_line(vc);
+       u16 ch;
+
+       spk_parked |= 0x01;
+       if (len == 0) {
+               synth_printf("%s\n", spk_msg_get(MSG_BLANK));
+               return;
+       }
+       for (i = 0; i < len; i++)
+               if (buf[i] != SPACE)
+                       break;
+       ch = buf[i];
+       spk_pos -= (spk_x - i) * 2;
+       spk_x = i;
+       synth_printf("%d, ", ++i);
+       speak_char(ch);
+}
+
+static void say_last_char(struct vc_data *vc)
+{
+       int len = get_line(vc);
+       u16 ch;
+
+       spk_parked |= 0x01;
+       if (len == 0) {
+               synth_printf("%s\n", spk_msg_get(MSG_BLANK));
+               return;
+       }
+       ch = buf[--len];
+       spk_pos -= (spk_x - len) * 2;
+       spk_x = len;
+       synth_printf("%d, ", ++len);
+       speak_char(ch);
+}
+
+static void say_position(struct vc_data *vc)
+{
+       synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
+                    vc->vc_num + 1);
+       synth_printf("\n");
+}
+
+/* Added by brianb */
+static void say_char_num(struct vc_data *vc)
+{
+       u_char tmp;
+       u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
+
+       synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
+}
+
+/* these are stub functions to keep keyboard.c happy. */
+
+static void say_from_top(struct vc_data *vc)
+{
+       say_screen_from_to(vc, 0, spk_y);
+}
+
+static void say_to_bottom(struct vc_data *vc)
+{
+       say_screen_from_to(vc, spk_y, vc->vc_rows);
+}
+
+static void say_from_left(struct vc_data *vc)
+{
+       say_line_from_to(vc, 0, spk_x, 1);
+}
+
+static void say_to_right(struct vc_data *vc)
+{
+       say_line_from_to(vc, spk_x, vc->vc_cols, 1);
+}
+
+/* end of stub functions. */
+
+static void spkup_write(const u16 *in_buf, int count)
+{
+       static int rep_count;
+       static u16 ch = '\0', old_ch = '\0';
+       static u_short char_type, last_type;
+       int in_count = count;
+
+       spk_keydown = 0;
+       while (count--) {
+               if (cursor_track == read_all_mode) {
+                       /* Insert Sentence Index */
+                       if ((in_buf == sentmarks[bn][currsentence]) &&
+                           (currsentence <= numsentences[bn]))
+                               synth_insert_next_index(currsentence++);
+               }
+               ch = *in_buf++;
+               if (ch < 0x100)
+                       char_type = spk_chartab[ch];
+               else
+                       char_type = ALPHA;
+               if (ch == old_ch && !(char_type & B_NUM)) {
+                       if (++rep_count > 2)
+                               continue;
+               } else {
+                       if ((last_type & CH_RPT) && rep_count > 2) {
+                               synth_printf(" ");
+                               synth_printf(spk_msg_get(MSG_REPEAT_DESC),
+                                            ++rep_count);
+                               synth_printf(" ");
+                       }
+                       rep_count = 0;
+               }
+               if (ch == spk_lastkey) {
+                       rep_count = 0;
+                       if (spk_key_echo == 1 && ch >= MINECHOCHAR)
+                               speak_char(ch);
+               } else if (char_type & B_ALPHA) {
+                       if ((synth_flags & SF_DEC) && (last_type & PUNC))
+                               synth_buffer_add(SPACE);
+                       synth_putwc_s(ch);
+               } else if (char_type & B_NUM) {
+                       rep_count = 0;
+                       synth_putwc_s(ch);
+               } else if (char_type & spk_punc_mask) {
+                       speak_char(ch);
+                       char_type &= ~PUNC;     /* for dec nospell processing */
+               } else if (char_type & SYNTH_OK) {
+                       /* these are usually puncts like . and , which synth
+                        * needs for expression.
+                        * suppress multiple to get rid of long pauses and
+                        * clear repeat count
+                        * so if someone has
+                        * repeats on you don't get nothing repeated count
+                        */
+                       if (ch != old_ch)
+                               synth_putwc_s(ch);
+                       else
+                               rep_count = 0;
+               } else {
+/* send space and record position, if next is num overwrite space */
+                       if (old_ch != ch)
+                               synth_buffer_add(SPACE);
+                       else
+                               rep_count = 0;
+               }
+               old_ch = ch;
+               last_type = char_type;
+       }
+       spk_lastkey = 0;
+       if (in_count > 2 && rep_count > 2) {
+               if (last_type & CH_RPT) {
+                       synth_printf(" ");
+                       synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
+                                    ++rep_count);
+                       synth_printf(" ");
+               }
+               rep_count = 0;
+       }
+}
+
+static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
+
+static void read_all_doc(struct vc_data *vc);
+static void cursor_done(struct timer_list *unused);
+static DEFINE_TIMER(cursor_timer, cursor_done);
+
+static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
+{
+       unsigned long flags;
+
+       if (!synth || up_flag || spk_killed)
+               return;
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       if (cursor_track == read_all_mode) {
+               switch (value) {
+               case KVAL(K_SHIFT):
+                       del_timer(&cursor_timer);
+                       spk_shut_up &= 0xfe;
+                       spk_do_flush();
+                       read_all_doc(vc);
+                       break;
+               case KVAL(K_CTRL):
+                       del_timer(&cursor_timer);
+                       cursor_track = prev_cursor_track;
+                       spk_shut_up &= 0xfe;
+                       spk_do_flush();
+                       break;
+               }
+       } else {
+               spk_shut_up &= 0xfe;
+               spk_do_flush();
+       }
+       if (spk_say_ctrl && value < NUM_CTL_LABELS)
+               synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+}
+
+static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       if (up_flag) {
+               spk_lastkey = 0;
+               spk_keydown = 0;
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return;
+       }
+       if (!synth || spk_killed) {
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return;
+       }
+       spk_shut_up &= 0xfe;
+       spk_lastkey = value;
+       spk_keydown++;
+       spk_parked &= 0xfe;
+       if (spk_key_echo == 2 && value >= MINECHOCHAR)
+               speak_char(value);
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+}
+
+int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
+{
+       int i = 0, states, key_data_len;
+       const u_char *cp = key_info;
+       u_char *cp1 = k_buffer;
+       u_char ch, version, num_keys;
+
+       version = *cp++;
+       if (version != KEY_MAP_VER) {
+               pr_debug("version found %d should be %d\n",
+                        version, KEY_MAP_VER);
+               return -EINVAL;
+       }
+       num_keys = *cp;
+       states = (int)cp[1];
+       key_data_len = (states + 1) * (num_keys + 1);
+       if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
+               pr_debug("too many key_infos (%d over %u)\n",
+                        key_data_len + SHIFT_TBL_SIZE + 4,
+                        (unsigned int)(sizeof(spk_key_buf)));
+               return -EINVAL;
+       }
+       memset(k_buffer, 0, SHIFT_TBL_SIZE);
+       memset(spk_our_keys, 0, sizeof(spk_our_keys));
+       spk_shift_table = k_buffer;
+       spk_our_keys[0] = spk_shift_table;
+       cp1 += SHIFT_TBL_SIZE;
+       memcpy(cp1, cp, key_data_len + 3);
+       /* get num_keys, states and data */
+       cp1 += 2;               /* now pointing at shift states */
+       for (i = 1; i <= states; i++) {
+               ch = *cp1++;
+               if (ch >= SHIFT_TBL_SIZE) {
+                       pr_debug("(%d) not valid shift state (max_allowed = %d)\n",
+                                ch, SHIFT_TBL_SIZE);
+                       return -EINVAL;
+               }
+               spk_shift_table[ch] = i;
+       }
+       keymap_flags = *cp1++;
+       while ((ch = *cp1)) {
+               if (ch >= MAX_KEY) {
+                       pr_debug("(%d), not valid key, (max_allowed = %d)\n",
+                                ch, MAX_KEY);
+                       return -EINVAL;
+               }
+               spk_our_keys[ch] = cp1;
+               cp1 += states + 1;
+       }
+       return 0;
+}
+
+static struct var_t spk_vars[] = {
+       /* bell must be first to set high limit */
+       {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
+       {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
+       {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
+       {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
+       {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
+       {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
+       {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
+       {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
+       {SAY_CONTROL, TOGGLE_0},
+       {SAY_WORD_CTL, TOGGLE_0},
+       {NO_INTERRUPT, TOGGLE_0},
+       {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
+       V_LAST_VAR
+};
+
+static void toggle_cursoring(struct vc_data *vc)
+{
+       if (cursor_track == read_all_mode)
+               cursor_track = prev_cursor_track;
+       if (++cursor_track >= CT_Max)
+               cursor_track = 0;
+       synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
+}
+
+void spk_reset_default_chars(void)
+{
+       int i;
+
+       /* First, free any non-default */
+       for (i = 0; i < 256; i++) {
+               if (spk_characters[i] &&
+                   (spk_characters[i] != spk_default_chars[i]))
+                       kfree(spk_characters[i]);
+       }
+
+       memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
+}
+
+void spk_reset_default_chartab(void)
+{
+       memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
+}
+
+static const struct st_bits_data *pb_edit;
+
+static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
+{
+       short mask = pb_edit->mask, ch_type = spk_chartab[ch];
+
+       if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
+               return -1;
+       if (ch == SPACE) {
+               synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
+               spk_special_handler = NULL;
+               return 1;
+       }
+       if (mask < PUNC && !(ch_type & PUNC))
+               return -1;
+       spk_chartab[ch] ^= mask;
+       speak_char(ch);
+       synth_printf(" %s\n",
+                    (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
+                    spk_msg_get(MSG_OFF));
+       return 1;
+}
+
+/* Allocation concurrency is protected by the console semaphore */
+static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
+{
+       int vc_num;
+
+       vc_num = vc->vc_num;
+       if (!speakup_console[vc_num]) {
+               speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
+                                                 gfp_flags);
+               if (!speakup_console[vc_num])
+                       return -ENOMEM;
+               speakup_date(vc);
+       } else if (!spk_parked) {
+               speakup_date(vc);
+       }
+
+       return 0;
+}
+
+static void speakup_deallocate(struct vc_data *vc)
+{
+       int vc_num;
+
+       vc_num = vc->vc_num;
+       kfree(speakup_console[vc_num]);
+       speakup_console[vc_num] = NULL;
+}
+
+static u_char is_cursor;
+static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
+static int cursor_con;
+
+static void reset_highlight_buffers(struct vc_data *);
+
+static int read_all_key;
+
+static int in_keyboard_notifier;
+
+static void start_read_all_timer(struct vc_data *vc, int command);
+
+enum {
+       RA_NOTHING,
+       RA_NEXT_SENT,
+       RA_PREV_LINE,
+       RA_NEXT_LINE,
+       RA_PREV_SENT,
+       RA_DOWN_ARROW,
+       RA_TIMER,
+       RA_FIND_NEXT_SENT,
+       RA_FIND_PREV_SENT,
+};
+
+static void kbd_fakekey2(struct vc_data *vc, int command)
+{
+       del_timer(&cursor_timer);
+       speakup_fake_down_arrow();
+       start_read_all_timer(vc, command);
+}
+
+static void read_all_doc(struct vc_data *vc)
+{
+       if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
+               return;
+       if (!synth_supports_indexing())
+               return;
+       if (cursor_track != read_all_mode)
+               prev_cursor_track = cursor_track;
+       cursor_track = read_all_mode;
+       spk_reset_index_count(0);
+       if (get_sentence_buf(vc, 0) == -1) {
+               del_timer(&cursor_timer);
+               if (!in_keyboard_notifier)
+                       speakup_fake_down_arrow();
+               start_read_all_timer(vc, RA_DOWN_ARROW);
+       } else {
+               say_sentence_num(0, 0);
+               synth_insert_next_index(0);
+               start_read_all_timer(vc, RA_TIMER);
+       }
+}
+
+static void stop_read_all(struct vc_data *vc)
+{
+       del_timer(&cursor_timer);
+       cursor_track = prev_cursor_track;
+       spk_shut_up &= 0xfe;
+       spk_do_flush();
+}
+
+static void start_read_all_timer(struct vc_data *vc, int command)
+{
+       struct var_t *cursor_timeout;
+
+       cursor_con = vc->vc_num;
+       read_all_key = command;
+       cursor_timeout = spk_get_var(CURSOR_TIME);
+       mod_timer(&cursor_timer,
+                 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
+}
+
+static void handle_cursor_read_all(struct vc_data *vc, int command)
+{
+       int indcount, sentcount, rv, sn;
+
+       switch (command) {
+       case RA_NEXT_SENT:
+               /* Get Current Sentence */
+               spk_get_index_count(&indcount, &sentcount);
+               /*printk("%d %d  ", indcount, sentcount); */
+               spk_reset_index_count(sentcount + 1);
+               if (indcount == 1) {
+                       if (!say_sentence_num(sentcount + 1, 0)) {
+                               kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
+                               return;
+                       }
+                       synth_insert_next_index(0);
+               } else {
+                       sn = 0;
+                       if (!say_sentence_num(sentcount + 1, 1)) {
+                               sn = 1;
+                               spk_reset_index_count(sn);
+                       } else {
+                               synth_insert_next_index(0);
+                       }
+                       if (!say_sentence_num(sn, 0)) {
+                               kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
+                               return;
+                       }
+                       synth_insert_next_index(0);
+               }
+               start_read_all_timer(vc, RA_TIMER);
+               break;
+       case RA_PREV_SENT:
+               break;
+       case RA_NEXT_LINE:
+               read_all_doc(vc);
+               break;
+       case RA_PREV_LINE:
+               break;
+       case RA_DOWN_ARROW:
+               if (get_sentence_buf(vc, 0) == -1) {
+                       kbd_fakekey2(vc, RA_DOWN_ARROW);
+               } else {
+                       say_sentence_num(0, 0);
+                       synth_insert_next_index(0);
+                       start_read_all_timer(vc, RA_TIMER);
+               }
+               break;
+       case RA_FIND_NEXT_SENT:
+               rv = get_sentence_buf(vc, 0);
+               if (rv == -1)
+                       read_all_doc(vc);
+               if (rv == 0) {
+                       kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
+               } else {
+                       say_sentence_num(1, 0);
+                       synth_insert_next_index(0);
+                       start_read_all_timer(vc, RA_TIMER);
+               }
+               break;
+       case RA_FIND_PREV_SENT:
+               break;
+       case RA_TIMER:
+               spk_get_index_count(&indcount, &sentcount);
+               if (indcount < 2)
+                       kbd_fakekey2(vc, RA_DOWN_ARROW);
+               else
+                       start_read_all_timer(vc, RA_TIMER);
+               break;
+       }
+}
+
+static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       if (cursor_track == read_all_mode) {
+               spk_parked &= 0xfe;
+               if (!synth || up_flag || spk_shut_up) {
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       return NOTIFY_STOP;
+               }
+               del_timer(&cursor_timer);
+               spk_shut_up &= 0xfe;
+               spk_do_flush();
+               start_read_all_timer(vc, value + 1);
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return NOTIFY_STOP;
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return NOTIFY_OK;
+}
+
+static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
+{
+       unsigned long flags;
+       struct var_t *cursor_timeout;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       spk_parked &= 0xfe;
+       if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return;
+       }
+       spk_shut_up &= 0xfe;
+       if (spk_no_intr)
+               spk_do_flush();
+/* the key press flushes if !no_inter but we want to flush on cursor
+ * moves regardless of no_inter state
+ */
+       is_cursor = value + 1;
+       old_cursor_pos = vc->vc_pos;
+       old_cursor_x = vc->vc_x;
+       old_cursor_y = vc->vc_y;
+       speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
+       cursor_con = vc->vc_num;
+       if (cursor_track == CT_Highlight)
+               reset_highlight_buffers(vc);
+       cursor_timeout = spk_get_var(CURSOR_TIME);
+       mod_timer(&cursor_timer,
+                 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+}
+
+static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
+{
+       int i, bi, hi;
+       int vc_num = vc->vc_num;
+
+       bi = (vc->vc_attr & 0x70) >> 4;
+       hi = speakup_console[vc_num]->ht.highsize[bi];
+
+       i = 0;
+       if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
+               speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
+               speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
+               speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
+       }
+       while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
+               if (ic[i] > 32) {
+                       speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
+                       hi++;
+               } else if ((ic[i] == 32) && (hi != 0)) {
+                       if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
+                           32) {
+                               speakup_console[vc_num]->ht.highbuf[bi][hi] =
+                                   ic[i];
+                               hi++;
+                       }
+               }
+               i++;
+       }
+       speakup_console[vc_num]->ht.highsize[bi] = hi;
+}
+
+static void reset_highlight_buffers(struct vc_data *vc)
+{
+       int i;
+       int vc_num = vc->vc_num;
+
+       for (i = 0; i < 8; i++)
+               speakup_console[vc_num]->ht.highsize[i] = 0;
+}
+
+static int count_highlight_color(struct vc_data *vc)
+{
+       int i, bg;
+       int cc;
+       int vc_num = vc->vc_num;
+       u16 ch;
+       u16 *start = (u16 *)vc->vc_origin;
+
+       for (i = 0; i < 8; i++)
+               speakup_console[vc_num]->ht.bgcount[i] = 0;
+
+       for (i = 0; i < vc->vc_rows; i++) {
+               u16 *end = start + vc->vc_cols * 2;
+               u16 *ptr;
+
+               for (ptr = start; ptr < end; ptr++) {
+                       ch = get_attributes(vc, ptr);
+                       bg = (ch & 0x70) >> 4;
+                       speakup_console[vc_num]->ht.bgcount[bg]++;
+               }
+               start += vc->vc_size_row;
+       }
+
+       cc = 0;
+       for (i = 0; i < 8; i++)
+               if (speakup_console[vc_num]->ht.bgcount[i] > 0)
+                       cc++;
+       return cc;
+}
+
+static int get_highlight_color(struct vc_data *vc)
+{
+       int i, j;
+       unsigned int cptr[8];
+       int vc_num = vc->vc_num;
+
+       for (i = 0; i < 8; i++)
+               cptr[i] = i;
+
+       for (i = 0; i < 7; i++)
+               for (j = i + 1; j < 8; j++)
+                       if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
+                           speakup_console[vc_num]->ht.bgcount[cptr[j]])
+                               swap(cptr[i], cptr[j]);
+
+       for (i = 0; i < 8; i++)
+               if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
+                       if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
+                               return cptr[i];
+       return -1;
+}
+
+static int speak_highlight(struct vc_data *vc)
+{
+       int hc, d;
+       int vc_num = vc->vc_num;
+
+       if (count_highlight_color(vc) == 1)
+               return 0;
+       hc = get_highlight_color(vc);
+       if (hc != -1) {
+               d = vc->vc_y - speakup_console[vc_num]->ht.cy;
+               if ((d == 1) || (d == -1))
+                       if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
+                               return 0;
+               spk_parked |= 0x01;
+               spk_do_flush();
+               spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
+                           speakup_console[vc_num]->ht.highsize[hc]);
+               spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
+               spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
+               spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
+               return 1;
+       }
+       return 0;
+}
+
+static void cursor_done(struct timer_list *unused)
+{
+       struct vc_data *vc = vc_cons[cursor_con].d;
+       unsigned long flags;
+
+       del_timer(&cursor_timer);
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       if (cursor_con != fg_console) {
+               is_cursor = 0;
+               goto out;
+       }
+       speakup_date(vc);
+       if (win_enabled) {
+               if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
+                   vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
+                       spk_keydown = 0;
+                       is_cursor = 0;
+                       goto out;
+               }
+       }
+       if (cursor_track == read_all_mode) {
+               handle_cursor_read_all(vc, read_all_key);
+               goto out;
+       }
+       if (cursor_track == CT_Highlight) {
+               if (speak_highlight(vc)) {
+                       spk_keydown = 0;
+                       is_cursor = 0;
+                       goto out;
+               }
+       }
+       if (cursor_track == CT_Window)
+               speakup_win_say(vc);
+       else if (is_cursor == 1 || is_cursor == 4)
+               say_line_from_to(vc, 0, vc->vc_cols, 0);
+       else
+               say_char(vc);
+       spk_keydown = 0;
+       is_cursor = 0;
+out:
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+}
+
+/* called by: vt_notifier_call() */
+static void speakup_bs(struct vc_data *vc)
+{
+       unsigned long flags;
+
+       if (!speakup_console[vc->vc_num])
+               return;
+       if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
+               /* Speakup output, discard */
+               return;
+       if (!spk_parked)
+               speakup_date(vc);
+       if (spk_shut_up || !synth) {
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return;
+       }
+       if (vc->vc_num == fg_console && spk_keydown) {
+               spk_keydown = 0;
+               if (!is_cursor)
+                       say_char(vc);
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+}
+
+/* called by: vt_notifier_call() */
+static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
+{
+       unsigned long flags;
+
+       if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
+               return;
+       if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
+               /* Speakup output, discard */
+               return;
+       if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
+               bleep(3);
+       if ((is_cursor) || (cursor_track == read_all_mode)) {
+               if (cursor_track == CT_Highlight)
+                       update_color_buffer(vc, str, len);
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return;
+       }
+       if (win_enabled) {
+               if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
+                   vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       return;
+               }
+       }
+
+       spkup_write(str, len);
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+}
+
+static void speakup_con_update(struct vc_data *vc)
+{
+       unsigned long flags;
+
+       if (!speakup_console[vc->vc_num] || spk_parked)
+               return;
+       if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
+               /* Speakup output, discard */
+               return;
+       speakup_date(vc);
+       if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
+               synth_printf("%s", spk_str_pause);
+               spk_paused = true;
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+}
+
+static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
+{
+       unsigned long flags;
+       int on_off = 2;
+       char *label;
+
+       if (!synth || up_flag || spk_killed)
+               return;
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       spk_shut_up &= 0xfe;
+       if (spk_no_intr)
+               spk_do_flush();
+       switch (value) {
+       case KVAL(K_CAPS):
+               label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
+               on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
+               break;
+       case KVAL(K_NUM):
+               label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
+               on_off = vt_get_leds(fg_console, VC_NUMLOCK);
+               break;
+       case KVAL(K_HOLD):
+               label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
+               on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
+               if (speakup_console[vc->vc_num])
+                       speakup_console[vc->vc_num]->tty_stopped = on_off;
+               break;
+       default:
+               spk_parked &= 0xfe;
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return;
+       }
+       if (on_off < 2)
+               synth_printf("%s %s\n",
+                            label, spk_msg_get(MSG_STATUS_START + on_off));
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+}
+
+static int inc_dec_var(u_char value)
+{
+       struct st_var_header *p_header;
+       struct var_t *var_data;
+       char num_buf[32];
+       char *cp = num_buf;
+       char *pn;
+       int var_id = (int)value - VAR_START;
+       int how = (var_id & 1) ? E_INC : E_DEC;
+
+       var_id = var_id / 2 + FIRST_SET_VAR;
+       p_header = spk_get_var_header(var_id);
+       if (!p_header)
+               return -1;
+       if (p_header->var_type != VAR_NUM)
+               return -1;
+       var_data = p_header->data;
+       if (spk_set_num_var(1, p_header, how) != 0)
+               return -1;
+       if (!spk_close_press) {
+               for (pn = p_header->name; *pn; pn++) {
+                       if (*pn == '_')
+                               *cp = SPACE;
+                       else
+                               *cp++ = *pn;
+               }
+       }
+       snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
+                var_data->u.n.value);
+       synth_printf("%s", num_buf);
+       return 0;
+}
+
+static void speakup_win_set(struct vc_data *vc)
+{
+       char info[40];
+
+       if (win_start > 1) {
+               synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
+               return;
+       }
+       if (spk_x < win_left || spk_y < win_top) {
+               synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
+               return;
+       }
+       if (win_start && spk_x == win_left && spk_y == win_top) {
+               win_left = 0;
+               win_right = vc->vc_cols - 1;
+               win_bottom = spk_y;
+               snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
+                        (int)win_top + 1);
+       } else {
+               if (!win_start) {
+                       win_top = spk_y;
+                       win_left = spk_x;
+               } else {
+                       win_bottom = spk_y;
+                       win_right = spk_x;
+               }
+               snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
+                        (win_start) ?
+                               spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
+                        (int)spk_y + 1, (int)spk_x + 1);
+       }
+       synth_printf("%s\n", info);
+       win_start++;
+}
+
+static void speakup_win_clear(struct vc_data *vc)
+{
+       win_top = 0;
+       win_bottom = 0;
+       win_left = 0;
+       win_right = 0;
+       win_start = 0;
+       synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
+}
+
+static void speakup_win_enable(struct vc_data *vc)
+{
+       if (win_start < 2) {
+               synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
+               return;
+       }
+       win_enabled ^= 1;
+       if (win_enabled)
+               synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
+       else
+               synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
+}
+
+static void speakup_bits(struct vc_data *vc)
+{
+       int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
+
+       if (spk_special_handler || val < 1 || val > 6) {
+               synth_printf("%s\n", spk_msg_get(MSG_ERROR));
+               return;
+       }
+       pb_edit = &spk_punc_info[val];
+       synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
+       spk_special_handler = edit_bits;
+}
+
+static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
+{
+       static u_char goto_buf[8];
+       static int num;
+       int maxlen;
+       char *cp;
+       u16 wch;
+
+       if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
+               goto do_goto;
+       if (type == KT_LATIN && ch == '\n')
+               goto do_goto;
+       if (type != 0)
+               goto oops;
+       if (ch == 8) {
+               u16 wch;
+
+               if (num == 0)
+                       return -1;
+               wch = goto_buf[--num];
+               goto_buf[num] = '\0';
+               spkup_write(&wch, 1);
+               return 1;
+       }
+       if (ch < '+' || ch > 'y')
+               goto oops;
+       wch = ch;
+       goto_buf[num++] = ch;
+       goto_buf[num] = '\0';
+       spkup_write(&wch, 1);
+       maxlen = (*goto_buf >= '0') ? 3 : 4;
+       if ((ch == '+' || ch == '-') && num == 1)
+               return 1;
+       if (ch >= '0' && ch <= '9' && num < maxlen)
+               return 1;
+       if (num < maxlen - 1 || num > maxlen)
+               goto oops;
+       if (ch < 'x' || ch > 'y') {
+oops:
+               if (!spk_killed)
+                       synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
+               goto_buf[num = 0] = '\0';
+               spk_special_handler = NULL;
+               return 1;
+       }
+
+       /* Do not replace with kstrtoul: here we need cp to be updated */
+       goto_pos = simple_strtoul(goto_buf, &cp, 10);
+
+       if (*cp == 'x') {
+               if (*goto_buf < '0')
+                       goto_pos += spk_x;
+               else if (goto_pos > 0)
+                       goto_pos--;
+
+               if (goto_pos >= vc->vc_cols)
+                       goto_pos = vc->vc_cols - 1;
+               goto_x = 1;
+       } else {
+               if (*goto_buf < '0')
+                       goto_pos += spk_y;
+               else if (goto_pos > 0)
+                       goto_pos--;
+
+               if (goto_pos >= vc->vc_rows)
+                       goto_pos = vc->vc_rows - 1;
+               goto_x = 0;
+       }
+       goto_buf[num = 0] = '\0';
+do_goto:
+       spk_special_handler = NULL;
+       spk_parked |= 0x01;
+       if (goto_x) {
+               spk_pos -= spk_x * 2;
+               spk_x = goto_pos;
+               spk_pos += goto_pos * 2;
+               say_word(vc);
+       } else {
+               spk_y = goto_pos;
+               spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
+               say_line(vc);
+       }
+       return 1;
+}
+
+static void speakup_goto(struct vc_data *vc)
+{
+       if (spk_special_handler) {
+               synth_printf("%s\n", spk_msg_get(MSG_ERROR));
+               return;
+       }
+       synth_printf("%s\n", spk_msg_get(MSG_GOTO));
+       spk_special_handler = handle_goto;
+}
+
+static void speakup_help(struct vc_data *vc)
+{
+       spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
+}
+
+static void do_nothing(struct vc_data *vc)
+{
+       return;                 /* flush done in do_spkup */
+}
+
+static u_char key_speakup, spk_key_locked;
+
+static void speakup_lock(struct vc_data *vc)
+{
+       if (!spk_key_locked) {
+               spk_key_locked = 16;
+               key_speakup = 16;
+       } else {
+               spk_key_locked = 0;
+               key_speakup = 0;
+       }
+}
+
+typedef void (*spkup_hand) (struct vc_data *);
+static spkup_hand spkup_handler[] = {
+       /* must be ordered same as defines in speakup.h */
+       do_nothing, speakup_goto, speech_kill, speakup_shut_up,
+       speakup_cut, speakup_paste, say_first_char, say_last_char,
+       say_char, say_prev_char, say_next_char,
+       say_word, say_prev_word, say_next_word,
+       say_line, say_prev_line, say_next_line,
+       top_edge, bottom_edge, left_edge, right_edge,
+       spell_word, spell_word, say_screen,
+       say_position, say_attributes,
+       speakup_off, speakup_parked, say_line,  /* this is for indent */
+       say_from_top, say_to_bottom,
+       say_from_left, say_to_right,
+       say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
+       speakup_bits, speakup_bits, speakup_bits,
+       speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
+       speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
+};
+
+static void do_spkup(struct vc_data *vc, u_char value)
+{
+       if (spk_killed && value != SPEECH_KILL)
+               return;
+       spk_keydown = 0;
+       spk_lastkey = 0;
+       spk_shut_up &= 0xfe;
+       this_speakup_key = value;
+       if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
+               spk_do_flush();
+               (*spkup_handler[value]) (vc);
+       } else {
+               if (inc_dec_var(value) < 0)
+                       bleep(9);
+       }
+}
+
+static const char *pad_chars = "0123456789+-*/\015,.?()";
+
+static int
+speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
+           int up_flag)
+{
+       unsigned long flags;
+       int kh;
+       u_char *key_info;
+       u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
+       u_char shift_info, offset;
+       int ret = 0;
+
+       if (!synth)
+               return 0;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       tty = vc->port.tty;
+       if (type >= 0xf0)
+               type -= 0xf0;
+       if (type == KT_PAD &&
+           (vt_get_leds(fg_console, VC_NUMLOCK))) {
+               if (up_flag) {
+                       spk_keydown = 0;
+                       goto out;
+               }
+               value = pad_chars[value];
+               spk_lastkey = value;
+               spk_keydown++;
+               spk_parked &= 0xfe;
+               goto no_map;
+       }
+       if (keycode >= MAX_KEY)
+               goto no_map;
+       key_info = spk_our_keys[keycode];
+       if (!key_info)
+               goto no_map;
+       /* Check valid read all mode keys */
+       if ((cursor_track == read_all_mode) && (!up_flag)) {
+               switch (value) {
+               case KVAL(K_DOWN):
+               case KVAL(K_UP):
+               case KVAL(K_LEFT):
+               case KVAL(K_RIGHT):
+               case KVAL(K_PGUP):
+               case KVAL(K_PGDN):
+                       break;
+               default:
+                       stop_read_all(vc);
+                       break;
+               }
+       }
+       shift_info = (shift_state & 0x0f) + key_speakup;
+       offset = spk_shift_table[shift_info];
+       if (offset) {
+               new_key = key_info[offset];
+               if (new_key) {
+                       ret = 1;
+                       if (new_key == SPK_KEY) {
+                               if (!spk_key_locked)
+                                       key_speakup = (up_flag) ? 0 : 16;
+                               if (up_flag || spk_killed)
+                                       goto out;
+                               spk_shut_up &= 0xfe;
+                               spk_do_flush();
+                               goto out;
+                       }
+                       if (up_flag)
+                               goto out;
+                       if (last_keycode == keycode &&
+                           time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
+                               spk_close_press = 1;
+                               offset = spk_shift_table[shift_info + 32];
+                               /* double press? */
+                               if (offset && key_info[offset])
+                                       new_key = key_info[offset];
+                       }
+                       last_keycode = keycode;
+                       last_spk_jiffy = jiffies;
+                       type = KT_SPKUP;
+                       value = new_key;
+               }
+       }
+no_map:
+       if (type == KT_SPKUP && !spk_special_handler) {
+               do_spkup(vc, new_key);
+               spk_close_press = 0;
+               ret = 1;
+               goto out;
+       }
+       if (up_flag || spk_killed || type == KT_SHIFT)
+               goto out;
+       spk_shut_up &= 0xfe;
+       kh = (value == KVAL(K_DOWN)) ||
+           (value == KVAL(K_UP)) ||
+           (value == KVAL(K_LEFT)) ||
+           (value == KVAL(K_RIGHT));
+       if ((cursor_track != read_all_mode) || !kh)
+               if (!spk_no_intr)
+                       spk_do_flush();
+       if (spk_special_handler) {
+               if (type == KT_SPEC && value == 1) {
+                       value = '\n';
+                       type = KT_LATIN;
+               } else if (type == KT_LETTER) {
+                       type = KT_LATIN;
+               } else if (value == 0x7f) {
+                       value = 8;      /* make del = backspace */
+               }
+               ret = (*spk_special_handler) (vc, type, value, keycode);
+               spk_close_press = 0;
+               if (ret < 0)
+                       bleep(9);
+               goto out;
+       }
+       last_keycode = 0;
+out:
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return ret;
+}
+
+static int keyboard_notifier_call(struct notifier_block *nb,
+                                 unsigned long code, void *_param)
+{
+       struct keyboard_notifier_param *param = _param;
+       struct vc_data *vc = param->vc;
+       int up = !param->down;
+       int ret = NOTIFY_OK;
+       static int keycode;     /* to hold the current keycode */
+
+       in_keyboard_notifier = 1;
+
+       if (vc->vc_mode == KD_GRAPHICS)
+               goto out;
+
+       /*
+        * First, determine whether we are handling a fake keypress on
+        * the current processor.  If we are, then return NOTIFY_OK,
+        * to pass the keystroke up the chain.  This prevents us from
+        * trying to take the Speakup lock while it is held by the
+        * processor on which the simulated keystroke was generated.
+        * Also, the simulated keystrokes should be ignored by Speakup.
+        */
+
+       if (speakup_fake_key_pressed())
+               goto out;
+
+       switch (code) {
+       case KBD_KEYCODE:
+               /* speakup requires keycode and keysym currently */
+               keycode = param->value;
+               break;
+       case KBD_UNBOUND_KEYCODE:
+               /* not used yet */
+               break;
+       case KBD_UNICODE:
+               /* not used yet */
+               break;
+       case KBD_KEYSYM:
+               if (speakup_key(vc, param->shift, keycode, param->value, up))
+                       ret = NOTIFY_STOP;
+               else if (KTYP(param->value) == KT_CUR)
+                       ret = pre_handle_cursor(vc, KVAL(param->value), up);
+               break;
+       case KBD_POST_KEYSYM:{
+                       unsigned char type = KTYP(param->value) - 0xf0;
+                       unsigned char val = KVAL(param->value);
+
+                       switch (type) {
+                       case KT_SHIFT:
+                               do_handle_shift(vc, val, up);
+                               break;
+                       case KT_LATIN:
+                       case KT_LETTER:
+                               do_handle_latin(vc, val, up);
+                               break;
+                       case KT_CUR:
+                               do_handle_cursor(vc, val, up);
+                               break;
+                       case KT_SPEC:
+                               do_handle_spec(vc, val, up);
+                               break;
+                       }
+                       break;
+               }
+       }
+out:
+       in_keyboard_notifier = 0;
+       return ret;
+}
+
+static int vt_notifier_call(struct notifier_block *nb,
+                           unsigned long code, void *_param)
+{
+       struct vt_notifier_param *param = _param;
+       struct vc_data *vc = param->vc;
+
+       switch (code) {
+       case VT_ALLOCATE:
+               if (vc->vc_mode == KD_TEXT)
+                       speakup_allocate(vc, GFP_ATOMIC);
+               break;
+       case VT_DEALLOCATE:
+               speakup_deallocate(vc);
+               break;
+       case VT_WRITE:
+               if (param->c == '\b') {
+                       speakup_bs(vc);
+               } else {
+                       u16 d = param->c;
+
+                       speakup_con_write(vc, &d, 1);
+               }
+               break;
+       case VT_UPDATE:
+               speakup_con_update(vc);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+/* called by: module_exit() */
+static void __exit speakup_exit(void)
+{
+       int i;
+
+       unregister_keyboard_notifier(&keyboard_notifier_block);
+       unregister_vt_notifier(&vt_notifier_block);
+       speakup_unregister_devsynth();
+       speakup_cancel_selection();
+       speakup_cancel_paste();
+       del_timer_sync(&cursor_timer);
+       kthread_stop(speakup_task);
+       speakup_task = NULL;
+       mutex_lock(&spk_mutex);
+       synth_release();
+       mutex_unlock(&spk_mutex);
+       spk_ttyio_unregister_ldisc();
+
+       speakup_kobj_exit();
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               kfree(speakup_console[i]);
+
+       speakup_remove_virtual_keyboard();
+
+       for (i = 0; i < MAXVARS; i++)
+               speakup_unregister_var(i);
+
+       for (i = 0; i < 256; i++) {
+               if (spk_characters[i] != spk_default_chars[i])
+                       kfree(spk_characters[i]);
+       }
+
+       spk_free_user_msgs();
+}
+
+/* call by: module_init() */
+static int __init speakup_init(void)
+{
+       int i;
+       long err = 0;
+       struct vc_data *vc = vc_cons[fg_console].d;
+       struct var_t *var;
+
+       /* These first few initializations cannot fail. */
+       spk_initialize_msgs();  /* Initialize arrays for i18n. */
+       spk_reset_default_chars();
+       spk_reset_default_chartab();
+       spk_strlwr(synth_name);
+       spk_vars[0].u.n.high = vc->vc_cols;
+       for (var = spk_vars; var->var_id != MAXVARS; var++)
+               speakup_register_var(var);
+       for (var = synth_time_vars;
+            (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
+               speakup_register_var(var);
+       for (i = 1; spk_punc_info[i].mask != 0; i++)
+               spk_set_mask_bits(NULL, i, 2);
+
+       spk_set_key_info(spk_key_defaults, spk_key_buf);
+
+       /* From here on out, initializations can fail. */
+       err = speakup_add_virtual_keyboard();
+       if (err)
+               goto error_virtkeyboard;
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               if (vc_cons[i].d) {
+                       err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
+                       if (err)
+                               goto error_kobjects;
+               }
+
+       if (spk_quiet_boot)
+               spk_shut_up |= 0x01;
+
+       err = speakup_kobj_init();
+       if (err)
+               goto error_kobjects;
+
+       spk_ttyio_register_ldisc();
+       synth_init(synth_name);
+       speakup_register_devsynth();
+       /*
+        * register_devsynth might fail, but this error is not fatal.
+        * /dev/synth is an extra feature; the rest of Speakup
+        * will work fine without it.
+        */
+
+       err = register_keyboard_notifier(&keyboard_notifier_block);
+       if (err)
+               goto error_kbdnotifier;
+       err = register_vt_notifier(&vt_notifier_block);
+       if (err)
+               goto error_vtnotifier;
+
+       speakup_task = kthread_create(speakup_thread, NULL, "speakup");
+
+       if (IS_ERR(speakup_task)) {
+               err = PTR_ERR(speakup_task);
+               goto error_task;
+       }
+
+       set_user_nice(speakup_task, 10);
+       wake_up_process(speakup_task);
+
+       pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
+       pr_info("synth name on entry is: %s\n", synth_name);
+       goto out;
+
+error_task:
+       unregister_vt_notifier(&vt_notifier_block);
+
+error_vtnotifier:
+       unregister_keyboard_notifier(&keyboard_notifier_block);
+       del_timer(&cursor_timer);
+
+error_kbdnotifier:
+       speakup_unregister_devsynth();
+       mutex_lock(&spk_mutex);
+       synth_release();
+       mutex_unlock(&spk_mutex);
+       speakup_kobj_exit();
+
+error_kobjects:
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               kfree(speakup_console[i]);
+
+       speakup_remove_virtual_keyboard();
+
+error_virtkeyboard:
+       for (i = 0; i < MAXVARS; i++)
+               speakup_unregister_var(i);
+
+       for (i = 0; i < 256; i++) {
+               if (spk_characters[i] != spk_default_chars[i])
+                       kfree(spk_characters[i]);
+       }
+
+       spk_free_user_msgs();
+
+out:
+       return err;
+}
+
+module_init(speakup_init);
+module_exit(speakup_exit);
diff --git a/drivers/accessibility/speakup/selection.c b/drivers/accessibility/speakup/selection.c
new file mode 100644 (file)
index 0000000..032f326
--- /dev/null
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/slab.h> /* for kmalloc */
+#include <linux/consolemap.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/device.h> /* for dev_warn */
+#include <linux/selection.h>
+#include <linux/workqueue.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/atomic.h>
+#include <linux/console.h>
+
+#include "speakup.h"
+
+unsigned short spk_xs, spk_ys, spk_xe, spk_ye; /* our region points */
+struct vc_data *spk_sel_cons;
+
+struct speakup_selection_work {
+       struct work_struct work;
+       struct tiocl_selection sel;
+       struct tty_struct *tty;
+};
+
+void speakup_clear_selection(void)
+{
+       console_lock();
+       clear_selection();
+       console_unlock();
+}
+
+static void __speakup_set_selection(struct work_struct *work)
+{
+       struct speakup_selection_work *ssw =
+               container_of(work, struct speakup_selection_work, work);
+
+       struct tty_struct *tty;
+       struct tiocl_selection sel;
+
+       sel = ssw->sel;
+
+       /* this ensures we copy sel before releasing the lock below */
+       rmb();
+
+       /* release the lock by setting tty of the struct to NULL */
+       tty = xchg(&ssw->tty, NULL);
+
+       if (spk_sel_cons != vc_cons[fg_console].d) {
+               spk_sel_cons = vc_cons[fg_console].d;
+               pr_warn("Selection: mark console not the same as cut\n");
+               goto unref;
+       }
+
+       set_selection_kernel(&sel, tty);
+
+unref:
+       tty_kref_put(tty);
+}
+
+static struct speakup_selection_work speakup_sel_work = {
+       .work = __WORK_INITIALIZER(speakup_sel_work.work,
+                                  __speakup_set_selection)
+};
+
+int speakup_set_selection(struct tty_struct *tty)
+{
+       /* we get kref here first in order to avoid a subtle race when
+        * cancelling selection work. getting kref first establishes the
+        * invariant that if speakup_sel_work.tty is not NULL when
+        * speakup_cancel_selection() is called, it must be the case that a put
+        * kref is pending.
+        */
+       tty_kref_get(tty);
+       if (cmpxchg(&speakup_sel_work.tty, NULL, tty)) {
+               tty_kref_put(tty);
+               return -EBUSY;
+       }
+       /* now we have the 'lock' by setting tty member of
+        * speakup_selection_work. wmb() ensures that writes to
+        * speakup_sel_work don't happen before cmpxchg() above.
+        */
+       wmb();
+
+       speakup_sel_work.sel.xs = spk_xs + 1;
+       speakup_sel_work.sel.ys = spk_ys + 1;
+       speakup_sel_work.sel.xe = spk_xe + 1;
+       speakup_sel_work.sel.ye = spk_ye + 1;
+       speakup_sel_work.sel.sel_mode = TIOCL_SELCHAR;
+
+       schedule_work_on(WORK_CPU_UNBOUND, &speakup_sel_work.work);
+
+       return 0;
+}
+
+void speakup_cancel_selection(void)
+{
+       struct tty_struct *tty;
+
+       cancel_work_sync(&speakup_sel_work.work);
+       /* setting to null so that if work fails to run and we cancel it,
+        * we can run it again without getting EBUSY forever from there on.
+        * we need to use xchg here to avoid race with speakup_set_selection()
+        */
+       tty = xchg(&speakup_sel_work.tty, NULL);
+       if (tty)
+               tty_kref_put(tty);
+}
+
+static void __speakup_paste_selection(struct work_struct *work)
+{
+       struct speakup_selection_work *ssw =
+               container_of(work, struct speakup_selection_work, work);
+       struct tty_struct *tty = xchg(&ssw->tty, NULL);
+
+       paste_selection(tty);
+       tty_kref_put(tty);
+}
+
+static struct speakup_selection_work speakup_paste_work = {
+       .work = __WORK_INITIALIZER(speakup_paste_work.work,
+                                  __speakup_paste_selection)
+};
+
+int speakup_paste_selection(struct tty_struct *tty)
+{
+       tty_kref_get(tty);
+       if (cmpxchg(&speakup_paste_work.tty, NULL, tty)) {
+               tty_kref_put(tty);
+               return -EBUSY;
+       }
+
+       schedule_work_on(WORK_CPU_UNBOUND, &speakup_paste_work.work);
+       return 0;
+}
+
+void speakup_cancel_paste(void)
+{
+       struct tty_struct *tty;
+
+       cancel_work_sync(&speakup_paste_work.work);
+       tty = xchg(&speakup_paste_work.tty, NULL);
+       if (tty)
+               tty_kref_put(tty);
+}
diff --git a/drivers/accessibility/speakup/serialio.c b/drivers/accessibility/speakup/serialio.c
new file mode 100644 (file)
index 0000000..177a298
--- /dev/null
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include "spk_types.h"
+#include "speakup.h"
+#include "spk_priv.h"
+#include "serialio.h"
+
+#include <linux/serial_core.h>
+/* WARNING:  Do not change this to <linux/serial.h> without testing that
+ * SERIAL_PORT_DFNS does get defined to the appropriate value.
+ */
+#include <asm/serial.h>
+
+#ifndef SERIAL_PORT_DFNS
+#define SERIAL_PORT_DFNS
+#endif
+
+static void start_serial_interrupt(int irq);
+
+static const struct old_serial_port rs_table[] = {
+       SERIAL_PORT_DFNS
+};
+
+static const struct old_serial_port *serstate;
+static int timeouts;
+
+static int spk_serial_out(struct spk_synth *in_synth, const char ch);
+static void spk_serial_send_xchar(char ch);
+static void spk_serial_tiocmset(unsigned int set, unsigned int clear);
+static unsigned char spk_serial_in(void);
+static unsigned char spk_serial_in_nowait(void);
+static void spk_serial_flush_buffer(void);
+
+struct spk_io_ops spk_serial_io_ops = {
+       .synth_out = spk_serial_out,
+       .send_xchar = spk_serial_send_xchar,
+       .tiocmset = spk_serial_tiocmset,
+       .synth_in = spk_serial_in,
+       .synth_in_nowait = spk_serial_in_nowait,
+       .flush_buffer = spk_serial_flush_buffer,
+};
+EXPORT_SYMBOL_GPL(spk_serial_io_ops);
+
+const struct old_serial_port *spk_serial_init(int index)
+{
+       int baud = 9600, quot = 0;
+       unsigned int cval = 0;
+       int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
+       const struct old_serial_port *ser;
+       int err;
+
+       if (index >= ARRAY_SIZE(rs_table)) {
+               pr_info("no port info for ttyS%d\n", index);
+               return NULL;
+       }
+       ser = rs_table + index;
+
+       /*      Divisor, bytesize and parity */
+       quot = ser->baud_base / baud;
+       cval = cflag & (CSIZE | CSTOPB);
+#if defined(__powerpc__) || defined(__alpha__)
+       cval >>= 8;
+#else /* !__powerpc__ && !__alpha__ */
+       cval >>= 4;
+#endif /* !__powerpc__ && !__alpha__ */
+       if (cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+       if (synth_request_region(ser->port, 8)) {
+               /* try to take it back. */
+               pr_info("Ports not available, trying to steal them\n");
+               __release_region(&ioport_resource, ser->port, 8);
+               err = synth_request_region(ser->port, 8);
+               if (err) {
+                       pr_warn("Unable to allocate port at %x, errno %i",
+                               ser->port, err);
+                       return NULL;
+               }
+       }
+
+       /*      Disable UART interrupts, set DTR and RTS high
+        *      and set speed.
+        */
+       outb(cval | UART_LCR_DLAB, ser->port + UART_LCR);       /* set DLAB */
+       outb(quot & 0xff, ser->port + UART_DLL);        /* LS of divisor */
+       outb(quot >> 8, ser->port + UART_DLM);          /* MS of divisor */
+       outb(cval, ser->port + UART_LCR);               /* reset DLAB */
+
+       /* Turn off Interrupts */
+       outb(0, ser->port + UART_IER);
+       outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
+
+       /* If we read 0xff from the LSR, there is no UART here. */
+       if (inb(ser->port + UART_LSR) == 0xff) {
+               synth_release_region(ser->port, 8);
+               serstate = NULL;
+               return NULL;
+       }
+
+       mdelay(1);
+       speakup_info.port_tts = ser->port;
+       serstate = ser;
+
+       start_serial_interrupt(ser->irq);
+
+       return ser;
+}
+
+static irqreturn_t synth_readbuf_handler(int irq, void *dev_id)
+{
+       unsigned long flags;
+       int c;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       while (inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR) {
+               c = inb_p(speakup_info.port_tts + UART_RX);
+               synth->read_buff_add((u_char)c);
+       }
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return IRQ_HANDLED;
+}
+
+static void start_serial_interrupt(int irq)
+{
+       int rv;
+
+       if (!synth->read_buff_add)
+               return;
+
+       rv = request_irq(irq, synth_readbuf_handler, IRQF_SHARED,
+                        "serial", (void *)synth_readbuf_handler);
+
+       if (rv)
+               pr_err("Unable to request Speakup serial I R Q\n");
+       /* Set MCR */
+       outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2,
+            speakup_info.port_tts + UART_MCR);
+       /* Turn on Interrupts */
+       outb(UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI,
+            speakup_info.port_tts + UART_IER);
+       inb(speakup_info.port_tts + UART_LSR);
+       inb(speakup_info.port_tts + UART_RX);
+       inb(speakup_info.port_tts + UART_IIR);
+       inb(speakup_info.port_tts + UART_MSR);
+       outb(1, speakup_info.port_tts + UART_FCR);      /* Turn FIFO On */
+}
+
+static void spk_serial_send_xchar(char ch)
+{
+       int timeout = SPK_XMITR_TIMEOUT;
+
+       while (spk_serial_tx_busy()) {
+               if (!--timeout)
+                       break;
+               udelay(1);
+       }
+       outb(ch, speakup_info.port_tts);
+}
+
+static void spk_serial_tiocmset(unsigned int set, unsigned int clear)
+{
+       int old = inb(speakup_info.port_tts + UART_MCR);
+
+       outb((old & ~clear) | set, speakup_info.port_tts + UART_MCR);
+}
+
+int spk_serial_synth_probe(struct spk_synth *synth)
+{
+       const struct old_serial_port *ser;
+       int failed = 0;
+
+       if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) {
+               ser = spk_serial_init(synth->ser);
+               if (!ser) {
+                       failed = -1;
+               } else {
+                       outb_p(0, ser->port);
+                       mdelay(1);
+                       outb_p('\r', ser->port);
+               }
+       } else {
+               failed = -1;
+               pr_warn("ttyS%i is an invalid port\n", synth->ser);
+       }
+       if (failed) {
+               pr_info("%s: not found\n", synth->long_name);
+               return -ENODEV;
+       }
+       pr_info("%s: ttyS%i, Driver Version %s\n",
+               synth->long_name, synth->ser, synth->version);
+       synth->alive = 1;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(spk_serial_synth_probe);
+
+void spk_stop_serial_interrupt(void)
+{
+       if (speakup_info.port_tts == 0)
+               return;
+
+       if (!synth->read_buff_add)
+               return;
+
+       /* Turn off interrupts */
+       outb(0, speakup_info.port_tts + UART_IER);
+       /* Free IRQ */
+       free_irq(serstate->irq, (void *)synth_readbuf_handler);
+}
+EXPORT_SYMBOL_GPL(spk_stop_serial_interrupt);
+
+int spk_wait_for_xmitr(struct spk_synth *in_synth)
+{
+       int tmout = SPK_XMITR_TIMEOUT;
+
+       if ((in_synth->alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) {
+               pr_warn("%s: too many timeouts, deactivating speakup\n",
+                       in_synth->long_name);
+               in_synth->alive = 0;
+               /* No synth any more, so nobody will restart TTYs, and we thus
+                * need to do it ourselves.  Now that there is no synth we can
+                * let application flood anyway
+                */
+               speakup_start_ttys();
+               timeouts = 0;
+               return 0;
+       }
+       while (spk_serial_tx_busy()) {
+               if (--tmout == 0) {
+                       pr_warn("%s: timed out (tx busy)\n",
+                               in_synth->long_name);
+                       timeouts++;
+                       return 0;
+               }
+               udelay(1);
+       }
+       tmout = SPK_CTS_TIMEOUT;
+       while (!((inb_p(speakup_info.port_tts + UART_MSR)) & UART_MSR_CTS)) {
+               /* CTS */
+               if (--tmout == 0) {
+                       timeouts++;
+                       return 0;
+               }
+               udelay(1);
+       }
+       timeouts = 0;
+       return 1;
+}
+
+static unsigned char spk_serial_in(void)
+{
+       int tmout = SPK_SERIAL_TIMEOUT;
+
+       while (!(inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR)) {
+               if (--tmout == 0) {
+                       pr_warn("time out while waiting for input.\n");
+                       return 0xff;
+               }
+               udelay(1);
+       }
+       return inb_p(speakup_info.port_tts + UART_RX);
+}
+
+static unsigned char spk_serial_in_nowait(void)
+{
+       unsigned char lsr;
+
+       lsr = inb_p(speakup_info.port_tts + UART_LSR);
+       if (!(lsr & UART_LSR_DR))
+               return 0;
+       return inb_p(speakup_info.port_tts + UART_RX);
+}
+
+static void spk_serial_flush_buffer(void)
+{
+       /* TODO: flush the UART 16550 buffer */
+}
+
+static int spk_serial_out(struct spk_synth *in_synth, const char ch)
+{
+       if (in_synth->alive && spk_wait_for_xmitr(in_synth)) {
+               outb_p(ch, speakup_info.port_tts);
+               return 1;
+       }
+       return 0;
+}
+
+const char *spk_serial_synth_immediate(struct spk_synth *synth,
+                                      const char *buff)
+{
+       u_char ch;
+
+       while ((ch = *buff)) {
+               if (ch == '\n')
+                       ch = synth->procspeech;
+               if (spk_wait_for_xmitr(synth))
+                       outb(ch, speakup_info.port_tts);
+               else
+                       return buff;
+               buff++;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(spk_serial_synth_immediate);
+
+void spk_serial_release(void)
+{
+       spk_stop_serial_interrupt();
+       if (speakup_info.port_tts == 0)
+               return;
+       synth_release_region(speakup_info.port_tts, 8);
+       speakup_info.port_tts = 0;
+}
+EXPORT_SYMBOL_GPL(spk_serial_release);
diff --git a/drivers/accessibility/speakup/serialio.h b/drivers/accessibility/speakup/serialio.h
new file mode 100644 (file)
index 0000000..6f8f86f
--- /dev/null
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SPEAKUP_SERIAL_H
+#define _SPEAKUP_SERIAL_H
+
+#include <linux/serial.h>      /* for rs_table, serial constants */
+#include <linux/serial_reg.h>  /* for more serial constants */
+#include <linux/serial_core.h>
+
+#include "spk_priv.h"
+
+/*
+ * this is cut&paste from 8250.h. Get rid of the structure, the definitions
+ * and this whole broken driver.
+ */
+struct old_serial_port {
+       unsigned int uart; /* unused */
+       unsigned int baud_base;
+       unsigned int port;
+       unsigned int irq;
+       upf_t flags; /* unused */
+};
+
+/* countdown values for serial timeouts in us */
+#define SPK_SERIAL_TIMEOUT SPK_SYNTH_TIMEOUT
+/* countdown values transmitter/dsr timeouts in us */
+#define SPK_XMITR_TIMEOUT 100000
+/* countdown values cts timeouts in us */
+#define SPK_CTS_TIMEOUT 100000
+/* check ttyS0 ... ttyS3 */
+#define SPK_LO_TTY 0
+#define SPK_HI_TTY 3
+/* # of timeouts permitted before disable */
+#define NUM_DISABLE_TIMEOUTS 3
+/* buffer timeout in ms */
+#define SPK_TIMEOUT 100
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+#define spk_serial_tx_busy() \
+       ((inb(speakup_info.port_tts + UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
+
+#endif
diff --git a/drivers/accessibility/speakup/speakup.h b/drivers/accessibility/speakup/speakup.h
new file mode 100644 (file)
index 0000000..74fe49c
--- /dev/null
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SPEAKUP_H
+#define _SPEAKUP_H
+
+#include "spk_types.h"
+#include "i18n.h"
+
+#define SPEAKUP_VERSION "3.1.6"
+#define KEY_MAP_VER 119
+#define SHIFT_TBL_SIZE 64
+#define MAX_DESC_LEN 72
+
+#define TOGGLE_0 .u.n = {NULL, 0, 0, 1, 0, 0, NULL }
+#define TOGGLE_1 .u.n = {NULL, 1, 0, 1, 0, 0, NULL }
+#define MAXVARLEN 15
+
+#define SYNTH_OK 0x0001
+#define B_ALPHA 0x0002
+#define ALPHA 0x0003
+#define B_CAP 0x0004
+#define A_CAP 0x0007
+#define B_NUM 0x0008
+#define NUM 0x0009
+#define ALPHANUM (B_ALPHA | B_NUM)
+#define SOME 0x0010
+#define MOST 0x0020
+#define PUNC 0x0040
+#define A_PUNC 0x0041
+#define B_WDLM 0x0080
+#define WDLM 0x0081
+#define B_EXNUM 0x0100
+#define CH_RPT 0x0200
+#define B_CTL 0x0400
+#define A_CTL (B_CTL + SYNTH_OK)
+#define B_SYM 0x0800
+#define B_CAPSYM (B_CAP | B_SYM)
+
+/* FIXME: u16 */
+#define IS_WDLM(x) (spk_chartab[((u_char)x)] & B_WDLM)
+#define IS_CHAR(x, type) (spk_chartab[((u_char)x)] & type)
+#define IS_TYPE(x, type) ((spk_chartab[((u_char)x)] & type) == type)
+
+int speakup_thread(void *data);
+void spk_reset_default_chars(void);
+void spk_reset_default_chartab(void);
+void synth_start(void);
+void synth_insert_next_index(int sent_num);
+void spk_reset_index_count(int sc);
+void spk_get_index_count(int *linecount, int *sentcount);
+int spk_set_key_info(const u_char *key_info, u_char *k_buffer);
+char *spk_strlwr(char *s);
+char *spk_s2uchar(char *start, char *dest);
+int speakup_kobj_init(void);
+void speakup_kobj_exit(void);
+int spk_chartab_get_value(char *keyword);
+void speakup_register_var(struct var_t *var);
+void speakup_unregister_var(enum var_id_t var_id);
+struct st_var_header *spk_get_var_header(enum var_id_t var_id);
+struct st_var_header *spk_var_header_by_name(const char *name);
+struct punc_var_t *spk_get_punc_var(enum var_id_t var_id);
+int spk_set_num_var(int val, struct st_var_header *var, int how);
+int spk_set_string_var(const char *page, struct st_var_header *var, int len);
+int spk_set_mask_bits(const char *input, const int which, const int how);
+extern special_func spk_special_handler;
+int spk_handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key);
+int synth_init(char *name);
+void synth_release(void);
+
+void spk_do_flush(void);
+void speakup_start_ttys(void);
+void synth_buffer_add(u16 ch);
+void synth_buffer_clear(void);
+void speakup_clear_selection(void);
+int speakup_set_selection(struct tty_struct *tty);
+void speakup_cancel_selection(void);
+int speakup_paste_selection(struct tty_struct *tty);
+void speakup_cancel_paste(void);
+void speakup_register_devsynth(void);
+void speakup_unregister_devsynth(void);
+void synth_write(const char *buf, size_t count);
+int synth_supports_indexing(void);
+
+extern struct vc_data *spk_sel_cons;
+extern unsigned short spk_xs, spk_ys, spk_xe, spk_ye; /* our region points */
+
+extern wait_queue_head_t speakup_event;
+extern struct kobject *speakup_kobj;
+extern struct task_struct *speakup_task;
+extern const u_char spk_key_defaults[];
+
+/* Protect speakup synthesizer list */
+extern struct mutex spk_mutex;
+extern struct st_spk_t *speakup_console[];
+extern struct spk_synth *synth;
+extern char spk_pitch_buff[];
+extern u_char *spk_our_keys[];
+extern short spk_punc_masks[];
+extern char spk_str_caps_start[], spk_str_caps_stop[], spk_str_pause[];
+extern bool spk_paused;
+extern const struct st_bits_data spk_punc_info[];
+extern u_char spk_key_buf[600];
+extern char *spk_characters[];
+extern char *spk_default_chars[];
+extern u_short spk_chartab[];
+extern int spk_no_intr, spk_say_ctrl, spk_say_word_ctl, spk_punc_level;
+extern int spk_reading_punc, spk_attrib_bleep, spk_bleeps;
+extern int spk_bleep_time, spk_bell_pos;
+extern int spk_spell_delay, spk_key_echo;
+extern short spk_punc_mask;
+extern short spk_pitch_shift, synth_flags;
+extern bool spk_quiet_boot;
+extern char *synth_name;
+extern struct bleep spk_unprocessed_sound;
+
+/* Prototypes from fakekey.c. */
+int speakup_add_virtual_keyboard(void);
+void speakup_remove_virtual_keyboard(void);
+void speakup_fake_down_arrow(void);
+bool speakup_fake_key_pressed(void);
+
+#endif
diff --git a/drivers/accessibility/speakup/speakup_acnt.h b/drivers/accessibility/speakup/speakup_acnt.h
new file mode 100644 (file)
index 0000000..cffa938
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* speakup_acntpc.h - header file for speakups Accent-PC driver. */
+
+#define SYNTH_IO_EXTENT        0x02
+
+#define SYNTH_CLEAR    0x18            /* stops speech */
+
+       /* Port Status Flags */
+#define SYNTH_READABLE 0x01    /* mask for bit which is nonzero if a
+                                * byte can be read from the data port
+                                */
+#define SYNTH_WRITABLE 0x02    /* mask for RDY bit, which when set to
+                                * 1, indicates the data port is ready
+                                *  to accept a byte of data.
+                                */
+#define SYNTH_QUIET    'S' /* synth is not speaking */
+#define SYNTH_FULL     'F' /* synth is full. */
+#define SYNTH_ALMOST_EMPTY 'M' /* synth has less than 2 seconds of text left */
+#define SYNTH_SPEAKING 's' /* synth is speaking and has a fare way to go */
diff --git a/drivers/accessibility/speakup/speakup_acntpc.c b/drivers/accessibility/speakup/speakup_acntpc.c
new file mode 100644 (file)
index 0000000..c94328a
--- /dev/null
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+ * This driver is for the Aicom Acent PC internal synthesizer.
+ */
+
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+
+#include "spk_priv.h"
+#include "serialio.h"
+#include "speakup.h"
+#include "speakup_acnt.h" /* local header file for Accent values */
+
+#define DRV_VERSION "2.10"
+#define PROCSPEECH '\r'
+
+static int synth_probe(struct spk_synth *synth);
+static void accent_release(void);
+static const char *synth_immediate(struct spk_synth *synth, const char *buf);
+static void do_catch_up(struct spk_synth *synth);
+static void synth_flush(struct spk_synth *synth);
+
+static int synth_port_control;
+static int port_forced;
+static unsigned int synth_portlist[] = { 0x2a8, 0 };
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"\033P8" } },
+       { CAPS_STOP, .u.s = {"\033P5" } },
+       { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" } },
+       { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL } },
+       { VOL, .u.n = {"\033A%d", 5, 0, 9, 0, 0, NULL } },
+       { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/acntpc.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute tone_attribute =
+       __ATTR(tone, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &rate_attribute.attr,
+       &tone_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_acntpc = {
+       .name = "acntpc",
+       .version = DRV_VERSION,
+       .long_name = "Accent PC",
+       .init = "\033=X \033Oi\033T2\033=M\033N1\n",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 1000,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_serial_io_ops,
+       .probe = synth_probe,
+       .release = accent_release,
+       .synth_immediate = synth_immediate,
+       .catch_up = do_catch_up,
+       .flush = synth_flush,
+       .is_alive = spk_synth_is_alive_nop,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = NULL,
+       .indexing = {
+               .command = NULL,
+               .lowindex = 0,
+               .highindex = 0,
+               .currindex = 0,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "acntpc",
+       },
+};
+
+static inline bool synth_writable(void)
+{
+       return inb_p(synth_port_control) & SYNTH_WRITABLE;
+}
+
+static inline bool synth_full(void)
+{
+       return inb_p(speakup_info.port_tts + UART_RX) == 'F';
+}
+
+static const char *synth_immediate(struct spk_synth *synth, const char *buf)
+{
+       u_char ch;
+
+       while ((ch = *buf)) {
+               int timeout = SPK_XMITR_TIMEOUT;
+
+               if (ch == '\n')
+                       ch = PROCSPEECH;
+               if (synth_full())
+                       return buf;
+               while (synth_writable()) {
+                       if (!--timeout)
+                               return buf;
+                       udelay(1);
+               }
+               outb_p(ch, speakup_info.port_tts);
+               buf++;
+       }
+       return NULL;
+}
+
+static void do_catch_up(struct spk_synth *synth)
+{
+       u_char ch;
+       unsigned long flags;
+       unsigned long jiff_max;
+       int timeout;
+       int delay_time_val;
+       int jiffy_delta_val;
+       int full_time_val;
+       struct var_t *delay_time;
+       struct var_t *full_time;
+       struct var_t *jiffy_delta;
+
+       jiffy_delta = spk_get_var(JIFFY);
+       delay_time = spk_get_var(DELAY);
+       full_time = spk_get_var(FULL);
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       jiffy_delta_val = jiffy_delta->u.n.value;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+
+       jiff_max = jiffies + jiffy_delta_val;
+       while (!kthread_should_stop()) {
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               if (speakup_info.flushing) {
+                       speakup_info.flushing = 0;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       synth->flush(synth);
+                       continue;
+               }
+               synth_buffer_skip_nonlatin1();
+               if (synth_buffer_empty()) {
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       break;
+               }
+               set_current_state(TASK_INTERRUPTIBLE);
+               full_time_val = full_time->u.n.value;
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (synth_full()) {
+                       schedule_timeout(msecs_to_jiffies(full_time_val));
+                       continue;
+               }
+               set_current_state(TASK_RUNNING);
+               timeout = SPK_XMITR_TIMEOUT;
+               while (synth_writable()) {
+                       if (!--timeout)
+                               break;
+                       udelay(1);
+               }
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               ch = synth_buffer_getc();
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (ch == '\n')
+                       ch = PROCSPEECH;
+               outb_p(ch, speakup_info.port_tts);
+               if (time_after_eq(jiffies, jiff_max) && ch == SPACE) {
+                       timeout = SPK_XMITR_TIMEOUT;
+                       while (synth_writable()) {
+                               if (!--timeout)
+                                       break;
+                               udelay(1);
+                       }
+                       outb_p(PROCSPEECH, speakup_info.port_tts);
+                       spin_lock_irqsave(&speakup_info.spinlock, flags);
+                       jiffy_delta_val = jiffy_delta->u.n.value;
+                       delay_time_val = delay_time->u.n.value;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       schedule_timeout(msecs_to_jiffies(delay_time_val));
+                       jiff_max = jiffies + jiffy_delta_val;
+               }
+       }
+       timeout = SPK_XMITR_TIMEOUT;
+       while (synth_writable()) {
+               if (!--timeout)
+                       break;
+               udelay(1);
+       }
+       outb_p(PROCSPEECH, speakup_info.port_tts);
+}
+
+static void synth_flush(struct spk_synth *synth)
+{
+       outb_p(SYNTH_CLEAR, speakup_info.port_tts);
+}
+
+static int synth_probe(struct spk_synth *synth)
+{
+       unsigned int port_val = 0;
+       int i = 0;
+
+       pr_info("Probing for %s.\n", synth->long_name);
+       if (port_forced) {
+               speakup_info.port_tts = port_forced;
+               pr_info("probe forced to %x by kernel command line\n",
+                       speakup_info.port_tts);
+               if (synth_request_region(speakup_info.port_tts - 1,
+                                        SYNTH_IO_EXTENT)) {
+                       pr_warn("sorry, port already reserved\n");
+                       return -EBUSY;
+               }
+               port_val = inw(speakup_info.port_tts - 1);
+               synth_port_control = speakup_info.port_tts - 1;
+       } else {
+               for (i = 0; synth_portlist[i]; i++) {
+                       if (synth_request_region(synth_portlist[i],
+                                                SYNTH_IO_EXTENT)) {
+                               pr_warn
+                                   ("request_region: failed with 0x%x, %d\n",
+                                    synth_portlist[i], SYNTH_IO_EXTENT);
+                               continue;
+                       }
+                       port_val = inw(synth_portlist[i]) & 0xfffc;
+                       if (port_val == 0x53fc) {
+                               /* 'S' and out&input bits */
+                               synth_port_control = synth_portlist[i];
+                               speakup_info.port_tts = synth_port_control + 1;
+                               break;
+                       }
+               }
+       }
+       port_val &= 0xfffc;
+       if (port_val != 0x53fc) {
+               /* 'S' and out&input bits */
+               pr_info("%s: not found\n", synth->long_name);
+               synth_release_region(synth_port_control, SYNTH_IO_EXTENT);
+               synth_port_control = 0;
+               return -ENODEV;
+       }
+       pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name,
+               synth_port_control, synth_port_control + SYNTH_IO_EXTENT - 1,
+               synth->version);
+       synth->alive = 1;
+       return 0;
+}
+
+static void accent_release(void)
+{
+       spk_stop_serial_interrupt();
+       if (speakup_info.port_tts)
+               synth_release_region(speakup_info.port_tts - 1,
+                                    SYNTH_IO_EXTENT);
+       speakup_info.port_tts = 0;
+}
+
+module_param_hw_named(port, port_forced, int, ioport, 0444);
+module_param_named(start, synth_acntpc.startup, short, 0444);
+
+MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_acntpc);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for Accent PC synthesizer");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_acntsa.c b/drivers/accessibility/speakup/speakup_acntsa.c
new file mode 100644 (file)
index 0000000..3a863dc
--- /dev/null
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+ */
+
+#include "spk_priv.h"
+#include "speakup.h"
+#include "speakup_acnt.h" /* local header file for Accent values */
+
+#define DRV_VERSION "2.11"
+#define PROCSPEECH '\r'
+
+static int synth_probe(struct spk_synth *synth);
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"\033P8" } },
+       { CAPS_STOP, .u.s = {"\033P5" } },
+       { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" } },
+       { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL } },
+       { VOL, .u.n = {"\033A%d", 9, 0, 9, 0, 0, NULL } },
+       { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/acntsa.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute tone_attribute =
+       __ATTR(tone, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &rate_attribute.attr,
+       &tone_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_acntsa = {
+       .name = "acntsa",
+       .version = DRV_VERSION,
+       .long_name = "Accent-SA",
+       .init = "\033T2\033=M\033Oi\033N1\n",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 400,
+       .trigger = 50,
+       .jiffies = 30,
+       .full = 40000,
+       .dev_name = SYNTH_DEFAULT_DEV,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_ttyio_ops,
+       .probe = synth_probe,
+       .release = spk_ttyio_release,
+       .synth_immediate = spk_ttyio_synth_immediate,
+       .catch_up = spk_do_catch_up,
+       .flush = spk_synth_flush,
+       .is_alive = spk_synth_is_alive_restart,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = NULL,
+       .indexing = {
+               .command = NULL,
+               .lowindex = 0,
+               .highindex = 0,
+               .currindex = 0,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "acntsa",
+       },
+};
+
+static int synth_probe(struct spk_synth *synth)
+{
+       int failed;
+
+       failed = spk_ttyio_synth_probe(synth);
+       if (failed == 0) {
+               synth->synth_immediate(synth, "\033=R\r");
+               mdelay(100);
+       }
+       synth->alive = !failed;
+       return failed;
+}
+
+module_param_named(ser, synth_acntsa.ser, int, 0444);
+module_param_named(dev, synth_acntsa.dev_name, charp, 0444);
+module_param_named(start, synth_acntsa.startup, short, 0444);
+
+MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
+MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_acntsa);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for Accent SA synthesizer");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_apollo.c b/drivers/accessibility/speakup/speakup_apollo.c
new file mode 100644 (file)
index 0000000..0877b40
--- /dev/null
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+ */
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+#include <linux/serial_reg.h>  /* for UART_MCR* constants */
+
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define DRV_VERSION "2.21"
+#define SYNTH_CLEAR 0x18
+#define PROCSPEECH '\r'
+
+static void do_catch_up(struct spk_synth *synth);
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"cap, " } },
+       { CAPS_STOP, .u.s = {"" } },
+       { RATE, .u.n = {"@W%d", 6, 1, 9, 0, 0, NULL } },
+       { PITCH, .u.n = {"@F%x", 10, 0, 15, 0, 0, NULL } },
+       { VOL, .u.n = {"@A%x", 10, 0, 15, 0, 0, NULL } },
+       { VOICE, .u.n = {"@V%d", 1, 1, 6, 0, 0, NULL } },
+       { LANG, .u.n = {"@=%d,", 1, 1, 4, 0, 0, NULL } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/apollo.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute lang_attribute =
+       __ATTR(lang, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute voice_attribute =
+       __ATTR(voice, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &lang_attribute.attr,
+       &pitch_attribute.attr,
+       &rate_attribute.attr,
+       &voice_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_apollo = {
+       .name = "apollo",
+       .version = DRV_VERSION,
+       .long_name = "Apollo",
+       .init = "@R3@D0@K1\r",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 40000,
+       .dev_name = SYNTH_DEFAULT_DEV,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_ttyio_ops,
+       .probe = spk_ttyio_synth_probe,
+       .release = spk_ttyio_release,
+       .synth_immediate = spk_ttyio_synth_immediate,
+       .catch_up = do_catch_up,
+       .flush = spk_synth_flush,
+       .is_alive = spk_synth_is_alive_restart,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = NULL,
+       .indexing = {
+               .command = NULL,
+               .lowindex = 0,
+               .highindex = 0,
+               .currindex = 0,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "apollo",
+       },
+};
+
+static void do_catch_up(struct spk_synth *synth)
+{
+       u_char ch;
+       unsigned long flags;
+       unsigned long jiff_max;
+       struct var_t *jiffy_delta;
+       struct var_t *delay_time;
+       struct var_t *full_time;
+       int full_time_val = 0;
+       int delay_time_val = 0;
+       int jiffy_delta_val = 0;
+
+       jiffy_delta = spk_get_var(JIFFY);
+       delay_time = spk_get_var(DELAY);
+       full_time = spk_get_var(FULL);
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       jiffy_delta_val = jiffy_delta->u.n.value;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       jiff_max = jiffies + jiffy_delta_val;
+
+       while (!kthread_should_stop()) {
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               jiffy_delta_val = jiffy_delta->u.n.value;
+               full_time_val = full_time->u.n.value;
+               delay_time_val = delay_time->u.n.value;
+               if (speakup_info.flushing) {
+                       speakup_info.flushing = 0;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       synth->flush(synth);
+                       continue;
+               }
+               synth_buffer_skip_nonlatin1();
+               if (synth_buffer_empty()) {
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       break;
+               }
+               ch = synth_buffer_peek();
+               set_current_state(TASK_INTERRUPTIBLE);
+               full_time_val = full_time->u.n.value;
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (!synth->io_ops->synth_out(synth, ch)) {
+                       synth->io_ops->tiocmset(0, UART_MCR_RTS);
+                       synth->io_ops->tiocmset(UART_MCR_RTS, 0);
+                       schedule_timeout(msecs_to_jiffies(full_time_val));
+                       continue;
+               }
+               if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
+                       spin_lock_irqsave(&speakup_info.spinlock, flags);
+                       jiffy_delta_val = jiffy_delta->u.n.value;
+                       full_time_val = full_time->u.n.value;
+                       delay_time_val = delay_time->u.n.value;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       if (synth->io_ops->synth_out(synth, synth->procspeech))
+                               schedule_timeout(msecs_to_jiffies
+                                                (delay_time_val));
+                       else
+                               schedule_timeout(msecs_to_jiffies
+                                                (full_time_val));
+                       jiff_max = jiffies + jiffy_delta_val;
+               }
+               set_current_state(TASK_RUNNING);
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               synth_buffer_getc();
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       }
+       synth->io_ops->synth_out(synth, PROCSPEECH);
+}
+
+module_param_named(ser, synth_apollo.ser, int, 0444);
+module_param_named(dev, synth_apollo.dev_name, charp, 0444);
+module_param_named(start, synth_apollo.startup, short, 0444);
+
+MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
+MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_apollo);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for Apollo II synthesizer");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_audptr.c b/drivers/accessibility/speakup/speakup_audptr.c
new file mode 100644 (file)
index 0000000..e6a6a96
--- /dev/null
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * specificly written as a driver for the speakup screenreview
+ * s not a general device driver.
+ */
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define DRV_VERSION "2.11"
+#define SYNTH_CLEAR 0x18 /* flush synth buffer */
+#define PROCSPEECH '\r' /* start synth processing speech char */
+
+static int synth_probe(struct spk_synth *synth);
+static void synth_flush(struct spk_synth *synth);
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"\x05[f99]" } },
+       { CAPS_STOP, .u.s = {"\x05[f80]" } },
+       { RATE, .u.n = {"\x05[r%d]", 10, 0, 20, 100, -10, NULL } },
+       { PITCH, .u.n = {"\x05[f%d]", 80, 39, 4500, 0, 0, NULL } },
+       { VOL, .u.n = {"\x05[g%d]", 21, 0, 40, 0, 0, NULL } },
+       { TONE, .u.n = {"\x05[s%d]", 9, 0, 63, 0, 0, NULL } },
+       { PUNCT, .u.n = {"\x05[A%c]", 0, 0, 3, 0, 0, "nmsa" } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/audptr.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute punct_attribute =
+       __ATTR(punct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute tone_attribute =
+       __ATTR(tone, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &punct_attribute.attr,
+       &rate_attribute.attr,
+       &tone_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_audptr = {
+       .name = "audptr",
+       .version = DRV_VERSION,
+       .long_name = "Audapter",
+       .init = "\x05[D1]\x05[Ol]",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 400,
+       .trigger = 50,
+       .jiffies = 30,
+       .full = 18000,
+       .dev_name = SYNTH_DEFAULT_DEV,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_ttyio_ops,
+       .probe = synth_probe,
+       .release = spk_ttyio_release,
+       .synth_immediate = spk_ttyio_synth_immediate,
+       .catch_up = spk_do_catch_up,
+       .flush = synth_flush,
+       .is_alive = spk_synth_is_alive_restart,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = NULL,
+       .indexing = {
+               .command = NULL,
+               .lowindex = 0,
+               .highindex = 0,
+               .currindex = 0,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "audptr",
+       },
+};
+
+static void synth_flush(struct spk_synth *synth)
+{
+       synth->io_ops->flush_buffer();
+       synth->io_ops->send_xchar(SYNTH_CLEAR);
+       synth->io_ops->synth_out(synth, PROCSPEECH);
+}
+
+static void synth_version(struct spk_synth *synth)
+{
+       unsigned char test = 0;
+       char synth_id[40] = "";
+
+       synth->synth_immediate(synth, "\x05[Q]");
+       synth_id[test] = synth->io_ops->synth_in();
+       if (synth_id[test] == 'A') {
+               do {
+                       /* read version string from synth */
+                       synth_id[++test] = synth->io_ops->synth_in();
+               } while (synth_id[test] != '\n' && test < 32);
+               synth_id[++test] = 0x00;
+       }
+       if (synth_id[0] == 'A')
+               pr_info("%s version: %s", synth->long_name, synth_id);
+}
+
+static int synth_probe(struct spk_synth *synth)
+{
+       int failed;
+
+       failed = spk_ttyio_synth_probe(synth);
+       if (failed == 0)
+               synth_version(synth);
+       synth->alive = !failed;
+       return 0;
+}
+
+module_param_named(ser, synth_audptr.ser, int, 0444);
+module_param_named(dev, synth_audptr.dev_name, charp, 0444);
+module_param_named(start, synth_audptr.startup, short, 0444);
+
+MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
+MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_audptr);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for Audapter synthesizer");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_bns.c b/drivers/accessibility/speakup/speakup_bns.c
new file mode 100644 (file)
index 0000000..76dfa3f
--- /dev/null
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+ */
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define DRV_VERSION "2.11"
+#define SYNTH_CLEAR 0x18
+#define PROCSPEECH '\r'
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"\x05\x31\x32P" } },
+       { CAPS_STOP, .u.s = {"\x05\x38P" } },
+       { RATE, .u.n = {"\x05%dE", 8, 1, 16, 0, 0, NULL } },
+       { PITCH, .u.n = {"\x05%dP", 8, 0, 16, 0, 0, NULL } },
+       { VOL, .u.n = {"\x05%dV", 8, 0, 16, 0, 0, NULL } },
+       { TONE, .u.n = {"\x05%dT", 8, 0, 16, 0, 0, NULL } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/bns.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute tone_attribute =
+       __ATTR(tone, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &rate_attribute.attr,
+       &tone_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_bns = {
+       .name = "bns",
+       .version = DRV_VERSION,
+       .long_name = "Braille 'N Speak",
+       .init = "\x05Z\x05\x43",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 40000,
+       .dev_name = SYNTH_DEFAULT_DEV,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_ttyio_ops,
+       .probe = spk_ttyio_synth_probe,
+       .release = spk_ttyio_release,
+       .synth_immediate = spk_ttyio_synth_immediate,
+       .catch_up = spk_do_catch_up,
+       .flush = spk_synth_flush,
+       .is_alive = spk_synth_is_alive_restart,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = NULL,
+       .indexing = {
+               .command = NULL,
+               .lowindex = 0,
+               .highindex = 0,
+               .currindex = 0,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "bns",
+       },
+};
+
+module_param_named(ser, synth_bns.ser, int, 0444);
+module_param_named(dev, synth_bns.dev_name, charp, 0444);
+module_param_named(start, synth_bns.startup, short, 0444);
+
+MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
+MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_bns);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for Braille 'n Speak synthesizers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_decext.c b/drivers/accessibility/speakup/speakup_decext.c
new file mode 100644 (file)
index 0000000..7408eb2
--- /dev/null
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * specificly written as a driver for the speakup screenreview
+ * s not a general device driver.
+ */
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define DRV_VERSION "2.14"
+#define SYNTH_CLEAR 0x03
+#define PROCSPEECH 0x0b
+
+static volatile unsigned char last_char;
+
+static void read_buff_add(u_char ch)
+{
+       last_char = ch;
+}
+
+static inline bool synth_full(void)
+{
+       return last_char == 0x13;
+}
+
+static void do_catch_up(struct spk_synth *synth);
+static void synth_flush(struct spk_synth *synth);
+
+static int in_escape;
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"[:dv ap 222]" } },
+       { CAPS_STOP, .u.s = {"[:dv ap 100]" } },
+       { RATE, .u.n = {"[:ra %d]", 7, 0, 9, 150, 25, NULL } },
+       { PITCH, .u.n = {"[:dv ap %d]", 100, 0, 100, 0, 0, NULL } },
+       { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
+       { VOL, .u.n = {"[:dv gv %d]", 13, 0, 16, 0, 5, NULL } },
+       { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" } },
+       { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/decext.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute inflection_attribute =
+       __ATTR(inflection, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute punct_attribute =
+       __ATTR(punct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute voice_attribute =
+       __ATTR(voice, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &inflection_attribute.attr,
+       &punct_attribute.attr,
+       &rate_attribute.attr,
+       &voice_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_decext = {
+       .name = "decext",
+       .version = DRV_VERSION,
+       .long_name = "Dectalk External",
+       .init = "[:pe -380]",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 40000,
+       .flags = SF_DEC,
+       .dev_name = SYNTH_DEFAULT_DEV,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_ttyio_ops,
+       .probe = spk_ttyio_synth_probe,
+       .release = spk_ttyio_release,
+       .synth_immediate = spk_ttyio_synth_immediate,
+       .catch_up = do_catch_up,
+       .flush = synth_flush,
+       .is_alive = spk_synth_is_alive_restart,
+       .synth_adjust = NULL,
+       .read_buff_add = read_buff_add,
+       .get_index = NULL,
+       .indexing = {
+               .command = NULL,
+               .lowindex = 0,
+               .highindex = 0,
+               .currindex = 0,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "decext",
+       },
+};
+
+static void do_catch_up(struct spk_synth *synth)
+{
+       u_char ch;
+       static u_char last = '\0';
+       unsigned long flags;
+       unsigned long jiff_max;
+       struct var_t *jiffy_delta;
+       struct var_t *delay_time;
+       int jiffy_delta_val = 0;
+       int delay_time_val = 0;
+
+       jiffy_delta = spk_get_var(JIFFY);
+       delay_time = spk_get_var(DELAY);
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       jiffy_delta_val = jiffy_delta->u.n.value;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       jiff_max = jiffies + jiffy_delta_val;
+
+       while (!kthread_should_stop()) {
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               if (speakup_info.flushing) {
+                       speakup_info.flushing = 0;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       synth->flush(synth);
+                       continue;
+               }
+               synth_buffer_skip_nonlatin1();
+               if (synth_buffer_empty()) {
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       break;
+               }
+               ch = synth_buffer_peek();
+               set_current_state(TASK_INTERRUPTIBLE);
+               delay_time_val = delay_time->u.n.value;
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (ch == '\n')
+                       ch = 0x0D;
+               if (synth_full() || !synth->io_ops->synth_out(synth, ch)) {
+                       schedule_timeout(msecs_to_jiffies(delay_time_val));
+                       continue;
+               }
+               set_current_state(TASK_RUNNING);
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               synth_buffer_getc();
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (ch == '[') {
+                       in_escape = 1;
+               } else if (ch == ']') {
+                       in_escape = 0;
+               } else if (ch <= SPACE) {
+                       if (!in_escape && strchr(",.!?;:", last))
+                               synth->io_ops->synth_out(synth, PROCSPEECH);
+                       if (time_after_eq(jiffies, jiff_max)) {
+                               if (!in_escape)
+                                       synth->io_ops->synth_out(synth,
+                                                                PROCSPEECH);
+                               spin_lock_irqsave(&speakup_info.spinlock,
+                                                 flags);
+                               jiffy_delta_val = jiffy_delta->u.n.value;
+                               delay_time_val = delay_time->u.n.value;
+                               spin_unlock_irqrestore(&speakup_info.spinlock,
+                                                      flags);
+                               schedule_timeout(msecs_to_jiffies
+                                                (delay_time_val));
+                               jiff_max = jiffies + jiffy_delta_val;
+                       }
+               }
+               last = ch;
+       }
+       if (!in_escape)
+               synth->io_ops->synth_out(synth, PROCSPEECH);
+}
+
+static void synth_flush(struct spk_synth *synth)
+{
+       in_escape = 0;
+       synth->io_ops->flush_buffer();
+       synth->synth_immediate(synth, "\033P;10z\033\\");
+}
+
+module_param_named(ser, synth_decext.ser, int, 0444);
+module_param_named(dev, synth_decext.dev_name, charp, 0444);
+module_param_named(start, synth_decext.startup, short, 0444);
+
+MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
+MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_decext);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for DECtalk External synthesizers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_decpc.c b/drivers/accessibility/speakup/speakup_decpc.c
new file mode 100644 (file)
index 0000000..96f24c8
--- /dev/null
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This is the DECtalk PC speakup driver
+ *
+ * Some constants from DEC's DOS driver:
+ *      Copyright (c) by Digital Equipment Corp.
+ *
+ * 386BSD DECtalk PC driver:
+ *      Copyright (c) 1996 Brian Buhrow <buhrow@lothlorien.nfbcal.org>
+ *
+ * Linux DECtalk PC driver:
+ *      Copyright (c) 1997 Nicolas Pitre <nico@cam.org>
+ *
+ * speakup DECtalk PC Internal driver:
+ *      Copyright (c) 2003 David Borowski <david575@golden.net>
+ *
+ * All rights reserved.
+ */
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define        MODULE_init             0x0dec  /* module in boot code */
+#define        MODULE_self_test        0x8800  /* module in self-test */
+#define        MODULE_reset            0xffff  /* reinit the whole module */
+
+#define        MODE_mask               0xf000  /* mode bits in high nibble */
+#define        MODE_null               0x0000
+#define        MODE_test               0x2000  /* in testing mode */
+#define        MODE_status             0x8000
+#define        STAT_int                0x0001  /* running in interrupt mode */
+#define        STAT_tr_char            0x0002  /* character data to transmit */
+#define        STAT_rr_char            0x0004  /* ready to receive char data */
+#define        STAT_cmd_ready          0x0008  /* ready to accept commands */
+#define        STAT_dma_ready          0x0010  /* dma command ready */
+#define        STAT_digitized          0x0020  /* spc in digitized mode */
+#define        STAT_new_index          0x0040  /* new last index ready */
+#define        STAT_new_status         0x0080  /* new status posted */
+#define        STAT_dma_state          0x0100  /* dma state toggle */
+#define        STAT_index_valid        0x0200  /* indexs are valid */
+#define        STAT_flushing           0x0400  /* flush in progress */
+#define        STAT_self_test          0x0800  /* module in self test */
+#define        MODE_ready              0xc000  /* module ready for next phase */
+#define        READY_boot              0x0000
+#define        READY_kernel            0x0001
+#define        MODE_error              0xf000
+
+#define        CMD_mask                0xf000  /* mask for command nibble */
+#define        CMD_null                0x0000  /* post status */
+#define        CMD_control             0x1000  /* hard control command */
+#define        CTRL_mask               0x0F00  /* mask off control nibble */
+#define        CTRL_data               0x00FF  /* mask to get data byte */
+#define        CTRL_null               0x0000  /* null control */
+#define        CTRL_vol_up             0x0100  /* increase volume */
+#define        CTRL_vol_down           0x0200  /* decrease volume */
+#define        CTRL_vol_set            0x0300  /* set volume */
+#define        CTRL_pause              0x0400  /* pause spc */
+#define        CTRL_resume             0x0500  /* resume spc clock */
+#define        CTRL_resume_spc         0x0001  /* resume spc soft pause */
+#define        CTRL_flush              0x0600  /* flush all buffers */
+#define        CTRL_int_enable         0x0700  /* enable status change ints */
+#define        CTRL_buff_free          0x0800  /* buffer remain count */
+#define        CTRL_buff_used          0x0900  /* buffer in use */
+#define        CTRL_speech             0x0a00  /* immediate speech change */
+#define        CTRL_SP_voice           0x0001  /* voice change */
+#define        CTRL_SP_rate            0x0002  /* rate change */
+#define        CTRL_SP_comma           0x0003  /* comma pause change */
+#define        CTRL_SP_period          0x0004  /* period pause change */
+#define        CTRL_SP_rate_delta      0x0005  /* delta rate change */
+#define        CTRL_SP_get_param       0x0006  /* return the desired parameter */
+#define        CTRL_last_index         0x0b00  /* get last index spoken */
+#define        CTRL_io_priority        0x0c00  /* change i/o priority */
+#define        CTRL_free_mem           0x0d00  /* get free paragraphs on module */
+#define        CTRL_get_lang           0x0e00  /* return bitmask of loaded languages */
+#define        CMD_test                0x2000  /* self-test request */
+#define        TEST_mask               0x0F00  /* isolate test field */
+#define        TEST_null               0x0000  /* no test requested */
+#define        TEST_isa_int            0x0100  /* assert isa irq */
+#define        TEST_echo               0x0200  /* make data in == data out */
+#define        TEST_seg                0x0300  /* set peek/poke segment */
+#define        TEST_off                0x0400  /* set peek/poke offset */
+#define        TEST_peek               0x0500  /* data out == *peek */
+#define        TEST_poke               0x0600  /* *peek == data in */
+#define        TEST_sub_code           0x00FF  /* user defined test sub codes */
+#define        CMD_id                  0x3000  /* return software id */
+#define        ID_null                 0x0000  /* null id */
+#define        ID_kernel               0x0100  /* kernel code executing */
+#define        ID_boot                 0x0200  /* boot code executing */
+#define        CMD_dma                 0x4000  /* force a dma start */
+#define        CMD_reset               0x5000  /* reset module status */
+#define        CMD_sync                0x6000  /* kernel sync command */
+#define        CMD_char_in             0x7000  /* single character send */
+#define        CMD_char_out            0x8000  /* single character get */
+#define        CHAR_count_1            0x0100  /* one char in cmd_low */
+#define        CHAR_count_2            0x0200  /* the second in data_low */
+#define        CHAR_count_3            0x0300  /* the third in data_high */
+#define        CMD_spc_mode            0x9000  /* change spc mode */
+#define        CMD_spc_to_text         0x0100  /* set to text mode */
+#define        CMD_spc_to_digit        0x0200  /* set to digital mode */
+#define        CMD_spc_rate            0x0400  /* change spc data rate */
+#define        CMD_error               0xf000  /* severe error */
+
+enum { PRIMARY_DIC     = 0, USER_DIC, COMMAND_DIC, ABBREV_DIC };
+
+#define        DMA_single_in           0x01
+#define        DMA_single_out          0x02
+#define        DMA_buff_in             0x03
+#define        DMA_buff_out            0x04
+#define        DMA_control             0x05
+#define        DT_MEM_ALLOC            0x03
+#define        DT_SET_DIC              0x04
+#define        DT_START_TASK           0x05
+#define        DT_LOAD_MEM             0x06
+#define        DT_READ_MEM             0x07
+#define        DT_DIGITAL_IN           0x08
+#define        DMA_sync                0x06
+#define        DMA_sync_char           0x07
+
+#define DRV_VERSION "2.12"
+#define PROCSPEECH 0x0b
+#define SYNTH_IO_EXTENT 8
+
+static int synth_probe(struct spk_synth *synth);
+static void dtpc_release(void);
+static const char *synth_immediate(struct spk_synth *synth, const char *buf);
+static void do_catch_up(struct spk_synth *synth);
+static void synth_flush(struct spk_synth *synth);
+
+static int synth_portlist[] = { 0x340, 0x350, 0x240, 0x250, 0 };
+static int in_escape, is_flushing;
+static int dt_stat, dma_state;
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"[:dv ap 200]" } },
+       { CAPS_STOP, .u.s = {"[:dv ap 100]" } },
+       { RATE, .u.n = {"[:ra %d]", 9, 0, 18, 150, 25, NULL } },
+       { PITCH, .u.n = {"[:dv ap %d]", 80, 0, 100, 20, 0, NULL } },
+       { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
+       { VOL, .u.n = {"[:vo se %d]", 5, 0, 9, 5, 10, NULL } },
+       { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" } },
+       { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/decpc.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute inflection_attribute =
+       __ATTR(inflection, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute punct_attribute =
+       __ATTR(punct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute voice_attribute =
+       __ATTR(voice, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &inflection_attribute.attr,
+       &punct_attribute.attr,
+       &rate_attribute.attr,
+       &voice_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_dec_pc = {
+       .name = "decpc",
+       .version = DRV_VERSION,
+       .long_name = "Dectalk PC",
+       .init = "[:pe -380]",
+       .procspeech = PROCSPEECH,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 1000,
+       .flags = SF_DEC,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_serial_io_ops,
+       .probe = synth_probe,
+       .release = dtpc_release,
+       .synth_immediate = synth_immediate,
+       .catch_up = do_catch_up,
+       .flush = synth_flush,
+       .is_alive = spk_synth_is_alive_nop,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = NULL,
+       .indexing = {
+               .command = NULL,
+               .lowindex = 0,
+               .highindex = 0,
+               .currindex = 0,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "decpc",
+       },
+};
+
+static int dt_getstatus(void)
+{
+       dt_stat = inb_p(speakup_info.port_tts) |
+                (inb_p(speakup_info.port_tts + 1) << 8);
+       return dt_stat;
+}
+
+static void dt_sendcmd(u_int cmd)
+{
+       outb_p(cmd & 0xFF, speakup_info.port_tts);
+       outb_p((cmd >> 8) & 0xFF, speakup_info.port_tts + 1);
+}
+
+static int dt_waitbit(int bit)
+{
+       int timeout = 100;
+
+       while (--timeout > 0) {
+               if ((dt_getstatus() & bit) == bit)
+                       return 1;
+               udelay(50);
+       }
+       return 0;
+}
+
+static int dt_wait_dma(void)
+{
+       int timeout = 100, state = dma_state;
+
+       if (!dt_waitbit(STAT_dma_ready))
+               return 0;
+       while (--timeout > 0) {
+               if ((dt_getstatus() & STAT_dma_state) == state)
+                       return 1;
+               udelay(50);
+       }
+       dma_state = dt_getstatus() & STAT_dma_state;
+       return 1;
+}
+
+static int dt_ctrl(u_int cmd)
+{
+       int timeout = 10;
+
+       if (!dt_waitbit(STAT_cmd_ready))
+               return -1;
+       outb_p(0, speakup_info.port_tts + 2);
+       outb_p(0, speakup_info.port_tts + 3);
+       dt_getstatus();
+       dt_sendcmd(CMD_control | cmd);
+       outb_p(0, speakup_info.port_tts + 6);
+       while (dt_getstatus() & STAT_cmd_ready) {
+               udelay(20);
+               if (--timeout == 0)
+                       break;
+       }
+       dt_sendcmd(CMD_null);
+       return 0;
+}
+
+static void synth_flush(struct spk_synth *synth)
+{
+       int timeout = 10;
+
+       if (is_flushing)
+               return;
+       is_flushing = 4;
+       in_escape = 0;
+       while (dt_ctrl(CTRL_flush)) {
+               if (--timeout == 0)
+                       break;
+               udelay(50);
+       }
+       for (timeout = 0; timeout < 10; timeout++) {
+               if (dt_waitbit(STAT_dma_ready))
+                       break;
+               udelay(50);
+       }
+       outb_p(DMA_sync, speakup_info.port_tts + 4);
+       outb_p(0, speakup_info.port_tts + 4);
+       udelay(100);
+       for (timeout = 0; timeout < 10; timeout++) {
+               if (!(dt_getstatus() & STAT_flushing))
+                       break;
+               udelay(50);
+       }
+       dma_state = dt_getstatus() & STAT_dma_state;
+       dma_state ^= STAT_dma_state;
+       is_flushing = 0;
+}
+
+static int dt_sendchar(char ch)
+{
+       if (!dt_wait_dma())
+               return -1;
+       if (!(dt_stat & STAT_rr_char))
+               return -2;
+       outb_p(DMA_single_in, speakup_info.port_tts + 4);
+       outb_p(ch, speakup_info.port_tts + 4);
+       dma_state ^= STAT_dma_state;
+       return 0;
+}
+
+static int testkernel(void)
+{
+       int status = 0;
+
+       if (dt_getstatus() == 0xffff) {
+               status = -1;
+               goto oops;
+       }
+       dt_sendcmd(CMD_sync);
+       if (!dt_waitbit(STAT_cmd_ready))
+               status = -2;
+       else if (dt_stat & 0x8000)
+               return 0;
+       else if (dt_stat == 0x0dec)
+               pr_warn("dec_pc at 0x%x, software not loaded\n",
+                       speakup_info.port_tts);
+       status = -3;
+oops:  synth_release_region(speakup_info.port_tts, SYNTH_IO_EXTENT);
+       speakup_info.port_tts = 0;
+       return status;
+}
+
+static void do_catch_up(struct spk_synth *synth)
+{
+       u_char ch;
+       static u_char last;
+       unsigned long flags;
+       unsigned long jiff_max;
+       struct var_t *jiffy_delta;
+       struct var_t *delay_time;
+       int jiffy_delta_val;
+       int delay_time_val;
+
+       jiffy_delta = spk_get_var(JIFFY);
+       delay_time = spk_get_var(DELAY);
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       jiffy_delta_val = jiffy_delta->u.n.value;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       jiff_max = jiffies + jiffy_delta_val;
+
+       while (!kthread_should_stop()) {
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               if (speakup_info.flushing) {
+                       speakup_info.flushing = 0;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       synth->flush(synth);
+                       continue;
+               }
+               synth_buffer_skip_nonlatin1();
+               if (synth_buffer_empty()) {
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       break;
+               }
+               ch = synth_buffer_peek();
+               set_current_state(TASK_INTERRUPTIBLE);
+               delay_time_val = delay_time->u.n.value;
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (ch == '\n')
+                       ch = 0x0D;
+               if (dt_sendchar(ch)) {
+                       schedule_timeout(msecs_to_jiffies(delay_time_val));
+                       continue;
+               }
+               set_current_state(TASK_RUNNING);
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               synth_buffer_getc();
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (ch == '[') {
+                       in_escape = 1;
+               } else if (ch == ']') {
+                       in_escape = 0;
+               } else if (ch <= SPACE) {
+                       if (!in_escape && strchr(",.!?;:", last))
+                               dt_sendchar(PROCSPEECH);
+                       if (time_after_eq(jiffies, jiff_max)) {
+                               if (!in_escape)
+                                       dt_sendchar(PROCSPEECH);
+                               spin_lock_irqsave(&speakup_info.spinlock,
+                                                 flags);
+                               jiffy_delta_val = jiffy_delta->u.n.value;
+                               delay_time_val = delay_time->u.n.value;
+                               spin_unlock_irqrestore(&speakup_info.spinlock,
+                                                      flags);
+                               schedule_timeout(msecs_to_jiffies
+                                                (delay_time_val));
+                               jiff_max = jiffies + jiffy_delta_val;
+                       }
+               }
+               last = ch;
+               ch = 0;
+       }
+       if (!in_escape)
+               dt_sendchar(PROCSPEECH);
+}
+
+static const char *synth_immediate(struct spk_synth *synth, const char *buf)
+{
+       u_char ch;
+
+       while ((ch = *buf)) {
+               if (ch == '\n')
+                       ch = PROCSPEECH;
+               if (dt_sendchar(ch))
+                       return buf;
+               buf++;
+       }
+       return NULL;
+}
+
+static int synth_probe(struct spk_synth *synth)
+{
+       int i = 0, failed = 0;
+
+       pr_info("Probing for %s.\n", synth->long_name);
+       for (i = 0; synth_portlist[i]; i++) {
+               if (synth_request_region(synth_portlist[i], SYNTH_IO_EXTENT)) {
+                       pr_warn("request_region: failed with 0x%x, %d\n",
+                               synth_portlist[i], SYNTH_IO_EXTENT);
+                       continue;
+               }
+               speakup_info.port_tts = synth_portlist[i];
+               failed = testkernel();
+               if (failed == 0)
+                       break;
+       }
+       if (failed) {
+               pr_info("%s: not found\n", synth->long_name);
+               return -ENODEV;
+       }
+       pr_info("%s: %03x-%03x, Driver Version %s,\n", synth->long_name,
+               speakup_info.port_tts, speakup_info.port_tts + 7,
+               synth->version);
+       synth->alive = 1;
+       return 0;
+}
+
+static void dtpc_release(void)
+{
+       spk_stop_serial_interrupt();
+       if (speakup_info.port_tts)
+               synth_release_region(speakup_info.port_tts, SYNTH_IO_EXTENT);
+       speakup_info.port_tts = 0;
+}
+
+module_param_named(start, synth_dec_pc.startup, short, 0444);
+
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_dec_pc);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for DECtalk PC synthesizers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/accessibility/speakup/speakup_dectlk.c b/drivers/accessibility/speakup/speakup_dectlk.c
new file mode 100644 (file)
index 0000000..780214b
--- /dev/null
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * specificly written as a driver for the speakup screenreview
+ * s not a general device driver.
+ */
+#include <linux/unistd.h>
+#include <linux/proc_fs.h>
+#include <linux/jiffies.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+#include "speakup.h"
+#include "spk_priv.h"
+
+#define DRV_VERSION "2.20"
+#define SYNTH_CLEAR 0x03
+#define PROCSPEECH 0x0b
+static int xoff;
+
+static inline int synth_full(void)
+{
+       return xoff;
+}
+
+static void do_catch_up(struct spk_synth *synth);
+static void synth_flush(struct spk_synth *synth);
+static void read_buff_add(u_char c);
+static unsigned char get_index(struct spk_synth *synth);
+
+static int in_escape;
+static int is_flushing;
+
+static spinlock_t flush_lock;
+static DECLARE_WAIT_QUEUE_HEAD(flush);
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"[:dv ap 160] " } },
+       { CAPS_STOP, .u.s = {"[:dv ap 100 ] " } },
+       { RATE, .u.n = {"[:ra %d] ", 180, 75, 650, 0, 0, NULL } },
+       { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
+       { VOL, .u.n = {"[:dv g5 %d] ", 86, 60, 86, 0, 0, NULL } },
+       { PUNCT, .u.n = {"[:pu %c] ", 0, 0, 2, 0, 0, "nsa" } },
+       { VOICE, .u.n = {"[:n%c] ", 0, 0, 9, 0, 0, "phfdburwkv" } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/dectlk.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute inflection_attribute =
+       __ATTR(inflection, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute punct_attribute =
+       __ATTR(punct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute voice_attribute =
+       __ATTR(voice, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &inflection_attribute.attr,
+       &punct_attribute.attr,
+       &rate_attribute.attr,
+       &voice_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static int ap_defaults[] = {122, 89, 155, 110, 208, 240, 200, 106, 306};
+static int g5_defaults[] = {86, 81, 86, 84, 81, 80, 83, 83, 73};
+
+static struct spk_synth synth_dectlk = {
+       .name = "dectlk",
+       .version = DRV_VERSION,
+       .long_name = "Dectalk Express",
+       .init = "[:error sp :name paul :rate 180 :tsr off] ",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 40000,
+       .dev_name = SYNTH_DEFAULT_DEV,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .default_pitch = ap_defaults,
+       .default_vol = g5_defaults,
+       .io_ops = &spk_ttyio_ops,
+       .probe = spk_ttyio_synth_probe,
+       .release = spk_ttyio_release,
+       .synth_immediate = spk_ttyio_synth_immediate,
+       .catch_up = do_catch_up,
+       .flush = synth_flush,
+       .is_alive = spk_synth_is_alive_restart,
+       .synth_adjust = NULL,
+       .read_buff_add = read_buff_add,
+       .get_index = get_index,
+       .indexing = {
+               .command = "[:in re %d ] ",
+               .lowindex = 1,
+               .highindex = 8,
+               .currindex = 1,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "dectlk",
+       },
+};
+
+static int is_indnum(u_char *ch)
+{
+       if ((*ch >= '0') && (*ch <= '9')) {
+               *ch = *ch - '0';
+               return 1;
+       }
+       return 0;
+}
+
+static u_char lastind;
+
+static unsigned char get_index(struct spk_synth *synth)
+{
+       u_char rv;
+
+       rv = lastind;
+       lastind = 0;
+       return rv;
+}
+
+static void read_buff_add(u_char c)
+{
+       static int ind = -1;
+
+       if (c == 0x01) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&flush_lock, flags);
+               is_flushing = 0;
+               wake_up_interruptible(&flush);
+               spin_unlock_irqrestore(&flush_lock, flags);
+       } else if (c == 0x13) {
+               xoff = 1;
+       } else if (c == 0x11) {
+               xoff = 0;
+       } else if (is_indnum(&c)) {
+               if (ind == -1)
+                       ind = c;
+               else
+                       ind = ind * 10 + c;
+       } else if ((c > 31) && (c < 127)) {
+               if (ind != -1)
+                       lastind = (u_char)ind;
+               ind = -1;
+       }
+}
+
+static void do_catch_up(struct spk_synth *synth)
+{
+       int synth_full_val = 0;
+       static u_char ch;
+       static u_char last = '\0';
+       unsigned long flags;
+       unsigned long jiff_max;
+       unsigned long timeout = msecs_to_jiffies(4000);
+       DEFINE_WAIT(wait);
+       struct var_t *jiffy_delta;
+       struct var_t *delay_time;
+       int jiffy_delta_val;
+       int delay_time_val;
+
+       jiffy_delta = spk_get_var(JIFFY);
+       delay_time = spk_get_var(DELAY);
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       jiffy_delta_val = jiffy_delta->u.n.value;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       jiff_max = jiffies + jiffy_delta_val;
+
+       while (!kthread_should_stop()) {
+               /* if no ctl-a in 4, send data anyway */
+               spin_lock_irqsave(&flush_lock, flags);
+               while (is_flushing && timeout) {
+                       prepare_to_wait(&flush, &wait, TASK_INTERRUPTIBLE);
+                       spin_unlock_irqrestore(&flush_lock, flags);
+                       timeout = schedule_timeout(timeout);
+                       spin_lock_irqsave(&flush_lock, flags);
+               }
+               finish_wait(&flush, &wait);
+               is_flushing = 0;
+               spin_unlock_irqrestore(&flush_lock, flags);
+
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               if (speakup_info.flushing) {
+                       speakup_info.flushing = 0;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       synth->flush(synth);
+                       continue;
+               }
+               synth_buffer_skip_nonlatin1();
+               if (synth_buffer_empty()) {
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       break;
+               }
+               ch = synth_buffer_peek();
+               set_current_state(TASK_INTERRUPTIBLE);
+               delay_time_val = delay_time->u.n.value;
+               synth_full_val = synth_full();
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (ch == '\n')
+                       ch = 0x0D;
+               if (synth_full_val || !synth->io_ops->synth_out(synth, ch)) {
+                       schedule_timeout(msecs_to_jiffies(delay_time_val));
+                       continue;
+               }
+               set_current_state(TASK_RUNNING);
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               synth_buffer_getc();
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (ch == '[') {
+                       in_escape = 1;
+               } else if (ch == ']') {
+                       in_escape = 0;
+               } else if (ch <= SPACE) {
+                       if (!in_escape && strchr(",.!?;:", last))
+                               synth->io_ops->synth_out(synth, PROCSPEECH);
+                       if (time_after_eq(jiffies, jiff_max)) {
+                               if (!in_escape)
+                                       synth->io_ops->synth_out(synth,
+                                                                PROCSPEECH);
+                               spin_lock_irqsave(&speakup_info.spinlock,
+                                                 flags);
+                               jiffy_delta_val = jiffy_delta->u.n.value;
+                               delay_time_val = delay_time->u.n.value;
+                               spin_unlock_irqrestore(&speakup_info.spinlock,
+                                                      flags);
+                               schedule_timeout(msecs_to_jiffies
+                                                (delay_time_val));
+                               jiff_max = jiffies + jiffy_delta_val;
+                       }
+               }
+               last = ch;
+       }
+       if (!in_escape)
+               synth->io_ops->synth_out(synth, PROCSPEECH);
+}
+
+static void synth_flush(struct spk_synth *synth)
+{
+       if (in_escape)
+               /* if in command output ']' so we don't get an error */
+               synth->io_ops->synth_out(synth, ']');
+       in_escape = 0;
+       is_flushing = 1;
+       synth->io_ops->flush_buffer();
+       synth->io_ops->synth_out(synth, SYNTH_CLEAR);
+}
+
+module_param_named(ser, synth_dectlk.ser, int, 0444);
+module_param_named(dev, synth_dectlk.dev_name, charp, 0444);
+module_param_named(start, synth_dectlk.startup, short, 0444);
+
+MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
+MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_dectlk);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for DECtalk Express synthesizers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_dtlk.c b/drivers/accessibility/speakup/speakup_dtlk.c
new file mode 100644 (file)
index 0000000..dbebed0
--- /dev/null
@@ -0,0 +1,390 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * specificly written as a driver for the speakup screenreview
+ * package it's not a general device driver.
+ * This driver is for the RC Systems DoubleTalk PC internal synthesizer.
+ */
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+
+#include "spk_priv.h"
+#include "serialio.h"
+#include "speakup_dtlk.h" /* local header file for DoubleTalk values */
+#include "speakup.h"
+
+#define DRV_VERSION "2.10"
+#define PROCSPEECH 0x00
+
+static int synth_probe(struct spk_synth *synth);
+static void dtlk_release(void);
+static const char *synth_immediate(struct spk_synth *synth, const char *buf);
+static void do_catch_up(struct spk_synth *synth);
+static void synth_flush(struct spk_synth *synth);
+
+static int synth_lpc;
+static int port_forced;
+static unsigned int synth_portlist[] = {
+                0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0
+};
+
+static u_char synth_status;
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"\x01+35p" } },
+       { CAPS_STOP, .u.s = {"\x01-35p" } },
+       { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL } },
+       { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL } },
+       { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
+       { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
+       { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL } },
+       { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
+       { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/dtlk.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute freq_attribute =
+       __ATTR(freq, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute punct_attribute =
+       __ATTR(punct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute tone_attribute =
+       __ATTR(tone, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute voice_attribute =
+       __ATTR(voice, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &freq_attribute.attr,
+       &pitch_attribute.attr,
+       &punct_attribute.attr,
+       &rate_attribute.attr,
+       &tone_attribute.attr,
+       &voice_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_dtlk = {
+       .name = "dtlk",
+       .version = DRV_VERSION,
+       .long_name = "DoubleTalk PC",
+       .init = "\x01@\x01\x31y",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 30,
+       .jiffies = 50,
+       .full = 1000,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_serial_io_ops,
+       .probe = synth_probe,
+       .release = dtlk_release,
+       .synth_immediate = synth_immediate,
+       .catch_up = do_catch_up,
+       .flush = synth_flush,
+       .is_alive = spk_synth_is_alive_nop,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = spk_synth_get_index,
+       .indexing = {
+               .command = "\x01%di",
+               .lowindex = 1,
+               .highindex = 5,
+               .currindex = 1,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "dtlk",
+       },
+};
+
+static inline bool synth_readable(void)
+{
+       synth_status = inb_p(speakup_info.port_tts + UART_RX);
+       return (synth_status & TTS_READABLE) != 0;
+}
+
+static inline bool synth_writable(void)
+{
+       synth_status = inb_p(speakup_info.port_tts + UART_RX);
+       return (synth_status & TTS_WRITABLE) != 0;
+}
+
+static inline bool synth_full(void)
+{
+       synth_status = inb_p(speakup_info.port_tts + UART_RX);
+       return (synth_status & TTS_ALMOST_FULL) != 0;
+}
+
+static void spk_out(const char ch)
+{
+       int timeout = SPK_XMITR_TIMEOUT;
+
+       while (!synth_writable()) {
+               if (!--timeout)
+                       break;
+               udelay(1);
+       }
+       outb_p(ch, speakup_info.port_tts);
+       timeout = SPK_XMITR_TIMEOUT;
+       while (synth_writable()) {
+               if (!--timeout)
+                       break;
+               udelay(1);
+       }
+}
+
+static void do_catch_up(struct spk_synth *synth)
+{
+       u_char ch;
+       unsigned long flags;
+       unsigned long jiff_max;
+       struct var_t *jiffy_delta;
+       struct var_t *delay_time;
+       int jiffy_delta_val;
+       int delay_time_val;
+
+       jiffy_delta = spk_get_var(JIFFY);
+       delay_time = spk_get_var(DELAY);
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       jiffy_delta_val = jiffy_delta->u.n.value;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       jiff_max = jiffies + jiffy_delta_val;
+       while (!kthread_should_stop()) {
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               if (speakup_info.flushing) {
+                       speakup_info.flushing = 0;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       synth->flush(synth);
+                       continue;
+               }
+               synth_buffer_skip_nonlatin1();
+               if (synth_buffer_empty()) {
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       break;
+               }
+               set_current_state(TASK_INTERRUPTIBLE);
+               delay_time_val = delay_time->u.n.value;
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (synth_full()) {
+                       schedule_timeout(msecs_to_jiffies(delay_time_val));
+                       continue;
+               }
+               set_current_state(TASK_RUNNING);
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               ch = synth_buffer_getc();
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (ch == '\n')
+                       ch = PROCSPEECH;
+               spk_out(ch);
+               if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
+                       spk_out(PROCSPEECH);
+                       spin_lock_irqsave(&speakup_info.spinlock, flags);
+                       delay_time_val = delay_time->u.n.value;
+                       jiffy_delta_val = jiffy_delta->u.n.value;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       schedule_timeout(msecs_to_jiffies(delay_time_val));
+                       jiff_max = jiffies + jiffy_delta_val;
+               }
+       }
+       spk_out(PROCSPEECH);
+}
+
+static const char *synth_immediate(struct spk_synth *synth, const char *buf)
+{
+       u_char ch;
+
+       while ((ch = (u_char)*buf)) {
+               if (synth_full())
+                       return buf;
+               if (ch == '\n')
+                       ch = PROCSPEECH;
+               spk_out(ch);
+               buf++;
+       }
+       return NULL;
+}
+
+static void synth_flush(struct spk_synth *synth)
+{
+       outb_p(SYNTH_CLEAR, speakup_info.port_tts);
+       while (synth_writable())
+               cpu_relax();
+}
+
+static char synth_read_tts(void)
+{
+       u_char ch;
+
+       while (!synth_readable())
+               cpu_relax();
+       ch = synth_status & 0x7f;
+       outb_p(ch, speakup_info.port_tts);
+       while (synth_readable())
+               cpu_relax();
+       return (char)ch;
+}
+
+/* interrogate the DoubleTalk PC and return its settings */
+static struct synth_settings *synth_interrogate(struct spk_synth *synth)
+{
+       u_char *t;
+       static char buf[sizeof(struct synth_settings) + 1];
+       int total, i;
+       static struct synth_settings status;
+
+       synth_immediate(synth, "\x18\x01?");
+       for (total = 0, i = 0; i < 50; i++) {
+               buf[total] = synth_read_tts();
+               if (total > 2 && buf[total] == 0x7f)
+                       break;
+               if (total < sizeof(struct synth_settings))
+                       total++;
+       }
+       t = buf;
+       /* serial number is little endian */
+       status.serial_number = t[0] + t[1] * 256;
+       t += 2;
+       for (i = 0; *t != '\r'; t++) {
+               status.rom_version[i] = *t;
+               if (i < sizeof(status.rom_version) - 1)
+                       i++;
+       }
+       status.rom_version[i] = 0;
+       t++;
+       status.mode = *t++;
+       status.punc_level = *t++;
+       status.formant_freq = *t++;
+       status.pitch = *t++;
+       status.speed = *t++;
+       status.volume = *t++;
+       status.tone = *t++;
+       status.expression = *t++;
+       status.ext_dict_loaded = *t++;
+       status.ext_dict_status = *t++;
+       status.free_ram = *t++;
+       status.articulation = *t++;
+       status.reverb = *t++;
+       status.eob = *t++;
+       return &status;
+}
+
+static int synth_probe(struct spk_synth *synth)
+{
+       unsigned int port_val = 0;
+       int i = 0;
+       struct synth_settings *sp;
+
+       pr_info("Probing for DoubleTalk.\n");
+       if (port_forced) {
+               speakup_info.port_tts = port_forced;
+               pr_info("probe forced to %x by kernel command line\n",
+                       speakup_info.port_tts);
+               if ((port_forced & 0xf) != 0xf)
+                       pr_info("warning: port base should probably end with f\n");
+               if (synth_request_region(speakup_info.port_tts - 1,
+                                        SYNTH_IO_EXTENT)) {
+                       pr_warn("sorry, port already reserved\n");
+                       return -EBUSY;
+               }
+               port_val = inw(speakup_info.port_tts - 1);
+               synth_lpc = speakup_info.port_tts - 1;
+       } else {
+               for (i = 0; synth_portlist[i]; i++) {
+                       if (synth_request_region(synth_portlist[i],
+                                                SYNTH_IO_EXTENT))
+                               continue;
+                       port_val = inw(synth_portlist[i]) & 0xfbff;
+                       if (port_val == 0x107f) {
+                               synth_lpc = synth_portlist[i];
+                               speakup_info.port_tts = synth_lpc + 1;
+                               break;
+                       }
+                       synth_release_region(synth_portlist[i],
+                                            SYNTH_IO_EXTENT);
+               }
+       }
+       port_val &= 0xfbff;
+       if (port_val != 0x107f) {
+               pr_info("DoubleTalk PC: not found\n");
+               if (synth_lpc)
+                       synth_release_region(synth_lpc, SYNTH_IO_EXTENT);
+               return -ENODEV;
+       }
+       while (inw_p(synth_lpc) != 0x147f)
+               cpu_relax(); /* wait until it's ready */
+       sp = synth_interrogate(synth);
+       pr_info("%s: %03x-%03x, ROM ver %s, s/n %u, driver: %s\n",
+               synth->long_name, synth_lpc, synth_lpc + SYNTH_IO_EXTENT - 1,
+               sp->rom_version, sp->serial_number, synth->version);
+       synth->alive = 1;
+       return 0;
+}
+
+static void dtlk_release(void)
+{
+       spk_stop_serial_interrupt();
+       if (speakup_info.port_tts)
+               synth_release_region(speakup_info.port_tts - 1,
+                                    SYNTH_IO_EXTENT);
+       speakup_info.port_tts = 0;
+}
+
+module_param_hw_named(port, port_forced, int, ioport, 0444);
+module_param_named(start, synth_dtlk.startup, short, 0444);
+
+MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_dtlk);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for DoubleTalk PC synthesizers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_dtlk.h b/drivers/accessibility/speakup/speakup_dtlk.h
new file mode 100644 (file)
index 0000000..9c378b5
--- /dev/null
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* speakup_dtlk.h - header file for speakups DoubleTalk driver. */
+
+#define SYNTH_IO_EXTENT        0x02
+#define SYNTH_CLEAR    0x18            /* stops speech */
+       /* TTS Port Status Flags */
+#define TTS_READABLE   0x80    /* mask for bit which is nonzero if a
+                                * byte can be read from the TTS port
+                                */
+#define TTS_SPEAKING   0x40    /* mask for SYNC bit, which is nonzero
+                                * while DoubleTalk is producing
+                                * output with TTS, PCM or CVSD
+                                * synthesizers or tone generators
+                                * (that is, all but LPC)
+                                */
+#define TTS_SPEAKING2  0x20    /* mask for SYNC2 bit,
+                                * which falls to zero up to 0.4 sec
+                                * before speech stops
+                                */
+#define TTS_WRITABLE   0x10    /* mask for RDY bit, which when set to
+                                * 1, indicates the TTS port is ready
+                                * to accept a byte of data.  The RDY
+                                * bit goes zero 2-3 usec after
+                                * writing, and goes 1 again 180-190
+                                * usec later.
+                                */
+#define TTS_ALMOST_FULL        0x08    /* mask for AF bit: When set to 1,
+                                * indicates that less than 300 bytes
+                                * are available in the TTS input
+                                * buffer. AF is always 0 in the PCM,
+                                * TGN and CVSD modes.
+                                */
+#define TTS_ALMOST_EMPTY 0x04  /* mask for AE bit: When set to 1,
+                                * indicates that less than 300 bytes
+                                * are remaining in DoubleTalk's input
+                                * (TTS or PCM) buffer. AE is always 1
+                                * in the TGN and CVSD modes.
+                                */
+
+                               /* data returned by Interrogate command */
+struct synth_settings {
+       u_short serial_number;  /* 0-7Fh:0-7Fh */
+       u_char rom_version[24]; /* null terminated string */
+       u_char mode;            /* 0=Character; 1=Phoneme; 2=Text */
+       u_char punc_level;      /* nB; 0-7 */
+       u_char formant_freq;    /* nF; 0-9 */
+       u_char pitch;           /* nP; 0-99 */
+       u_char speed;           /* nS; 0-9 */
+       u_char volume;          /* nV; 0-9 */
+       u_char tone;            /* nX; 0-2 */
+       u_char expression;      /* nE; 0-9 */
+       u_char ext_dict_loaded; /* 1=exception dictionary loaded */
+       u_char ext_dict_status; /* 1=exception dictionary enabled */
+       u_char free_ram;        /* # pages (truncated) remaining for
+                                * text buffer
+                                */
+       u_char articulation;    /* nA; 0-9 */
+       u_char reverb;          /* nR; 0-9 */
+       u_char eob;             /* 7Fh value indicating end of
+                                * parameter block
+                                */
+       u_char has_indexing;    /* nonzero if indexing is implemented */
+};
diff --git a/drivers/accessibility/speakup/speakup_dummy.c b/drivers/accessibility/speakup/speakup_dummy.c
new file mode 100644 (file)
index 0000000..e393438
--- /dev/null
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ * eventually modified by Samuel Thibault <samuel.thibault@ens-lyon.org>
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ * Copyright (C) 2007 Samuel Thibault.
+ *
+ * specificly written as a driver for the speakup screenreview
+ * s not a general device driver.
+ */
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define PROCSPEECH '\n'
+#define DRV_VERSION "2.11"
+#define SYNTH_CLEAR '!'
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"CAPS_START\n" } },
+       { CAPS_STOP, .u.s = {"CAPS_STOP\n" } },
+       { PAUSE, .u.s = {"PAUSE\n"} },
+       { RATE, .u.n = {"RATE %d\n", 8, 1, 16, 0, 0, NULL } },
+       { PITCH, .u.n = {"PITCH %d\n", 8, 0, 16, 0, 0, NULL } },
+       { INFLECTION, .u.n = {"INFLECTION %d\n", 8, 0, 16, 0, 0, NULL } },
+       { VOL, .u.n = {"VOL %d\n", 8, 0, 16, 0, 0, NULL } },
+       { TONE, .u.n = {"TONE %d\n", 8, 0, 16, 0, 0, NULL } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/dummy.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute inflection_attribute =
+       __ATTR(inflection, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute tone_attribute =
+       __ATTR(tone, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &inflection_attribute.attr,
+       &rate_attribute.attr,
+       &tone_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_dummy = {
+       .name = "dummy",
+       .version = DRV_VERSION,
+       .long_name = "Dummy",
+       .init = "Speakup\n",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 40000,
+       .dev_name = SYNTH_DEFAULT_DEV,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_ttyio_ops,
+       .probe = spk_ttyio_synth_probe,
+       .release = spk_ttyio_release,
+       .synth_immediate = spk_ttyio_synth_immediate,
+       .catch_up = spk_do_catch_up_unicode,
+       .flush = spk_synth_flush,
+       .is_alive = spk_synth_is_alive_restart,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = NULL,
+       .indexing = {
+               .command = NULL,
+               .lowindex = 0,
+               .highindex = 0,
+               .currindex = 0,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "dummy",
+       },
+};
+
+module_param_named(ser, synth_dummy.ser, int, 0444);
+module_param_named(dev, synth_dummy.dev_name, charp, 0444);
+module_param_named(start, synth_dummy.startup, short, 0444);
+
+MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
+MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_dummy);
+
+MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
+MODULE_DESCRIPTION("Speakup support for text console");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_keypc.c b/drivers/accessibility/speakup/speakup_keypc.c
new file mode 100644 (file)
index 0000000..414827e
--- /dev/null
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * written by David Borowski
+ *
+ * Copyright (C) 2003 David Borowski.
+ *
+ * specificly written as a driver for the speakup screenreview
+ * package it's not a general device driver.
+ * This driver is for the Keynote Gold internal synthesizer.
+ */
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+#include <linux/serial_reg.h>
+
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define DRV_VERSION "2.10"
+#define SYNTH_IO_EXTENT        0x04
+#define SWAIT udelay(70)
+#define PROCSPEECH 0x1f
+#define SYNTH_CLEAR 0x03
+
+static int synth_probe(struct spk_synth *synth);
+static void keynote_release(void);
+static const char *synth_immediate(struct spk_synth *synth, const char *buf);
+static void do_catch_up(struct spk_synth *synth);
+static void synth_flush(struct spk_synth *synth);
+
+static int synth_port;
+static int port_forced;
+static unsigned int synth_portlist[] = { 0x2a8, 0 };
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"[f130]" } },
+       { CAPS_STOP, .u.s = {"[f90]" } },
+       { RATE, .u.n = {"\04%c ", 8, 0, 10, 81, -8, NULL } },
+       { PITCH, .u.n = {"[f%d]", 5, 0, 9, 40, 10, NULL } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/keypc.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &rate_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_keypc = {
+       .name = "keypc",
+       .version = DRV_VERSION,
+       .long_name = "Keynote PC",
+       .init = "[t][n7,1][n8,0]",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 1000,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_serial_io_ops,
+       .probe = synth_probe,
+       .release = keynote_release,
+       .synth_immediate = synth_immediate,
+       .catch_up = do_catch_up,
+       .flush = synth_flush,
+       .is_alive = spk_synth_is_alive_nop,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = NULL,
+       .indexing = {
+               .command = NULL,
+               .lowindex = 0,
+               .highindex = 0,
+               .currindex = 0,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "keypc",
+       },
+};
+
+static inline bool synth_writable(void)
+{
+       return (inb_p(synth_port + UART_RX) & 0x10) != 0;
+}
+
+static inline bool synth_full(void)
+{
+       return (inb_p(synth_port + UART_RX) & 0x80) == 0;
+}
+
+static char *oops(void)
+{
+       int s1, s2, s3, s4;
+
+       s1 = inb_p(synth_port);
+       s2 = inb_p(synth_port + 1);
+       s3 = inb_p(synth_port + 2);
+       s4 = inb_p(synth_port + 3);
+       pr_warn("synth timeout %d %d %d %d\n", s1, s2, s3, s4);
+       return NULL;
+}
+
+static const char *synth_immediate(struct spk_synth *synth, const char *buf)
+{
+       u_char ch;
+       int timeout;
+
+       while ((ch = *buf)) {
+               if (ch == '\n')
+                       ch = PROCSPEECH;
+               if (synth_full())
+                       return buf;
+               timeout = 1000;
+               while (synth_writable())
+                       if (--timeout <= 0)
+                               return oops();
+               outb_p(ch, synth_port);
+               udelay(70);
+               buf++;
+       }
+       return NULL;
+}
+
+static void do_catch_up(struct spk_synth *synth)
+{
+       u_char ch;
+       int timeout;
+       unsigned long flags;
+       unsigned long jiff_max;
+       struct var_t *jiffy_delta;
+       struct var_t *delay_time;
+       struct var_t *full_time;
+       int delay_time_val;
+       int full_time_val;
+       int jiffy_delta_val;
+
+       jiffy_delta = spk_get_var(JIFFY);
+       delay_time = spk_get_var(DELAY);
+       full_time = spk_get_var(FULL);
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       jiffy_delta_val = jiffy_delta->u.n.value;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+
+       jiff_max = jiffies + jiffy_delta_val;
+       while (!kthread_should_stop()) {
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               if (speakup_info.flushing) {
+                       speakup_info.flushing = 0;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       synth->flush(synth);
+                       continue;
+               }
+               synth_buffer_skip_nonlatin1();
+               if (synth_buffer_empty()) {
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       break;
+               }
+               set_current_state(TASK_INTERRUPTIBLE);
+               full_time_val = full_time->u.n.value;
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (synth_full()) {
+                       schedule_timeout(msecs_to_jiffies(full_time_val));
+                       continue;
+               }
+               set_current_state(TASK_RUNNING);
+               timeout = 1000;
+               while (synth_writable())
+                       if (--timeout <= 0)
+                               break;
+               if (timeout <= 0) {
+                       oops();
+                       break;
+               }
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               ch = synth_buffer_getc();
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (ch == '\n')
+                       ch = PROCSPEECH;
+               outb_p(ch, synth_port);
+               SWAIT;
+               if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
+                       timeout = 1000;
+                       while (synth_writable())
+                               if (--timeout <= 0)
+                                       break;
+                       if (timeout <= 0) {
+                               oops();
+                               break;
+                       }
+                       outb_p(PROCSPEECH, synth_port);
+                       spin_lock_irqsave(&speakup_info.spinlock, flags);
+                       jiffy_delta_val = jiffy_delta->u.n.value;
+                       delay_time_val = delay_time->u.n.value;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       schedule_timeout(msecs_to_jiffies(delay_time_val));
+                       jiff_max = jiffies + jiffy_delta_val;
+               }
+       }
+       timeout = 1000;
+       while (synth_writable())
+               if (--timeout <= 0)
+                       break;
+       if (timeout <= 0)
+               oops();
+       else
+               outb_p(PROCSPEECH, synth_port);
+}
+
+static void synth_flush(struct spk_synth *synth)
+{
+       outb_p(SYNTH_CLEAR, synth_port);
+}
+
+static int synth_probe(struct spk_synth *synth)
+{
+       unsigned int port_val = 0;
+       int i = 0;
+
+       pr_info("Probing for %s.\n", synth->long_name);
+       if (port_forced) {
+               synth_port = port_forced;
+               pr_info("probe forced to %x by kernel command line\n",
+                       synth_port);
+               if (synth_request_region(synth_port - 1, SYNTH_IO_EXTENT)) {
+                       pr_warn("sorry, port already reserved\n");
+                       return -EBUSY;
+               }
+               port_val = inb(synth_port);
+       } else {
+               for (i = 0; synth_portlist[i]; i++) {
+                       if (synth_request_region(synth_portlist[i],
+                                                SYNTH_IO_EXTENT)) {
+                               pr_warn
+                                   ("request_region: failed with 0x%x, %d\n",
+                                    synth_portlist[i], SYNTH_IO_EXTENT);
+                               continue;
+                       }
+                       port_val = inb(synth_portlist[i]);
+                       if (port_val == 0x80) {
+                               synth_port = synth_portlist[i];
+                               break;
+                       }
+               }
+       }
+       if (port_val != 0x80) {
+               pr_info("%s: not found\n", synth->long_name);
+               synth_release_region(synth_port, SYNTH_IO_EXTENT);
+               synth_port = 0;
+               return -ENODEV;
+       }
+       pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name,
+               synth_port, synth_port + SYNTH_IO_EXTENT - 1,
+               synth->version);
+       synth->alive = 1;
+       return 0;
+}
+
+static void keynote_release(void)
+{
+       spk_stop_serial_interrupt();
+       if (synth_port)
+               synth_release_region(synth_port, SYNTH_IO_EXTENT);
+       synth_port = 0;
+}
+
+module_param_hw_named(port, port_forced, int, ioport, 0444);
+module_param_named(start, synth_keypc.startup, short, 0444);
+
+MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_keypc);
+
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for Keynote Gold PC synthesizers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_ltlk.c b/drivers/accessibility/speakup/speakup_ltlk.c
new file mode 100644 (file)
index 0000000..3c59519
--- /dev/null
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * specificly written as a driver for the speakup screenreview
+ * s not a general device driver.
+ */
+#include "speakup.h"
+#include "spk_priv.h"
+#include "speakup_dtlk.h" /* local header file for LiteTalk values */
+
+#define DRV_VERSION "2.11"
+#define PROCSPEECH 0x0d
+
+static int synth_probe(struct spk_synth *synth);
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"\x01+35p" } },
+       { CAPS_STOP, .u.s = {"\x01-35p" } },
+       { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL } },
+       { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL } },
+       { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
+       { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
+       { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL } },
+       { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
+       { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/*
+ * These attributes will appear in /sys/accessibility/speakup/ltlk.
+ */
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute freq_attribute =
+       __ATTR(freq, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute punct_attribute =
+       __ATTR(punct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute tone_attribute =
+       __ATTR(tone, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute voice_attribute =
+       __ATTR(voice, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &freq_attribute.attr,
+       &pitch_attribute.attr,
+       &punct_attribute.attr,
+       &rate_attribute.attr,
+       &tone_attribute.attr,
+       &voice_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_ltlk = {
+       .name = "ltlk",
+       .version = DRV_VERSION,
+       .long_name = "LiteTalk",
+       .init = "\01@\x01\x31y\n\0",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 40000,
+       .dev_name = SYNTH_DEFAULT_DEV,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_ttyio_ops,
+       .probe = synth_probe,
+       .release = spk_ttyio_release,
+       .synth_immediate = spk_ttyio_synth_immediate,
+       .catch_up = spk_do_catch_up,
+       .flush = spk_synth_flush,
+       .is_alive = spk_synth_is_alive_restart,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = spk_synth_get_index,
+       .indexing = {
+               .command = "\x01%di",
+               .lowindex = 1,
+               .highindex = 5,
+               .currindex = 1,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "ltlk",
+       },
+};
+
+/* interrogate the LiteTalk and print its settings */
+static void synth_interrogate(struct spk_synth *synth)
+{
+       unsigned char *t, i;
+       unsigned char buf[50], rom_v[20];
+
+       synth->synth_immediate(synth, "\x18\x01?");
+       for (i = 0; i < 50; i++) {
+               buf[i] = synth->io_ops->synth_in();
+               if (i > 2 && buf[i] == 0x7f)
+                       break;
+       }
+       t = buf + 2;
+       for (i = 0; *t != '\r'; t++) {
+               rom_v[i] = *t;
+               if (++i >= 19)
+                       break;
+       }
+       rom_v[i] = 0;
+       pr_info("%s: ROM version: %s\n", synth->long_name, rom_v);
+}
+
+static int synth_probe(struct spk_synth *synth)
+{
+       int failed = 0;
+
+       failed = spk_ttyio_synth_probe(synth);
+       if (failed == 0)
+               synth_interrogate(synth);
+       synth->alive = !failed;
+       return failed;
+}
+
+module_param_named(ser, synth_ltlk.ser, int, 0444);
+module_param_named(dev, synth_ltlk.dev_name, charp, 0444);
+module_param_named(start, synth_ltlk.startup, short, 0444);
+
+MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
+MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_ltlk);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for DoubleTalk LT/LiteTalk synthesizers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_soft.c b/drivers/accessibility/speakup/speakup_soft.c
new file mode 100644 (file)
index 0000000..9a70295
--- /dev/null
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* speakup_soft.c - speakup driver to register and make available
+ * a user space device for software synthesizers.  written by: Kirk
+ * Reiser <kirk@braille.uwo.ca>
+ *
+ * Copyright (C) 2003  Kirk Reiser.
+ *
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+ */
+
+#include <linux/unistd.h>
+#include <linux/miscdevice.h>  /* for misc_register, and MISC_DYNAMIC_MINOR */
+#include <linux/poll.h>                /* for poll_wait() */
+
+/* schedule(), signal_pending(), TASK_INTERRUPTIBLE */
+#include <linux/sched/signal.h>
+
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define DRV_VERSION "2.6"
+#define PROCSPEECH 0x0d
+#define CLEAR_SYNTH 0x18
+
+static int softsynth_probe(struct spk_synth *synth);
+static void softsynth_release(void);
+static int softsynth_is_alive(struct spk_synth *synth);
+static unsigned char get_index(struct spk_synth *synth);
+
+static struct miscdevice synth_device, synthu_device;
+static int init_pos;
+static int misc_registered;
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"\x01+3p" } },
+       { CAPS_STOP, .u.s = {"\x01-3p" } },
+       { PAUSE, .u.n = {"\x01P" } },
+       { RATE, .u.n = {"\x01%ds", 2, 0, 9, 0, 0, NULL } },
+       { PITCH, .u.n = {"\x01%dp", 5, 0, 9, 0, 0, NULL } },
+       { INFLECTION, .u.n = {"\x01%dr", 5, 0, 9, 0, 0, NULL } },
+       { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
+       { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
+       { PUNCT, .u.n = {"\x01%db", 0, 0, 2, 0, 0, NULL } },
+       { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
+       { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/* These attributes will appear in /sys/accessibility/speakup/soft. */
+
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute freq_attribute =
+       __ATTR(freq, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute inflection_attribute =
+       __ATTR(inflection, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute punct_attribute =
+       __ATTR(punct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute tone_attribute =
+       __ATTR(tone, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute voice_attribute =
+       __ATTR(voice, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+/*
+ * We should uncomment the following definition, when we agree on a
+ * method of passing a language designation to the software synthesizer.
+ * static struct kobj_attribute lang_attribute =
+ *     __ATTR(lang, 0644, spk_var_show, spk_var_store);
+ */
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &freq_attribute.attr,
+/*     &lang_attribute.attr, */
+       &pitch_attribute.attr,
+       &inflection_attribute.attr,
+       &punct_attribute.attr,
+       &rate_attribute.attr,
+       &tone_attribute.attr,
+       &voice_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_soft = {
+       .name = "soft",
+       .version = DRV_VERSION,
+       .long_name = "software synth",
+       .init = "\01@\x01\x31y\n",
+       .procspeech = PROCSPEECH,
+       .delay = 0,
+       .trigger = 0,
+       .jiffies = 0,
+       .full = 0,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = NULL,
+       .probe = softsynth_probe,
+       .release = softsynth_release,
+       .synth_immediate = NULL,
+       .catch_up = NULL,
+       .flush = NULL,
+       .is_alive = softsynth_is_alive,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = get_index,
+       .indexing = {
+               .command = "\x01%di",
+               .lowindex = 1,
+               .highindex = 5,
+               .currindex = 1,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "soft",
+       },
+};
+
+static char *get_initstring(void)
+{
+       static char buf[40];
+       char *cp;
+       struct var_t *var;
+
+       memset(buf, 0, sizeof(buf));
+       cp = buf;
+       var = synth_soft.vars;
+       while (var->var_id != MAXVARS) {
+               if (var->var_id != CAPS_START && var->var_id != CAPS_STOP &&
+                   var->var_id != PAUSE && var->var_id != DIRECT)
+                       cp = cp + sprintf(cp, var->u.n.synth_fmt,
+                                         var->u.n.value);
+               var++;
+       }
+       cp = cp + sprintf(cp, "\n");
+       return buf;
+}
+
+static int softsynth_open(struct inode *inode, struct file *fp)
+{
+       unsigned long flags;
+       /*if ((fp->f_flags & O_ACCMODE) != O_RDONLY) */
+       /*      return -EPERM; */
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       if (synth_soft.alive) {
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               return -EBUSY;
+       }
+       synth_soft.alive = 1;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return 0;
+}
+
+static int softsynth_close(struct inode *inode, struct file *fp)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       synth_soft.alive = 0;
+       init_pos = 0;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       /* Make sure we let applications go before leaving */
+       speakup_start_ttys();
+       return 0;
+}
+
+static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count,
+                              loff_t *pos, int unicode)
+{
+       int chars_sent = 0;
+       char __user *cp;
+       char *init;
+       size_t bytes_per_ch = unicode ? 3 : 1;
+       u16 ch;
+       int empty;
+       unsigned long flags;
+       DEFINE_WAIT(wait);
+
+       if (count < bytes_per_ch)
+               return -EINVAL;
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       synth_soft.alive = 1;
+       while (1) {
+               prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE);
+               if (synth_current() == &synth_soft) {
+                       if (!unicode)
+                               synth_buffer_skip_nonlatin1();
+                       if (!synth_buffer_empty() || speakup_info.flushing)
+                               break;
+               }
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (fp->f_flags & O_NONBLOCK) {
+                       finish_wait(&speakup_event, &wait);
+                       return -EAGAIN;
+               }
+               if (signal_pending(current)) {
+                       finish_wait(&speakup_event, &wait);
+                       return -ERESTARTSYS;
+               }
+               schedule();
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+       }
+       finish_wait(&speakup_event, &wait);
+
+       cp = buf;
+       init = get_initstring();
+
+       /* Keep 3 bytes available for a 16bit UTF-8-encoded character */
+       while (chars_sent <= count - bytes_per_ch) {
+               if (synth_current() != &synth_soft)
+                       break;
+               if (speakup_info.flushing) {
+                       speakup_info.flushing = 0;
+                       ch = '\x18';
+               } else if (init[init_pos]) {
+                       ch = init[init_pos++];
+               } else {
+                       if (!unicode)
+                               synth_buffer_skip_nonlatin1();
+                       if (synth_buffer_empty())
+                               break;
+                       ch = synth_buffer_getc();
+               }
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+
+               if ((!unicode && ch < 0x100) || (unicode && ch < 0x80)) {
+                       u_char c = ch;
+
+                       if (copy_to_user(cp, &c, 1))
+                               return -EFAULT;
+
+                       chars_sent++;
+                       cp++;
+               } else if (unicode && ch < 0x800) {
+                       u_char s[2] = {
+                               0xc0 | (ch >> 6),
+                               0x80 | (ch & 0x3f)
+                       };
+
+                       if (copy_to_user(cp, s, sizeof(s)))
+                               return -EFAULT;
+
+                       chars_sent += sizeof(s);
+                       cp += sizeof(s);
+               } else if (unicode) {
+                       u_char s[3] = {
+                               0xe0 | (ch >> 12),
+                               0x80 | ((ch >> 6) & 0x3f),
+                               0x80 | (ch & 0x3f)
+                       };
+
+                       if (copy_to_user(cp, s, sizeof(s)))
+                               return -EFAULT;
+
+                       chars_sent += sizeof(s);
+                       cp += sizeof(s);
+               }
+
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+       }
+       *pos += chars_sent;
+       empty = synth_buffer_empty();
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       if (empty) {
+               speakup_start_ttys();
+               *pos = 0;
+       }
+       return chars_sent;
+}
+
+static ssize_t softsynth_read(struct file *fp, char __user *buf, size_t count,
+                             loff_t *pos)
+{
+       return softsynthx_read(fp, buf, count, pos, 0);
+}
+
+static ssize_t softsynthu_read(struct file *fp, char __user *buf, size_t count,
+                              loff_t *pos)
+{
+       return softsynthx_read(fp, buf, count, pos, 1);
+}
+
+static int last_index;
+
+static ssize_t softsynth_write(struct file *fp, const char __user *buf,
+                              size_t count, loff_t *pos)
+{
+       unsigned long supplied_index = 0;
+       int converted;
+
+       converted = kstrtoul_from_user(buf, count, 0, &supplied_index);
+
+       if (converted < 0)
+               return converted;
+
+       last_index = supplied_index;
+       return count;
+}
+
+static __poll_t softsynth_poll(struct file *fp, struct poll_table_struct *wait)
+{
+       unsigned long flags;
+       __poll_t ret = 0;
+
+       poll_wait(fp, &speakup_event, wait);
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       if (synth_current() == &synth_soft &&
+           (!synth_buffer_empty() || speakup_info.flushing))
+               ret = EPOLLIN | EPOLLRDNORM;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       return ret;
+}
+
+static unsigned char get_index(struct spk_synth *synth)
+{
+       int rv;
+
+       rv = last_index;
+       last_index = 0;
+       return rv;
+}
+
+static const struct file_operations softsynth_fops = {
+       .owner = THIS_MODULE,
+       .poll = softsynth_poll,
+       .read = softsynth_read,
+       .write = softsynth_write,
+       .open = softsynth_open,
+       .release = softsynth_close,
+};
+
+static const struct file_operations softsynthu_fops = {
+       .owner = THIS_MODULE,
+       .poll = softsynth_poll,
+       .read = softsynthu_read,
+       .write = softsynth_write,
+       .open = softsynth_open,
+       .release = softsynth_close,
+};
+
+static int softsynth_probe(struct spk_synth *synth)
+{
+       if (misc_registered != 0)
+               return 0;
+       memset(&synth_device, 0, sizeof(synth_device));
+       synth_device.minor = MISC_DYNAMIC_MINOR;
+       synth_device.name = "softsynth";
+       synth_device.fops = &softsynth_fops;
+       if (misc_register(&synth_device)) {
+               pr_warn("Couldn't initialize miscdevice /dev/softsynth.\n");
+               return -ENODEV;
+       }
+
+       memset(&synthu_device, 0, sizeof(synthu_device));
+       synthu_device.minor = MISC_DYNAMIC_MINOR;
+       synthu_device.name = "softsynthu";
+       synthu_device.fops = &softsynthu_fops;
+       if (misc_register(&synthu_device)) {
+               pr_warn("Couldn't initialize miscdevice /dev/softsynthu.\n");
+               return -ENODEV;
+       }
+
+       misc_registered = 1;
+       pr_info("initialized device: /dev/softsynth, node (MAJOR 10, MINOR %d)\n",
+               synth_device.minor);
+       pr_info("initialized device: /dev/softsynthu, node (MAJOR 10, MINOR %d)\n",
+               synthu_device.minor);
+       return 0;
+}
+
+static void softsynth_release(void)
+{
+       misc_deregister(&synth_device);
+       misc_deregister(&synthu_device);
+       misc_registered = 0;
+       pr_info("unregistered /dev/softsynth\n");
+       pr_info("unregistered /dev/softsynthu\n");
+}
+
+static int softsynth_is_alive(struct spk_synth *synth)
+{
+       if (synth_soft.alive)
+               return 1;
+       return 0;
+}
+
+module_param_named(start, synth_soft.startup, short, 0444);
+
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_soft);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_DESCRIPTION("Speakup userspace software synthesizer support");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/accessibility/speakup/speakup_spkout.c b/drivers/accessibility/speakup/speakup_spkout.c
new file mode 100644 (file)
index 0000000..6e933bf
--- /dev/null
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * specificly written as a driver for the speakup screenreview
+ * s not a general device driver.
+ */
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define DRV_VERSION "2.11"
+#define SYNTH_CLEAR 0x18
+#define PROCSPEECH '\r'
+
+static void synth_flush(struct spk_synth *synth);
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"\x05P+" } },
+       { CAPS_STOP, .u.s = {"\x05P-" } },
+       { RATE, .u.n = {"\x05R%d", 7, 0, 9, 0, 0, NULL } },
+       { PITCH, .u.n = {"\x05P%d", 3, 0, 9, 0, 0, NULL } },
+       { VOL, .u.n = {"\x05V%d", 9, 0, 9, 0, 0, NULL } },
+       { TONE, .u.n = {"\x05T%c", 8, 0, 25, 65, 0, NULL } },
+       { PUNCT, .u.n = {"\x05M%c", 0, 0, 3, 0, 0, "nsma" } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/* These attributes will appear in /sys/accessibility/speakup/spkout. */
+
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute punct_attribute =
+       __ATTR(punct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute tone_attribute =
+       __ATTR(tone, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &punct_attribute.attr,
+       &rate_attribute.attr,
+       &tone_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_spkout = {
+       .name = "spkout",
+       .version = DRV_VERSION,
+       .long_name = "Speakout",
+       .init = "\005W1\005I2\005C3",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 40000,
+       .dev_name = SYNTH_DEFAULT_DEV,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_ttyio_ops,
+       .probe = spk_ttyio_synth_probe,
+       .release = spk_ttyio_release,
+       .synth_immediate = spk_ttyio_synth_immediate,
+       .catch_up = spk_do_catch_up,
+       .flush = synth_flush,
+       .is_alive = spk_synth_is_alive_restart,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = spk_synth_get_index,
+       .indexing = {
+               .command = "\x05[%c",
+               .lowindex = 1,
+               .highindex = 5,
+               .currindex = 1,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "spkout",
+       },
+};
+
+static void synth_flush(struct spk_synth *synth)
+{
+       synth->io_ops->flush_buffer();
+       synth->io_ops->send_xchar(SYNTH_CLEAR);
+}
+
+module_param_named(ser, synth_spkout.ser, int, 0444);
+module_param_named(dev, synth_spkout.dev_name, charp, 0444);
+module_param_named(start, synth_spkout.startup, short, 0444);
+
+MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
+MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_spkout);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for Speak Out synthesizers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakup_txprt.c b/drivers/accessibility/speakup/speakup_txprt.c
new file mode 100644 (file)
index 0000000..a7326f2
--- /dev/null
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+ * this version considerably modified by David Borowski, david575@rogers.com
+ *
+ * Copyright (C) 1998-99  Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ *
+ * specificly written as a driver for the speakup screenreview
+ * s not a general device driver.
+ */
+#include "spk_priv.h"
+#include "speakup.h"
+
+#define DRV_VERSION "2.11"
+#define SYNTH_CLEAR 0x18
+#define PROCSPEECH '\r' /* process speech char */
+
+static struct var_t vars[] = {
+       { CAPS_START, .u.s = {"\x05P8" } },
+       { CAPS_STOP, .u.s = {"\x05P5" } },
+       { RATE, .u.n = {"\x05R%d", 5, 0, 9, 0, 0, NULL } },
+       { PITCH, .u.n = {"\x05P%d", 5, 0, 9, 0, 0, NULL } },
+       { VOL, .u.n = {"\x05V%d", 5, 0, 9, 0, 0, NULL } },
+       { TONE, .u.n = {"\x05T%c", 12, 0, 25, 61, 0, NULL } },
+       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
+       V_LAST_VAR
+        };
+
+/* These attributes will appear in /sys/accessibility/speakup/txprt. */
+
+static struct kobj_attribute caps_start_attribute =
+       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute caps_stop_attribute =
+       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute pitch_attribute =
+       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute rate_attribute =
+       __ATTR(rate, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute tone_attribute =
+       __ATTR(tone, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute vol_attribute =
+       __ATTR(vol, 0644, spk_var_show, spk_var_store);
+
+static struct kobj_attribute delay_time_attribute =
+       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute direct_attribute =
+       __ATTR(direct, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute full_time_attribute =
+       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute jiffy_delta_attribute =
+       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
+static struct kobj_attribute trigger_time_attribute =
+       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
+
+/*
+ * Create a group of attributes so that we can create and destroy them all
+ * at once.
+ */
+static struct attribute *synth_attrs[] = {
+       &caps_start_attribute.attr,
+       &caps_stop_attribute.attr,
+       &pitch_attribute.attr,
+       &rate_attribute.attr,
+       &tone_attribute.attr,
+       &vol_attribute.attr,
+       &delay_time_attribute.attr,
+       &direct_attribute.attr,
+       &full_time_attribute.attr,
+       &jiffy_delta_attribute.attr,
+       &trigger_time_attribute.attr,
+       NULL,   /* need to NULL terminate the list of attributes */
+};
+
+static struct spk_synth synth_txprt = {
+       .name = "txprt",
+       .version = DRV_VERSION,
+       .long_name = "Transport",
+       .init = "\x05N1",
+       .procspeech = PROCSPEECH,
+       .clear = SYNTH_CLEAR,
+       .delay = 500,
+       .trigger = 50,
+       .jiffies = 50,
+       .full = 40000,
+       .dev_name = SYNTH_DEFAULT_DEV,
+       .startup = SYNTH_START,
+       .checkval = SYNTH_CHECK,
+       .vars = vars,
+       .io_ops = &spk_ttyio_ops,
+       .probe = spk_ttyio_synth_probe,
+       .release = spk_ttyio_release,
+       .synth_immediate = spk_ttyio_synth_immediate,
+       .catch_up = spk_do_catch_up,
+       .flush = spk_synth_flush,
+       .is_alive = spk_synth_is_alive_restart,
+       .synth_adjust = NULL,
+       .read_buff_add = NULL,
+       .get_index = NULL,
+       .indexing = {
+               .command = NULL,
+               .lowindex = 0,
+               .highindex = 0,
+               .currindex = 0,
+       },
+       .attributes = {
+               .attrs = synth_attrs,
+               .name = "txprt",
+       },
+};
+
+module_param_named(ser, synth_txprt.ser, int, 0444);
+module_param_named(dev, synth_txprt.dev_name, charp, 0444);
+module_param_named(start, synth_txprt.startup, short, 0444);
+
+MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
+MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
+MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
+
+module_spk_synth(synth_txprt);
+
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup support for Transport synthesizers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/accessibility/speakup/speakupmap.h b/drivers/accessibility/speakup/speakupmap.h
new file mode 100644 (file)
index 0000000..c60d733
--- /dev/null
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+       119, 62, 6,
+       0, 16, 20, 17, 32, 48, 0,
+       2, 0, 78, 0, 0, 0, 0,
+       3, 0, 79, 0, 0, 0, 0,
+       4, 0, 76, 0, 0, 0, 0,
+       5, 0, 77, 0, 0, 0, 0,
+       6, 0, 74, 0, 0, 0, 0,
+       7, 0, 75, 0, 0, 0, 0,
+       9, 0, 5, 46, 0, 0, 0,
+       10, 0, 4, 0, 0, 0, 0,
+       11, 0, 0, 1, 0, 0, 0,
+       12, 0, 27, 0, 33, 0, 0,
+       19, 0, 47, 0, 0, 0, 0,
+       21, 0, 29, 17, 0, 0, 0,
+       22, 0, 15, 0, 0, 0, 0,
+       23, 0, 14, 0, 0, 0, 28,
+       24, 0, 16, 0, 0, 0, 0,
+       25, 0, 30, 18, 0, 0, 0,
+       28, 0, 3, 26, 0, 0, 0,
+       35, 0, 31, 0, 0, 0, 0,
+       36, 0, 12, 0, 0, 0, 0,
+       37, 0, 11, 0, 0, 0, 22,
+       38, 0, 13, 0, 0, 0, 0,
+       39, 0, 32, 7, 0, 0, 0,
+       40, 0, 23, 0, 0, 0, 0,
+       44, 0, 44, 0, 0, 0, 0,
+       49, 0, 24, 0, 0, 0, 0,
+       50, 0, 9, 19, 6, 0, 0,
+       51, 0, 8, 0, 0, 0, 36,
+       52, 0, 10, 20, 0, 0, 0,
+       53, 0, 25, 0, 0, 0, 0,
+       55, 46, 1, 0, 0, 0, 0,
+       58, 128, 128, 0, 0, 0, 0,
+       59, 0, 45, 0, 0, 0, 0,
+       60, 0, 40, 0, 0, 0, 0,
+       61, 0, 41, 0, 0, 0, 0,
+       62, 0, 42, 0, 0, 0, 0,
+       63, 0, 34, 0, 0, 0, 0,
+       64, 0, 35, 0, 0, 0, 0,
+       65, 0, 37, 0, 0, 0, 0,
+       66, 0, 38, 0, 0, 0, 0,
+       67, 0, 66, 0, 39, 0, 0,
+       68, 0, 67, 0, 0, 0, 0,
+       71, 15, 19, 0, 0, 0, 0,
+       72, 14, 29, 0, 0, 28, 0,
+       73, 16, 17, 0, 0, 0, 0,
+       74, 27, 33, 0, 0, 0, 0,
+       75, 12, 31, 0, 0, 0, 0,
+       76, 11, 21, 0, 0, 22, 0,
+       77, 13, 32, 0, 0, 0, 0,
+       78, 23, 43, 0, 0, 0, 0,
+       79, 9, 20, 0, 0, 0, 0,
+       80, 8, 30, 0, 0, 36, 0,
+       81, 10, 18, 0, 0, 0, 0,
+       82, 128, 128, 0, 0, 0, 0,
+       83, 24, 25, 0, 0, 0, 0,
+       87, 0, 68, 0, 0, 0, 0,
+       88, 0, 69, 0, 0, 0, 0,
+       96, 3, 26, 0, 0, 0, 0,
+       98, 4, 5, 0, 0, 0, 0,
+       99, 2, 0, 0, 0, 0, 0,
+       104, 0, 6, 0, 0, 0, 0,
+       109, 0, 7, 0, 0, 0, 0,
+       125, 128, 128, 0, 0, 0, 0,
+       0, 119
diff --git a/drivers/accessibility/speakup/speakupmap.map b/drivers/accessibility/speakup/speakupmap.map
new file mode 100644 (file)
index 0000000..f10d44c
--- /dev/null
@@ -0,0 +1,93 @@
+spk key_f9 = punc_level_dec
+spk key_f10 = punc_level_inc
+spk key_f11 = reading_punc_dec
+spk key_f12 = reading_punc_inc
+spk key_1 = vol_dec
+spk key_2 = vol_inc
+spk key_3 = pitch_dec
+spk key_4 = pitch_inc
+spk key_5 = rate_dec
+spk key_6 = rate_inc
+key_kpasterisk = toggle_cursoring
+ctrl spk key_8 = toggle_cursoring
+spk key_kpasterisk = speakup_goto
+spk key_f1 = speakup_help
+spk key_f2 = set_win
+spk key_f3 = clear_win
+spk key_f4 = enable_win
+spk key_f5 = edit_some
+spk key_f6 = edit_most
+spk key_f7 = edit_delim
+spk key_f8 = edit_repeat
+shift spk key_f9 = edit_exnum
+ key_kp7 = say_prev_line
+spk key_kp7 = left_edge
+ key_kp8 = say_line
+double key_kp8 = say_line_indent
+spk key_kp8 = say_from_top
+ key_kp9 = say_next_line
+spk key_kp9 = top_edge
+ key_kpminus = speakup_parked
+spk key_kpminus = say_char_num
+ key_kp4 = say_prev_word
+spk key_kp4 = say_from_left
+ key_kp5 = say_word
+double key_kp5 = spell_word
+spk key_kp5 = spell_phonetic
+ key_kp6 = say_next_word
+spk key_kp6 = say_to_right
+ key_kpplus = say_screen
+spk key_kpplus = say_win
+ key_kp1 = say_prev_char
+spk key_kp1 = right_edge
+ key_kp2 = say_char
+spk key_kp2 = say_to_bottom
+double key_kp2 = say_phonetic_char
+ key_kp3 = say_next_char
+spk key_kp3 = bottom_edge
+ key_kp0 = spk_key
+ key_kpdot = say_position
+spk key_kpdot = say_attributes
+key_kpenter = speakup_quiet
+spk key_kpenter = speakup_off
+key_sysrq = speech_kill
+ key_kpslash = speakup_cut
+spk key_kpslash = speakup_paste
+spk key_pageup = say_first_char
+spk key_pagedown = say_last_char
+key_capslock = spk_key
+ spk key_z = spk_lock
+key_leftmeta = spk_key
+ctrl spk key_0 = speakup_goto
+spk key_u = say_prev_line
+spk key_i = say_line
+double spk key_i = say_line_indent
+spk key_o = say_next_line
+spk key_minus = speakup_parked
+shift spk key_minus = say_char_num
+spk key_j = say_prev_word
+spk key_k = say_word
+double spk key_k = spell_word
+spk key_l = say_next_word
+spk key_m = say_prev_char
+spk key_comma = say_char
+double spk key_comma = say_phonetic_char
+spk key_dot = say_next_char
+spk key_n = say_position
+ ctrl spk key_m = left_edge
+ ctrl spk key_y = top_edge
+ ctrl spk key_dot = right_edge
+ctrl spk key_p = bottom_edge
+spk key_apostrophe = say_screen
+spk key_h = say_from_left
+spk key_y = say_from_top
+spk key_semicolon = say_to_right
+spk key_p = say_to_bottom
+spk key_slash = say_attributes
+ spk key_enter = speakup_quiet
+ ctrl spk key_enter = speakup_off
+ spk key_9 = speakup_cut
+spk key_8 = speakup_paste
+shift spk key_m = say_first_char
+ ctrl spk key_semicolon = say_last_char
+spk key_r = read_all_doc
diff --git a/drivers/accessibility/speakup/spk_priv.h b/drivers/accessibility/speakup/spk_priv.h
new file mode 100644 (file)
index 0000000..c75b408
--- /dev/null
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* spk_priv.h
+ * review functions for the speakup screen review package.
+ * originally written by: Kirk Reiser and Andy Berdan.
+ *
+ * extensively modified by David Borowski.
+ *
+ * Copyright (C) 1998  Kirk Reiser.
+ * Copyright (C) 2003  David Borowski.
+ */
+#ifndef _SPEAKUP_PRIVATE_H
+#define _SPEAKUP_PRIVATE_H
+
+#include <linux/printk.h>
+
+#include "spk_types.h"
+#include "spk_priv_keyinfo.h"
+
+#define V_LAST_VAR { MAXVARS }
+#define SPACE 0x20
+#define SYNTH_CHECK 20030716 /* today's date ought to do for check value */
+/* synth flags, for odd synths */
+#define SF_DEC 1 /* to fiddle puncs in alpha strings so it doesn't spell */
+#ifdef MODULE
+#define SYNTH_START 1
+#else
+#define SYNTH_START 0
+#endif
+
+#define KT_SPKUP 15
+#define SPK_SYNTH_TIMEOUT 100000 /* in micro-seconds */
+#define SYNTH_DEFAULT_DEV "ttyS0"
+#define SYNTH_DEFAULT_SER 0
+
+const struct old_serial_port *spk_serial_init(int index);
+void spk_stop_serial_interrupt(void);
+int spk_wait_for_xmitr(struct spk_synth *in_synth);
+void spk_serial_release(void);
+void spk_ttyio_release(void);
+void spk_ttyio_register_ldisc(void);
+void spk_ttyio_unregister_ldisc(void);
+
+void synth_buffer_skip_nonlatin1(void);
+u16 synth_buffer_getc(void);
+u16 synth_buffer_peek(void);
+int synth_buffer_empty(void);
+struct var_t *spk_get_var(enum var_id_t var_id);
+ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
+                    char *buf);
+ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
+                     const char *buf, size_t count);
+
+int spk_serial_synth_probe(struct spk_synth *synth);
+int spk_ttyio_synth_probe(struct spk_synth *synth);
+const char *spk_serial_synth_immediate(struct spk_synth *synth,
+                                      const char *buff);
+const char *spk_ttyio_synth_immediate(struct spk_synth *synth,
+                                     const char *buff);
+void spk_do_catch_up(struct spk_synth *synth);
+void spk_do_catch_up_unicode(struct spk_synth *synth);
+void spk_synth_flush(struct spk_synth *synth);
+unsigned char spk_synth_get_index(struct spk_synth *synth);
+int spk_synth_is_alive_nop(struct spk_synth *synth);
+int spk_synth_is_alive_restart(struct spk_synth *synth);
+__printf(1, 2)
+void synth_printf(const char *buf, ...);
+void synth_putwc(u16 wc);
+void synth_putwc_s(u16 wc);
+void synth_putws(const u16 *buf);
+void synth_putws_s(const u16 *buf);
+int synth_request_region(unsigned long start, unsigned long n);
+int synth_release_region(unsigned long start, unsigned long n);
+int synth_add(struct spk_synth *in_synth);
+void synth_remove(struct spk_synth *in_synth);
+struct spk_synth *synth_current(void);
+
+extern struct speakup_info_t speakup_info;
+
+extern struct var_t synth_time_vars[];
+
+extern struct spk_io_ops spk_serial_io_ops;
+extern struct spk_io_ops spk_ttyio_ops;
+
+#endif
diff --git a/drivers/accessibility/speakup/spk_priv_keyinfo.h b/drivers/accessibility/speakup/spk_priv_keyinfo.h
new file mode 100644 (file)
index 0000000..1f789bd
--- /dev/null
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* spk_priv.h
+ * review functions for the speakup screen review package.
+ * originally written by: Kirk Reiser and Andy Berdan.
+ *
+ * extensively modified by David Borowski.
+ *
+ * Copyright (C) 1998  Kirk Reiser.
+ * Copyright (C) 2003  David Borowski.
+ */
+
+#ifndef _SPEAKUP_KEYINFO_H
+#define _SPEAKUP_KEYINFO_H
+
+#define FIRST_SYNTH_VAR RATE
+/* 0 is reserved for no remap */
+#define SPEAKUP_GOTO           0x01
+#define SPEECH_KILL            0x02
+#define SPEAKUP_QUIET          0x03
+#define SPEAKUP_CUT            0x04
+#define SPEAKUP_PASTE          0x05
+#define SAY_FIRST_CHAR         0x06
+#define SAY_LAST_CHAR          0x07
+#define SAY_CHAR               0x08
+#define SAY_PREV_CHAR          0x09
+#define SAY_NEXT_CHAR          0x0a
+#define SAY_WORD               0x0b
+#define SAY_PREV_WORD          0x0c
+#define SAY_NEXT_WORD          0x0d
+#define SAY_LINE               0x0e
+#define SAY_PREV_LINE          0x0f
+#define SAY_NEXT_LINE          0x10
+#define TOP_EDGE               0x11
+#define BOTTOM_EDGE            0x12
+#define LEFT_EDGE              0x13
+#define RIGHT_EDGE             0x14
+#define SPELL_PHONETIC         0x15
+#define SPELL_WORD             0x16
+#define SAY_SCREEN             0x17
+#define SAY_POSITION           0x18
+#define SAY_ATTRIBUTES         0x19
+#define SPEAKUP_OFF            0x1a
+#define SPEAKUP_PARKED         0x1b
+#define SAY_LINE_INDENT        0x1c
+#define SAY_FROM_TOP           0x1d
+#define SAY_TO_BOTTOM          0x1e
+#define SAY_FROM_LEFT          0x1f
+#define SAY_TO_RIGHT           0x20
+#define SAY_CHAR_NUM           0x21
+#define EDIT_SOME              0x22
+#define EDIT_MOST              0x23
+#define SAY_PHONETIC_CHAR      0x24
+#define EDIT_DELIM             0x25
+#define EDIT_REPEAT            0x26
+#define EDIT_EXNUM             0x27
+#define SET_WIN                0x28
+#define CLEAR_WIN              0x29
+#define ENABLE_WIN             0x2a
+#define SAY_WIN                0x2b
+#define SPK_LOCK               0x2c
+#define SPEAKUP_HELP           0x2d
+#define TOGGLE_CURSORING       0x2e
+#define READ_ALL_DOC           0x2f
+
+/* one greater than the last func handler */
+#define SPKUP_MAX_FUNC         0x30
+
+#define SPK_KEY                0x80
+#define FIRST_EDIT_BITS        0x22
+#define FIRST_SET_VAR SPELL_DELAY
+
+/* increase if adding more than 0x3f functions */
+#define VAR_START              0x40
+
+/* keys for setting variables, must be ordered same as the enum for var_ids */
+/* with dec being even and inc being 1 greater */
+#define SPELL_DELAY_DEC (VAR_START + 0)
+#define SPELL_DELAY_INC (SPELL_DELAY_DEC + 1)
+#define PUNC_LEVEL_DEC (SPELL_DELAY_DEC + 2)
+#define PUNC_LEVEL_INC (PUNC_LEVEL_DEC + 1)
+#define READING_PUNC_DEC (PUNC_LEVEL_DEC + 2)
+#define READING_PUNC_INC (READING_PUNC_DEC + 1)
+#define ATTRIB_BLEEP_DEC (READING_PUNC_DEC + 2)
+#define ATTRIB_BLEEP_INC (ATTRIB_BLEEP_DEC + 1)
+#define BLEEPS_DEC (ATTRIB_BLEEP_DEC + 2)
+#define BLEEPS_INC (BLEEPS_DEC + 1)
+#define RATE_DEC (BLEEPS_DEC + 2)
+#define RATE_INC (RATE_DEC + 1)
+#define PITCH_DEC (RATE_DEC + 2)
+#define PITCH_INC (PITCH_DEC + 1)
+#define VOL_DEC (PITCH_DEC + 2)
+#define VOL_INC (VOL_DEC + 1)
+#define TONE_DEC (VOL_DEC + 2)
+#define TONE_INC (TONE_DEC + 1)
+#define PUNCT_DEC (TONE_DEC + 2)
+#define PUNCT_INC (PUNCT_DEC + 1)
+#define VOICE_DEC (PUNCT_DEC + 2)
+#define VOICE_INC (VOICE_DEC + 1)
+
+#endif
diff --git a/drivers/accessibility/speakup/spk_ttyio.c b/drivers/accessibility/speakup/spk_ttyio.c
new file mode 100644 (file)
index 0000000..9b95f77
--- /dev/null
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/types.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+
+#include "speakup.h"
+#include "spk_types.h"
+#include "spk_priv.h"
+
+struct spk_ldisc_data {
+       char buf;
+       struct completion completion;
+       bool buf_free;
+};
+
+static struct spk_synth *spk_ttyio_synth;
+static struct tty_struct *speakup_tty;
+/* mutex to protect against speakup_tty disappearing from underneath us while
+ * we are using it. this can happen when the device physically unplugged,
+ * while in use. it also serialises access to speakup_tty.
+ */
+static DEFINE_MUTEX(speakup_tty_mutex);
+
+static int ser_to_dev(int ser, dev_t *dev_no)
+{
+       if (ser < 0 || ser > (255 - 64)) {
+               pr_err("speakup: Invalid ser param. Must be between 0 and 191 inclusive.\n");
+               return -EINVAL;
+       }
+
+       *dev_no = MKDEV(4, (64 + ser));
+       return 0;
+}
+
+static int get_dev_to_use(struct spk_synth *synth, dev_t *dev_no)
+{
+       /* use ser only when dev is not specified */
+       if (strcmp(synth->dev_name, SYNTH_DEFAULT_DEV) ||
+           synth->ser == SYNTH_DEFAULT_SER)
+               return tty_dev_name_to_number(synth->dev_name, dev_no);
+
+       return ser_to_dev(synth->ser, dev_no);
+}
+
+static int spk_ttyio_ldisc_open(struct tty_struct *tty)
+{
+       struct spk_ldisc_data *ldisc_data;
+
+       if (!tty->ops->write)
+               return -EOPNOTSUPP;
+       speakup_tty = tty;
+
+       ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL);
+       if (!ldisc_data)
+               return -ENOMEM;
+
+       init_completion(&ldisc_data->completion);
+       ldisc_data->buf_free = true;
+       speakup_tty->disc_data = ldisc_data;
+
+       return 0;
+}
+
+static void spk_ttyio_ldisc_close(struct tty_struct *tty)
+{
+       mutex_lock(&speakup_tty_mutex);
+       kfree(speakup_tty->disc_data);
+       speakup_tty = NULL;
+       mutex_unlock(&speakup_tty_mutex);
+}
+
+static int spk_ttyio_receive_buf2(struct tty_struct *tty,
+                                 const unsigned char *cp, char *fp, int count)
+{
+       struct spk_ldisc_data *ldisc_data = tty->disc_data;
+
+       if (spk_ttyio_synth->read_buff_add) {
+               int i;
+
+               for (i = 0; i < count; i++)
+                       spk_ttyio_synth->read_buff_add(cp[i]);
+
+               return count;
+       }
+
+       if (!ldisc_data->buf_free)
+               /* ttyio_in will tty_schedule_flip */
+               return 0;
+
+       /* Make sure the consumer has read buf before we have seen
+        * buf_free == true and overwrite buf
+        */
+       mb();
+
+       ldisc_data->buf = cp[0];
+       ldisc_data->buf_free = false;
+       complete(&ldisc_data->completion);
+
+       return 1;
+}
+
+static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
+       .owner          = THIS_MODULE,
+       .magic          = TTY_LDISC_MAGIC,
+       .name           = "speakup_ldisc",
+       .open           = spk_ttyio_ldisc_open,
+       .close          = spk_ttyio_ldisc_close,
+       .receive_buf2   = spk_ttyio_receive_buf2,
+};
+
+static int spk_ttyio_out(struct spk_synth *in_synth, const char ch);
+static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch);
+static void spk_ttyio_send_xchar(char ch);
+static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear);
+static unsigned char spk_ttyio_in(void);
+static unsigned char spk_ttyio_in_nowait(void);
+static void spk_ttyio_flush_buffer(void);
+
+struct spk_io_ops spk_ttyio_ops = {
+       .synth_out = spk_ttyio_out,
+       .synth_out_unicode = spk_ttyio_out_unicode,
+       .send_xchar = spk_ttyio_send_xchar,
+       .tiocmset = spk_ttyio_tiocmset,
+       .synth_in = spk_ttyio_in,
+       .synth_in_nowait = spk_ttyio_in_nowait,
+       .flush_buffer = spk_ttyio_flush_buffer,
+};
+EXPORT_SYMBOL_GPL(spk_ttyio_ops);
+
+static inline void get_termios(struct tty_struct *tty,
+                              struct ktermios *out_termios)
+{
+       down_read(&tty->termios_rwsem);
+       *out_termios = tty->termios;
+       up_read(&tty->termios_rwsem);
+}
+
+static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
+{
+       int ret = 0;
+       struct tty_struct *tty;
+       struct ktermios tmp_termios;
+       dev_t dev;
+
+       ret = get_dev_to_use(synth, &dev);
+       if (ret)
+               return ret;
+
+       tty = tty_kopen(dev);
+       if (IS_ERR(tty))
+               return PTR_ERR(tty);
+
+       if (tty->ops->open)
+               ret = tty->ops->open(tty, NULL);
+       else
+               ret = -ENODEV;
+
+       if (ret) {
+               tty_unlock(tty);
+               return ret;
+       }
+
+       clear_bit(TTY_HUPPED, &tty->flags);
+       /* ensure hardware flow control is enabled */
+       get_termios(tty, &tmp_termios);
+       if (!(tmp_termios.c_cflag & CRTSCTS)) {
+               tmp_termios.c_cflag |= CRTSCTS;
+               tty_set_termios(tty, &tmp_termios);
+               /*
+                * check c_cflag to see if it's updated as tty_set_termios
+                * may not return error even when no tty bits are
+                * changed by the request.
+                */
+               get_termios(tty, &tmp_termios);
+               if (!(tmp_termios.c_cflag & CRTSCTS))
+                       pr_warn("speakup: Failed to set hardware flow control\n");
+       }
+
+       tty_unlock(tty);
+
+       ret = tty_set_ldisc(tty, N_SPEAKUP);
+       if (ret)
+               pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
+
+       return ret;
+}
+
+void spk_ttyio_register_ldisc(void)
+{
+       if (tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops))
+               pr_warn("speakup: Error registering line discipline. Most synths won't work.\n");
+}
+
+void spk_ttyio_unregister_ldisc(void)
+{
+       if (tty_unregister_ldisc(N_SPEAKUP))
+               pr_warn("speakup: Couldn't unregister ldisc\n");
+}
+
+static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
+{
+       mutex_lock(&speakup_tty_mutex);
+       if (in_synth->alive && speakup_tty && speakup_tty->ops->write) {
+               int ret = speakup_tty->ops->write(speakup_tty, &ch, 1);
+
+               mutex_unlock(&speakup_tty_mutex);
+               if (ret == 0)
+                       /* No room */
+                       return 0;
+               if (ret < 0) {
+                       pr_warn("%s: I/O error, deactivating speakup\n",
+                               in_synth->long_name);
+                       /* No synth any more, so nobody will restart TTYs,
+                        * and we thus need to do it ourselves.  Now that there
+                        * is no synth we can let application flood anyway
+                        */
+                       in_synth->alive = 0;
+                       speakup_start_ttys();
+                       return 0;
+               }
+               return 1;
+       }
+
+       mutex_unlock(&speakup_tty_mutex);
+       return 0;
+}
+
+static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch)
+{
+       int ret;
+
+       if (ch < 0x80) {
+               ret = spk_ttyio_out(in_synth, ch);
+       } else if (ch < 0x800) {
+               ret  = spk_ttyio_out(in_synth, 0xc0 | (ch >> 6));
+               ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
+       } else {
+               ret  = spk_ttyio_out(in_synth, 0xe0 | (ch >> 12));
+               ret &= spk_ttyio_out(in_synth, 0x80 | ((ch >> 6) & 0x3f));
+               ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
+       }
+       return ret;
+}
+
+static int check_tty(struct tty_struct *tty)
+{
+       if (!tty) {
+               pr_warn("%s: I/O error, deactivating speakup\n",
+                       spk_ttyio_synth->long_name);
+               /* No synth any more, so nobody will restart TTYs, and we thus
+                * need to do it ourselves.  Now that there is no synth we can
+                * let application flood anyway
+                */
+               spk_ttyio_synth->alive = 0;
+               speakup_start_ttys();
+               return 1;
+       }
+
+       return 0;
+}
+
+static void spk_ttyio_send_xchar(char ch)
+{
+       mutex_lock(&speakup_tty_mutex);
+       if (check_tty(speakup_tty)) {
+               mutex_unlock(&speakup_tty_mutex);
+               return;
+       }
+
+       if (speakup_tty->ops->send_xchar)
+               speakup_tty->ops->send_xchar(speakup_tty, ch);
+       mutex_unlock(&speakup_tty_mutex);
+}
+
+static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear)
+{
+       mutex_lock(&speakup_tty_mutex);
+       if (check_tty(speakup_tty)) {
+               mutex_unlock(&speakup_tty_mutex);
+               return;
+       }
+
+       if (speakup_tty->ops->tiocmset)
+               speakup_tty->ops->tiocmset(speakup_tty, set, clear);
+       mutex_unlock(&speakup_tty_mutex);
+}
+
+static unsigned char ttyio_in(int timeout)
+{
+       struct spk_ldisc_data *ldisc_data = speakup_tty->disc_data;
+       char rv;
+
+       if (wait_for_completion_timeout(&ldisc_data->completion,
+                                       usecs_to_jiffies(timeout)) == 0) {
+               if (timeout)
+                       pr_warn("spk_ttyio: timeout (%d)  while waiting for input\n",
+                               timeout);
+               return 0xff;
+       }
+
+       rv = ldisc_data->buf;
+       /* Make sure we have read buf before we set buf_free to let
+        * the producer overwrite it
+        */
+       mb();
+       ldisc_data->buf_free = true;
+       /* Let TTY push more characters */
+       tty_schedule_flip(speakup_tty->port);
+
+       return rv;
+}
+
+static unsigned char spk_ttyio_in(void)
+{
+       return ttyio_in(SPK_SYNTH_TIMEOUT);
+}
+
+static unsigned char spk_ttyio_in_nowait(void)
+{
+       u8 rv = ttyio_in(0);
+
+       return (rv == 0xff) ? 0 : rv;
+}
+
+static void spk_ttyio_flush_buffer(void)
+{
+       mutex_lock(&speakup_tty_mutex);
+       if (check_tty(speakup_tty)) {
+               mutex_unlock(&speakup_tty_mutex);
+               return;
+       }
+
+       if (speakup_tty->ops->flush_buffer)
+               speakup_tty->ops->flush_buffer(speakup_tty);
+
+       mutex_unlock(&speakup_tty_mutex);
+}
+
+int spk_ttyio_synth_probe(struct spk_synth *synth)
+{
+       int rv = spk_ttyio_initialise_ldisc(synth);
+
+       if (rv)
+               return rv;
+
+       synth->alive = 1;
+       spk_ttyio_synth = synth;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(spk_ttyio_synth_probe);
+
+void spk_ttyio_release(void)
+{
+       if (!speakup_tty)
+               return;
+
+       tty_lock(speakup_tty);
+
+       if (speakup_tty->ops->close)
+               speakup_tty->ops->close(speakup_tty, NULL);
+
+       tty_ldisc_flush(speakup_tty);
+       tty_unlock(speakup_tty);
+       tty_kclose(speakup_tty);
+}
+EXPORT_SYMBOL_GPL(spk_ttyio_release);
+
+const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff)
+{
+       u_char ch;
+
+       while ((ch = *buff)) {
+               if (ch == '\n')
+                       ch = synth->procspeech;
+               if (tty_write_room(speakup_tty) < 1 ||
+                   !synth->io_ops->synth_out(synth, ch))
+                       return buff;
+               buff++;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(spk_ttyio_synth_immediate);
diff --git a/drivers/accessibility/speakup/spk_types.h b/drivers/accessibility/speakup/spk_types.h
new file mode 100644 (file)
index 0000000..d3272c6
--- /dev/null
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef SPEAKUP_TYPES_H
+#define SPEAKUP_TYPES_H
+
+/* This file includes all of the typedefs and structs used in speakup. */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/wait.h>                /* for wait_queue */
+#include <linux/init.h>                /* for __init */
+#include <linux/module.h>
+#include <linux/vt_kern.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/io.h>          /* for inb_p, outb_p, inb, outb, etc... */
+#include <linux/device.h>
+
+enum var_type_t {
+       VAR_NUM = 0,
+       VAR_TIME,
+       VAR_STRING,
+       VAR_PROC
+};
+
+enum {
+       E_DEFAULT = 0,
+       E_SET,
+       E_INC,
+       E_DEC,
+       E_NEW_DEFAULT,
+};
+
+enum var_id_t {
+       VERSION = 0, SYNTH, SILENT, SYNTH_DIRECT,
+       KEYMAP, CHARS,
+       PUNC_SOME, PUNC_MOST, PUNC_ALL,
+       DELIM, REPEATS, EXNUMBER,
+       DELAY, TRIGGER, JIFFY, FULL, /* all timers must be together */
+       BLEEP_TIME, CURSOR_TIME, BELL_POS,
+       SAY_CONTROL, SAY_WORD_CTL, NO_INTERRUPT, KEY_ECHO,
+       SPELL_DELAY, PUNC_LEVEL, READING_PUNC,
+       ATTRIB_BLEEP, BLEEPS,
+       RATE, PITCH, INFLECTION, VOL, TONE, PUNCT, VOICE, FREQUENCY, LANG,
+       DIRECT, PAUSE,
+       CAPS_START, CAPS_STOP, CHARTAB,
+       MAXVARS
+};
+
+typedef int (*special_func)(struct vc_data *vc, u_char type, u_char ch,
+               u_short key);
+
+#define COLOR_BUFFER_SIZE 160
+
+struct spk_highlight_color_track {
+       /* Count of each background color */
+       unsigned int bgcount[8];
+       /* Buffer for characters drawn with each background color */
+       u16 highbuf[8][COLOR_BUFFER_SIZE];
+       /* Current index into highbuf */
+       unsigned int highsize[8];
+       /* Reading Position for each color */
+       u_long rpos[8], rx[8], ry[8];
+       /* Real Cursor Y Position */
+       ulong cy;
+};
+
+struct st_spk_t {
+       u_long reading_x, cursor_x;
+       u_long reading_y, cursor_y;
+       u_long reading_pos, cursor_pos;
+       u_long go_x, go_pos;
+       u_long w_top, w_bottom, w_left, w_right;
+       u_char w_start, w_enabled;
+       u_char reading_attr, old_attr;
+       char parked, shut_up;
+       struct spk_highlight_color_track ht;
+       int tty_stopped;
+};
+
+/* now some defines to make these easier to use. */
+#define spk_shut_up (speakup_console[vc->vc_num]->shut_up)
+#define spk_killed (speakup_console[vc->vc_num]->shut_up & 0x40)
+#define spk_x (speakup_console[vc->vc_num]->reading_x)
+#define spk_cx (speakup_console[vc->vc_num]->cursor_x)
+#define spk_y (speakup_console[vc->vc_num]->reading_y)
+#define spk_cy (speakup_console[vc->vc_num]->cursor_y)
+#define spk_pos (speakup_console[vc->vc_num]->reading_pos)
+#define spk_cp (speakup_console[vc->vc_num]->cursor_pos)
+#define goto_pos (speakup_console[vc->vc_num]->go_pos)
+#define goto_x (speakup_console[vc->vc_num]->go_x)
+#define win_top (speakup_console[vc->vc_num]->w_top)
+#define win_bottom (speakup_console[vc->vc_num]->w_bottom)
+#define win_left (speakup_console[vc->vc_num]->w_left)
+#define win_right (speakup_console[vc->vc_num]->w_right)
+#define win_start (speakup_console[vc->vc_num]->w_start)
+#define win_enabled (speakup_console[vc->vc_num]->w_enabled)
+#define spk_attr (speakup_console[vc->vc_num]->reading_attr)
+#define spk_old_attr (speakup_console[vc->vc_num]->old_attr)
+#define spk_parked (speakup_console[vc->vc_num]->parked)
+
+struct st_var_header {
+       char *name;
+       enum var_id_t var_id;
+       enum var_type_t var_type;
+       void *p_val; /* ptr to programs variable to store value */
+       void *data;  /* ptr to the vars data */
+};
+
+struct num_var_t {
+       char *synth_fmt;
+       int default_val;
+       int low;
+       int high;
+       short offset, multiplier; /* for fiddling rates etc. */
+       char *out_str;  /* if synth needs char representation of number */
+       int value;      /* current value */
+};
+
+struct punc_var_t {
+       enum var_id_t var_id;
+       short value;
+};
+
+struct string_var_t {
+       char *default_val;
+};
+
+struct var_t {
+       enum var_id_t var_id;
+       union {
+               struct num_var_t n;
+               struct string_var_t s;
+       } u;
+};
+
+struct st_bits_data { /* punc, repeats, word delim bits */
+       char *name;
+       char *value;
+       short mask;
+};
+
+struct synth_indexing {
+       char *command;
+       unsigned char lowindex;
+       unsigned char highindex;
+       unsigned char currindex;
+};
+
+struct spk_synth;
+
+struct spk_io_ops {
+       int (*synth_out)(struct spk_synth *synth, const char ch);
+       int (*synth_out_unicode)(struct spk_synth *synth, u16 ch);
+       void (*send_xchar)(char ch);
+       void (*tiocmset)(unsigned int set, unsigned int clear);
+       unsigned char (*synth_in)(void);
+       unsigned char (*synth_in_nowait)(void);
+       void (*flush_buffer)(void);
+};
+
+struct spk_synth {
+       struct list_head node;
+
+       const char *name;
+       const char *version;
+       const char *long_name;
+       const char *init;
+       char procspeech;
+       char clear;
+       int delay;
+       int trigger;
+       int jiffies;
+       int full;
+       int ser;
+       char *dev_name;
+       short flags;
+       short startup;
+       const int checkval; /* for validating a proper synth module */
+       struct var_t *vars;
+       int *default_pitch;
+       int *default_vol;
+       struct spk_io_ops *io_ops;
+       int (*probe)(struct spk_synth *synth);
+       void (*release)(void);
+       const char *(*synth_immediate)(struct spk_synth *synth,
+                                      const char *buff);
+       void (*catch_up)(struct spk_synth *synth);
+       void (*flush)(struct spk_synth *synth);
+       int (*is_alive)(struct spk_synth *synth);
+       int (*synth_adjust)(struct st_var_header *var);
+       void (*read_buff_add)(u_char c);
+       unsigned char (*get_index)(struct spk_synth *synth);
+       struct synth_indexing indexing;
+       int alive;
+       struct attribute_group attributes;
+};
+
+/*
+ * module_spk_synth() - Helper macro for registering a speakup driver
+ * @__spk_synth: spk_synth struct
+ * Helper macro for speakup drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_spk_synth(__spk_synth) \
+       module_driver(__spk_synth, synth_add, synth_remove)
+
+struct speakup_info_t {
+       spinlock_t spinlock;
+       int port_tts;
+       int flushing;
+};
+
+struct bleep {
+       short freq;
+       unsigned long jiffies;
+       int active;
+};
+#endif
diff --git a/drivers/accessibility/speakup/synth.c b/drivers/accessibility/speakup/synth.c
new file mode 100644 (file)
index 0000000..3568bfb
--- /dev/null
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/types.h>
+#include <linux/ctype.h>       /* for isdigit() and friends */
+#include <linux/fs.h>
+#include <linux/mm.h>          /* for verify_area */
+#include <linux/errno.h>       /* for -EBUSY */
+#include <linux/ioport.h>      /* for check_region, request_region */
+#include <linux/interrupt.h>
+#include <linux/delay.h>       /* for loops_per_sec */
+#include <linux/kmod.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>     /* for copy_from_user */
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+
+#include "spk_priv.h"
+#include "speakup.h"
+#include "serialio.h"
+
+static LIST_HEAD(synths);
+struct spk_synth *synth;
+char spk_pitch_buff[32] = "";
+static int module_status;
+bool spk_quiet_boot;
+
+struct speakup_info_t speakup_info = {
+       /*
+        * This spinlock is used to protect the entire speakup machinery, and
+        * must be taken at each kernel->speakup transition and released at
+        * each corresponding speakup->kernel transition.
+        *
+        * The progression thread only interferes with the speakup machinery
+        * through the synth buffer, so only needs to take the lock
+        * while tinkering with the buffer.
+        *
+        * We use spin_lock/trylock_irqsave and spin_unlock_irqrestore with this
+        * spinlock because speakup needs to disable the keyboard IRQ.
+        */
+       .spinlock = __SPIN_LOCK_UNLOCKED(speakup_info.spinlock),
+       .flushing = 0,
+};
+EXPORT_SYMBOL_GPL(speakup_info);
+
+static int do_synth_init(struct spk_synth *in_synth);
+
+/*
+ * Main loop of the progression thread: keep eating from the buffer
+ * and push to the serial port, waiting as needed
+ *
+ * For devices that have a "full" notification mechanism, the driver can
+ * adapt the loop the way they prefer.
+ */
+static void _spk_do_catch_up(struct spk_synth *synth, int unicode)
+{
+       u16 ch;
+       unsigned long flags;
+       unsigned long jiff_max;
+       struct var_t *delay_time;
+       struct var_t *full_time;
+       struct var_t *jiffy_delta;
+       int jiffy_delta_val;
+       int delay_time_val;
+       int full_time_val;
+       int ret;
+
+       jiffy_delta = spk_get_var(JIFFY);
+       full_time = spk_get_var(FULL);
+       delay_time = spk_get_var(DELAY);
+
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       jiffy_delta_val = jiffy_delta->u.n.value;
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+
+       jiff_max = jiffies + jiffy_delta_val;
+       while (!kthread_should_stop()) {
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               if (speakup_info.flushing) {
+                       speakup_info.flushing = 0;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       synth->flush(synth);
+                       continue;
+               }
+               if (!unicode)
+                       synth_buffer_skip_nonlatin1();
+               if (synth_buffer_empty()) {
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       break;
+               }
+               ch = synth_buffer_peek();
+               set_current_state(TASK_INTERRUPTIBLE);
+               full_time_val = full_time->u.n.value;
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               if (ch == '\n')
+                       ch = synth->procspeech;
+               if (unicode)
+                       ret = synth->io_ops->synth_out_unicode(synth, ch);
+               else
+                       ret = synth->io_ops->synth_out(synth, ch);
+               if (!ret) {
+                       schedule_timeout(msecs_to_jiffies(full_time_val));
+                       continue;
+               }
+               if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
+                       spin_lock_irqsave(&speakup_info.spinlock, flags);
+                       jiffy_delta_val = jiffy_delta->u.n.value;
+                       delay_time_val = delay_time->u.n.value;
+                       full_time_val = full_time->u.n.value;
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       if (synth->io_ops->synth_out(synth, synth->procspeech))
+                               schedule_timeout(
+                                       msecs_to_jiffies(delay_time_val));
+                       else
+                               schedule_timeout(
+                                       msecs_to_jiffies(full_time_val));
+                       jiff_max = jiffies + jiffy_delta_val;
+               }
+               set_current_state(TASK_RUNNING);
+               spin_lock_irqsave(&speakup_info.spinlock, flags);
+               synth_buffer_getc();
+               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       }
+       synth->io_ops->synth_out(synth, synth->procspeech);
+}
+
+void spk_do_catch_up(struct spk_synth *synth)
+{
+       _spk_do_catch_up(synth, 0);
+}
+EXPORT_SYMBOL_GPL(spk_do_catch_up);
+
+void spk_do_catch_up_unicode(struct spk_synth *synth)
+{
+       _spk_do_catch_up(synth, 1);
+}
+EXPORT_SYMBOL_GPL(spk_do_catch_up_unicode);
+
+void spk_synth_flush(struct spk_synth *synth)
+{
+       synth->io_ops->flush_buffer();
+       synth->io_ops->synth_out(synth, synth->clear);
+}
+EXPORT_SYMBOL_GPL(spk_synth_flush);
+
+unsigned char spk_synth_get_index(struct spk_synth *synth)
+{
+       return synth->io_ops->synth_in_nowait();
+}
+EXPORT_SYMBOL_GPL(spk_synth_get_index);
+
+int spk_synth_is_alive_nop(struct spk_synth *synth)
+{
+       synth->alive = 1;
+       return 1;
+}
+EXPORT_SYMBOL_GPL(spk_synth_is_alive_nop);
+
+int spk_synth_is_alive_restart(struct spk_synth *synth)
+{
+       if (synth->alive)
+               return 1;
+       if (spk_wait_for_xmitr(synth) > 0) {
+               /* restart */
+               synth->alive = 1;
+               synth_printf("%s", synth->init);
+               return 2; /* reenabled */
+       }
+       pr_warn("%s: can't restart synth\n", synth->long_name);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(spk_synth_is_alive_restart);
+
+static void thread_wake_up(struct timer_list *unused)
+{
+       wake_up_interruptible_all(&speakup_event);
+}
+
+static DEFINE_TIMER(thread_timer, thread_wake_up);
+
+void synth_start(void)
+{
+       struct var_t *trigger_time;
+
+       if (!synth->alive) {
+               synth_buffer_clear();
+               return;
+       }
+       trigger_time = spk_get_var(TRIGGER);
+       if (!timer_pending(&thread_timer))
+               mod_timer(&thread_timer, jiffies +
+                       msecs_to_jiffies(trigger_time->u.n.value));
+}
+
+void spk_do_flush(void)
+{
+       if (!synth)
+               return;
+
+       speakup_info.flushing = 1;
+       synth_buffer_clear();
+       if (synth->alive) {
+               if (spk_pitch_shift) {
+                       synth_printf("%s", spk_pitch_buff);
+                       spk_pitch_shift = 0;
+               }
+       }
+       wake_up_interruptible_all(&speakup_event);
+       wake_up_process(speakup_task);
+}
+
+void synth_write(const char *buf, size_t count)
+{
+       while (count--)
+               synth_buffer_add(*buf++);
+       synth_start();
+}
+
+void synth_printf(const char *fmt, ...)
+{
+       va_list args;
+       unsigned char buf[160], *p;
+       int r;
+
+       va_start(args, fmt);
+       r = vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+       if (r > sizeof(buf) - 1)
+               r = sizeof(buf) - 1;
+
+       p = buf;
+       while (r--)
+               synth_buffer_add(*p++);
+       synth_start();
+}
+EXPORT_SYMBOL_GPL(synth_printf);
+
+void synth_putwc(u16 wc)
+{
+       synth_buffer_add(wc);
+}
+EXPORT_SYMBOL_GPL(synth_putwc);
+
+void synth_putwc_s(u16 wc)
+{
+       synth_buffer_add(wc);
+       synth_start();
+}
+EXPORT_SYMBOL_GPL(synth_putwc_s);
+
+void synth_putws(const u16 *buf)
+{
+       const u16 *p;
+
+       for (p = buf; *p; p++)
+               synth_buffer_add(*p);
+}
+EXPORT_SYMBOL_GPL(synth_putws);
+
+void synth_putws_s(const u16 *buf)
+{
+       synth_putws(buf);
+       synth_start();
+}
+EXPORT_SYMBOL_GPL(synth_putws_s);
+
+static int index_count;
+static int sentence_count;
+
+void spk_reset_index_count(int sc)
+{
+       static int first = 1;
+
+       if (first)
+               first = 0;
+       else
+               synth->get_index(synth);
+       index_count = 0;
+       sentence_count = sc;
+}
+
+int synth_supports_indexing(void)
+{
+       if (synth->get_index)
+               return 1;
+       return 0;
+}
+
+void synth_insert_next_index(int sent_num)
+{
+       int out;
+
+       if (synth->alive) {
+               if (sent_num == 0) {
+                       synth->indexing.currindex++;
+                       index_count++;
+                       if (synth->indexing.currindex >
+                                       synth->indexing.highindex)
+                               synth->indexing.currindex =
+                                       synth->indexing.lowindex;
+               }
+
+               out = synth->indexing.currindex * 10 + sent_num;
+               synth_printf(synth->indexing.command, out, out);
+       }
+}
+
+void spk_get_index_count(int *linecount, int *sentcount)
+{
+       int ind = synth->get_index(synth);
+
+       if (ind) {
+               sentence_count = ind % 10;
+
+               if ((ind / 10) <= synth->indexing.currindex)
+                       index_count = synth->indexing.currindex - (ind / 10);
+               else
+                       index_count = synth->indexing.currindex
+                               - synth->indexing.lowindex
+                               + synth->indexing.highindex - (ind / 10) + 1;
+       }
+       *sentcount = sentence_count;
+       *linecount = index_count;
+}
+
+static struct resource synth_res;
+
+int synth_request_region(unsigned long start, unsigned long n)
+{
+       struct resource *parent = &ioport_resource;
+
+       memset(&synth_res, 0, sizeof(synth_res));
+       synth_res.name = synth->name;
+       synth_res.start = start;
+       synth_res.end = start + n - 1;
+       synth_res.flags = IORESOURCE_BUSY;
+       return request_resource(parent, &synth_res);
+}
+EXPORT_SYMBOL_GPL(synth_request_region);
+
+int synth_release_region(unsigned long start, unsigned long n)
+{
+       return release_resource(&synth_res);
+}
+EXPORT_SYMBOL_GPL(synth_release_region);
+
+struct var_t synth_time_vars[] = {
+       { DELAY, .u.n = {NULL, 100, 100, 2000, 0, 0, NULL } },
+       { TRIGGER, .u.n = {NULL, 20, 10, 2000, 0, 0, NULL } },
+       { JIFFY, .u.n = {NULL, 50, 20, 200, 0, 0, NULL } },
+       { FULL, .u.n = {NULL, 400, 200, 60000, 0, 0, NULL } },
+       V_LAST_VAR
+};
+
+/* called by: speakup_init() */
+int synth_init(char *synth_name)
+{
+       int ret = 0;
+       struct spk_synth *tmp, *synth = NULL;
+
+       if (!synth_name)
+               return 0;
+
+       if (strcmp(synth_name, "none") == 0) {
+               mutex_lock(&spk_mutex);
+               synth_release();
+               mutex_unlock(&spk_mutex);
+               return 0;
+       }
+
+       mutex_lock(&spk_mutex);
+       /* First, check if we already have it loaded. */
+       list_for_each_entry(tmp, &synths, node) {
+               if (strcmp(tmp->name, synth_name) == 0)
+                       synth = tmp;
+       }
+
+       /* If we got one, initialize it now. */
+       if (synth)
+               ret = do_synth_init(synth);
+       else
+               ret = -ENODEV;
+       mutex_unlock(&spk_mutex);
+
+       return ret;
+}
+
+/* called by: synth_add() */
+static int do_synth_init(struct spk_synth *in_synth)
+{
+       struct var_t *var;
+
+       synth_release();
+       if (in_synth->checkval != SYNTH_CHECK)
+               return -EINVAL;
+       synth = in_synth;
+       synth->alive = 0;
+       pr_warn("synth probe\n");
+       if (synth->probe(synth) < 0) {
+               pr_warn("%s: device probe failed\n", in_synth->name);
+               synth = NULL;
+               return -ENODEV;
+       }
+       synth_time_vars[0].u.n.value =
+               synth_time_vars[0].u.n.default_val = synth->delay;
+       synth_time_vars[1].u.n.value =
+               synth_time_vars[1].u.n.default_val = synth->trigger;
+       synth_time_vars[2].u.n.value =
+               synth_time_vars[2].u.n.default_val = synth->jiffies;
+       synth_time_vars[3].u.n.value =
+               synth_time_vars[3].u.n.default_val = synth->full;
+       synth_printf("%s", synth->init);
+       for (var = synth->vars;
+               (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
+               speakup_register_var(var);
+       if (!spk_quiet_boot)
+               synth_printf("%s found\n", synth->long_name);
+       if (synth->attributes.name &&
+           sysfs_create_group(speakup_kobj, &synth->attributes) < 0)
+               return -ENOMEM;
+       synth_flags = synth->flags;
+       wake_up_interruptible_all(&speakup_event);
+       if (speakup_task)
+               wake_up_process(speakup_task);
+       return 0;
+}
+
+void synth_release(void)
+{
+       struct var_t *var;
+       unsigned long flags;
+
+       if (!synth)
+               return;
+       spin_lock_irqsave(&speakup_info.spinlock, flags);
+       pr_info("releasing synth %s\n", synth->name);
+       synth->alive = 0;
+       del_timer(&thread_timer);
+       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+       if (synth->attributes.name)
+               sysfs_remove_group(speakup_kobj, &synth->attributes);
+       for (var = synth->vars; var->var_id != MAXVARS; var++)
+               speakup_unregister_var(var->var_id);
+       synth->release();
+       synth = NULL;
+}
+
+/* called by: all_driver_init() */
+int synth_add(struct spk_synth *in_synth)
+{
+       int status = 0;
+       struct spk_synth *tmp;
+
+       mutex_lock(&spk_mutex);
+
+       list_for_each_entry(tmp, &synths, node) {
+               if (tmp == in_synth) {
+                       mutex_unlock(&spk_mutex);
+                       return 0;
+               }
+       }
+
+       if (in_synth->startup)
+               status = do_synth_init(in_synth);
+
+       if (!status)
+               list_add_tail(&in_synth->node, &synths);
+
+       mutex_unlock(&spk_mutex);
+       return status;
+}
+EXPORT_SYMBOL_GPL(synth_add);
+
+void synth_remove(struct spk_synth *in_synth)
+{
+       mutex_lock(&spk_mutex);
+       if (synth == in_synth)
+               synth_release();
+       list_del(&in_synth->node);
+       module_status = 0;
+       mutex_unlock(&spk_mutex);
+}
+EXPORT_SYMBOL_GPL(synth_remove);
+
+struct spk_synth *synth_current(void)
+{
+       return synth;
+}
+EXPORT_SYMBOL_GPL(synth_current);
+
+short spk_punc_masks[] = { 0, SOME, MOST, PUNC, PUNC | B_SYM };
diff --git a/drivers/accessibility/speakup/thread.c b/drivers/accessibility/speakup/thread.c
new file mode 100644 (file)
index 0000000..2fc75e6
--- /dev/null
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kthread.h>
+#include <linux/wait.h>
+
+#include "spk_types.h"
+#include "speakup.h"
+#include "spk_priv.h"
+
+DECLARE_WAIT_QUEUE_HEAD(speakup_event);
+EXPORT_SYMBOL_GPL(speakup_event);
+
+int speakup_thread(void *data)
+{
+       unsigned long flags;
+       int should_break;
+       struct bleep our_sound;
+
+       our_sound.active = 0;
+       our_sound.freq = 0;
+       our_sound.jiffies = 0;
+
+       mutex_lock(&spk_mutex);
+       while (1) {
+               DEFINE_WAIT(wait);
+
+               while (1) {
+                       spin_lock_irqsave(&speakup_info.spinlock, flags);
+                       our_sound = spk_unprocessed_sound;
+                       spk_unprocessed_sound.active = 0;
+                       prepare_to_wait(&speakup_event, &wait,
+                                       TASK_INTERRUPTIBLE);
+                       should_break = kthread_should_stop() ||
+                               our_sound.active ||
+                               (synth && synth->catch_up && synth->alive &&
+                                       (speakup_info.flushing ||
+                                       !synth_buffer_empty()));
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+                       if (should_break)
+                               break;
+                       mutex_unlock(&spk_mutex);
+                       schedule();
+                       mutex_lock(&spk_mutex);
+               }
+               finish_wait(&speakup_event, &wait);
+               if (kthread_should_stop())
+                       break;
+
+               if (our_sound.active)
+                       kd_mksound(our_sound.freq, our_sound.jiffies);
+               if (synth && synth->catch_up && synth->alive) {
+                       /*
+                        * It is up to the callee to take the lock, so that it
+                        * can sleep whenever it likes
+                        */
+                       synth->catch_up(synth);
+               }
+
+               speakup_start_ttys();
+       }
+       mutex_unlock(&spk_mutex);
+       return 0;
+}
diff --git a/drivers/accessibility/speakup/varhandlers.c b/drivers/accessibility/speakup/varhandlers.c
new file mode 100644 (file)
index 0000000..d7f6bec
--- /dev/null
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/ctype.h>
+#include "spk_types.h"
+#include "spk_priv.h"
+#include "speakup.h"
+
+static struct st_var_header var_headers[] = {
+       { "version", VERSION, VAR_PROC, NULL, NULL },
+       { "synth_name", SYNTH, VAR_PROC, NULL, NULL },
+       { "keymap", KEYMAP, VAR_PROC, NULL, NULL },
+       { "silent", SILENT, VAR_PROC, NULL, NULL },
+       { "punc_some", PUNC_SOME, VAR_PROC, NULL, NULL },
+       { "punc_most", PUNC_MOST, VAR_PROC, NULL, NULL },
+       { "punc_all", PUNC_ALL, VAR_PROC, NULL, NULL },
+       { "delimiters", DELIM, VAR_PROC, NULL, NULL },
+       { "repeats", REPEATS, VAR_PROC, NULL, NULL },
+       { "ex_num", EXNUMBER, VAR_PROC, NULL, NULL },
+       { "characters", CHARS, VAR_PROC, NULL, NULL },
+       { "synth_direct", SYNTH_DIRECT, VAR_PROC, NULL, NULL },
+       { "caps_start", CAPS_START, VAR_STRING, spk_str_caps_start, NULL },
+       { "caps_stop", CAPS_STOP, VAR_STRING, spk_str_caps_stop, NULL },
+       { "delay_time", DELAY, VAR_TIME, NULL, NULL },
+       { "trigger_time", TRIGGER, VAR_TIME, NULL, NULL },
+       { "jiffy_delta", JIFFY, VAR_TIME, NULL, NULL },
+       { "full_time", FULL, VAR_TIME, NULL, NULL },
+       { "spell_delay", SPELL_DELAY, VAR_NUM, &spk_spell_delay, NULL },
+       { "bleeps", BLEEPS, VAR_NUM, &spk_bleeps, NULL },
+       { "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, &spk_attrib_bleep, NULL },
+       { "bleep_time", BLEEP_TIME, VAR_TIME, &spk_bleep_time, NULL },
+       { "cursor_time", CURSOR_TIME, VAR_TIME, NULL, NULL },
+       { "punc_level", PUNC_LEVEL, VAR_NUM, &spk_punc_level, NULL },
+       { "reading_punc", READING_PUNC, VAR_NUM, &spk_reading_punc, NULL },
+       { "say_control", SAY_CONTROL, VAR_NUM, &spk_say_ctrl, NULL },
+       { "say_word_ctl", SAY_WORD_CTL, VAR_NUM, &spk_say_word_ctl, NULL },
+       { "no_interrupt", NO_INTERRUPT, VAR_NUM, &spk_no_intr, NULL },
+       { "key_echo", KEY_ECHO, VAR_NUM, &spk_key_echo, NULL },
+       { "bell_pos", BELL_POS, VAR_NUM, &spk_bell_pos, NULL },
+       { "rate", RATE, VAR_NUM, NULL, NULL },
+       { "pitch", PITCH, VAR_NUM, NULL, NULL },
+       { "inflection", INFLECTION, VAR_NUM, NULL, NULL },
+       { "vol", VOL, VAR_NUM, NULL, NULL },
+       { "tone", TONE, VAR_NUM, NULL, NULL },
+       { "punct", PUNCT, VAR_NUM, NULL, NULL   },
+       { "voice", VOICE, VAR_NUM, NULL, NULL },
+       { "freq", FREQUENCY, VAR_NUM, NULL, NULL },
+       { "lang", LANG, VAR_NUM, NULL, NULL },
+       { "chartab", CHARTAB, VAR_PROC, NULL, NULL },
+       { "direct", DIRECT, VAR_NUM, NULL, NULL },
+       { "pause", PAUSE, VAR_STRING, spk_str_pause, NULL },
+};
+
+static struct st_var_header *var_ptrs[MAXVARS] = { NULL, NULL, NULL };
+
+static struct punc_var_t punc_vars[] = {
+       { PUNC_SOME, 1 },
+       { PUNC_MOST, 2 },
+       { PUNC_ALL, 3 },
+       { DELIM, 4 },
+       { REPEATS, 5 },
+       { EXNUMBER, 6 },
+       { -1, -1 },
+};
+
+int spk_chartab_get_value(char *keyword)
+{
+       int value = 0;
+
+       if (!strcmp(keyword, "ALPHA"))
+               value = ALPHA;
+       else if (!strcmp(keyword, "B_CTL"))
+               value = B_CTL;
+       else if (!strcmp(keyword, "WDLM"))
+               value = WDLM;
+       else if (!strcmp(keyword, "A_PUNC"))
+               value = A_PUNC;
+       else if (!strcmp(keyword, "PUNC"))
+               value = PUNC;
+       else if (!strcmp(keyword, "NUM"))
+               value = NUM;
+       else if (!strcmp(keyword, "A_CAP"))
+               value = A_CAP;
+       else if (!strcmp(keyword, "B_CAPSYM"))
+               value = B_CAPSYM;
+       else if (!strcmp(keyword, "B_SYM"))
+               value = B_SYM;
+       return value;
+}
+
+void speakup_register_var(struct var_t *var)
+{
+       static char nothing[2] = "\0";
+       int i;
+       struct st_var_header *p_header;
+
+       BUG_ON(!var || var->var_id < 0 || var->var_id >= MAXVARS);
+       if (!var_ptrs[0]) {
+               for (i = 0; i < MAXVARS; i++) {
+                       p_header = &var_headers[i];
+                       var_ptrs[p_header->var_id] = p_header;
+                       p_header->data = NULL;
+               }
+       }
+       p_header = var_ptrs[var->var_id];
+       if (p_header->data)
+               return;
+       p_header->data = var;
+       switch (p_header->var_type) {
+       case VAR_STRING:
+               spk_set_string_var(nothing, p_header, 0);
+               break;
+       case VAR_NUM:
+       case VAR_TIME:
+               spk_set_num_var(0, p_header, E_DEFAULT);
+               break;
+       default:
+               break;
+       }
+}
+
+void speakup_unregister_var(enum var_id_t var_id)
+{
+       struct st_var_header *p_header;
+
+       BUG_ON(var_id < 0 || var_id >= MAXVARS);
+       p_header = var_ptrs[var_id];
+       p_header->data = NULL;
+}
+
+struct st_var_header *spk_get_var_header(enum var_id_t var_id)
+{
+       struct st_var_header *p_header;
+
+       if (var_id < 0 || var_id >= MAXVARS)
+               return NULL;
+       p_header = var_ptrs[var_id];
+       if (!p_header->data)
+               return NULL;
+       return p_header;
+}
+
+struct st_var_header *spk_var_header_by_name(const char *name)
+{
+       int i;
+
+       if (!name)
+               return NULL;
+
+       for (i = 0; i < MAXVARS; i++) {
+               if (strcmp(name, var_ptrs[i]->name) == 0)
+                       return var_ptrs[i];
+       }
+       return NULL;
+}
+
+struct var_t *spk_get_var(enum var_id_t var_id)
+{
+       BUG_ON(var_id < 0 || var_id >= MAXVARS);
+       BUG_ON(!var_ptrs[var_id]);
+       return var_ptrs[var_id]->data;
+}
+EXPORT_SYMBOL_GPL(spk_get_var);
+
+struct punc_var_t *spk_get_punc_var(enum var_id_t var_id)
+{
+       struct punc_var_t *rv = NULL;
+       struct punc_var_t *where;
+
+       where = punc_vars;
+       while ((where->var_id != -1) && (!rv)) {
+               if (where->var_id == var_id)
+                       rv = where;
+               else
+                       where++;
+       }
+       return rv;
+}
+
+/* handlers for setting vars */
+int spk_set_num_var(int input, struct st_var_header *var, int how)
+{
+       int val;
+       int *p_val = var->p_val;
+       char buf[32];
+       char *cp;
+       struct var_t *var_data = var->data;
+
+       if (!var_data)
+               return -ENODATA;
+
+       val = var_data->u.n.value;
+       switch (how) {
+       case E_NEW_DEFAULT:
+               if (input < var_data->u.n.low || input > var_data->u.n.high)
+                       return -ERANGE;
+               var_data->u.n.default_val = input;
+               return 0;
+       case E_DEFAULT:
+               val = var_data->u.n.default_val;
+               break;
+       case E_SET:
+               val = input;
+               break;
+       case E_INC:
+               val += input;
+               break;
+       case E_DEC:
+               val -= input;
+               break;
+       }
+
+       if (val < var_data->u.n.low || val > var_data->u.n.high)
+               return -ERANGE;
+
+       var_data->u.n.value = val;
+       if (var->var_type == VAR_TIME && p_val) {
+               *p_val = msecs_to_jiffies(val);
+               return 0;
+       }
+       if (p_val)
+               *p_val = val;
+       if (var->var_id == PUNC_LEVEL) {
+               spk_punc_mask = spk_punc_masks[val];
+               return 0;
+       }
+       if (var_data->u.n.multiplier != 0)
+               val *= var_data->u.n.multiplier;
+       val += var_data->u.n.offset;
+       if (var->var_id < FIRST_SYNTH_VAR || !synth)
+               return 0;
+       if (synth->synth_adjust)
+               return synth->synth_adjust(var);
+
+       if (!var_data->u.n.synth_fmt)
+               return 0;
+       if (var->var_id == PITCH)
+               cp = spk_pitch_buff;
+       else
+               cp = buf;
+       if (!var_data->u.n.out_str)
+               sprintf(cp, var_data->u.n.synth_fmt, (int)val);
+       else
+               sprintf(cp, var_data->u.n.synth_fmt,
+                       var_data->u.n.out_str[val]);
+       synth_printf("%s", cp);
+       return 0;
+}
+
+int spk_set_string_var(const char *page, struct st_var_header *var, int len)
+{
+       struct var_t *var_data = var->data;
+
+       if (!var_data)
+               return -ENODATA;
+       if (len > MAXVARLEN)
+               return -E2BIG;
+       if (!len) {
+               if (!var_data->u.s.default_val)
+                       return 0;
+               if (!var->p_val)
+                       var->p_val = var_data->u.s.default_val;
+               if (var->p_val != var_data->u.s.default_val)
+                       strcpy((char *)var->p_val, var_data->u.s.default_val);
+               return -ERESTART;
+       } else if (var->p_val) {
+               strcpy((char *)var->p_val, page);
+       } else {
+               return -E2BIG;
+       }
+       return 0;
+}
+
+/*
+ * spk_set_mask_bits sets or clears the punc/delim/repeat bits,
+ * if input is null uses the defaults.
+ * values for how: 0 clears bits of chars supplied,
+ * 1 clears allk, 2 sets bits for chars
+ */
+int spk_set_mask_bits(const char *input, const int which, const int how)
+{
+       u_char *cp;
+       short mask = spk_punc_info[which].mask;
+
+       if (how & 1) {
+               for (cp = (u_char *)spk_punc_info[3].value; *cp; cp++)
+                       spk_chartab[*cp] &= ~mask;
+       }
+       cp = (u_char *)input;
+       if (!cp) {
+               cp = spk_punc_info[which].value;
+       } else {
+               for (; *cp; cp++) {
+                       if (*cp < SPACE)
+                               break;
+                       if (mask < PUNC) {
+                               if (!(spk_chartab[*cp] & PUNC))
+                                       break;
+                       } else if (spk_chartab[*cp] & B_NUM) {
+                               break;
+                       }
+               }
+               if (*cp)
+                       return -EINVAL;
+               cp = (u_char *)input;
+       }
+       if (how & 2) {
+               for (; *cp; cp++)
+                       if (*cp > SPACE)
+                               spk_chartab[*cp] |= mask;
+       } else {
+               for (; *cp; cp++)
+                       if (*cp > SPACE)
+                               spk_chartab[*cp] &= ~mask;
+       }
+       return 0;
+}
+
+char *spk_strlwr(char *s)
+{
+       char *p;
+
+       if (!s)
+               return NULL;
+
+       for (p = s; *p; p++)
+               *p = tolower(*p);
+       return s;
+}
+
+char *spk_s2uchar(char *start, char *dest)
+{
+       int val;
+
+       /* Do not replace with kstrtoul: here we need start to be updated */
+       val = simple_strtoul(skip_spaces(start), &start, 10);
+       if (*start == ',')
+               start++;
+       *dest = (u_char)val;
+       return start;
+}
index b3fb4d4..e6c831c 100644 (file)
@@ -56,8 +56,6 @@ source "drivers/staging/sm750fb/Kconfig"
 
 source "drivers/staging/emxx_udc/Kconfig"
 
-source "drivers/staging/speakup/Kconfig"
-
 source "drivers/staging/nvec/Kconfig"
 
 source "drivers/staging/media/Kconfig"
index 3d8c7ea..a3b1fd0 100644 (file)
@@ -20,7 +20,6 @@ obj-$(CONFIG_VME_BUS)         += vme/
 obj-$(CONFIG_IIO)              += iio/
 obj-$(CONFIG_FB_SM750)         += sm750fb/
 obj-$(CONFIG_USB_EMXX)         += emxx_udc/
-obj-$(CONFIG_SPEAKUP)          += speakup/
 obj-$(CONFIG_MFD_NVEC)         += nvec/
 obj-$(CONFIG_ANDROID)          += android/
 obj-$(CONFIG_STAGING_BOARD)    += board/
diff --git a/drivers/staging/speakup/DefaultKeyAssignments b/drivers/staging/speakup/DefaultKeyAssignments
deleted file mode 100644 (file)
index 101c803..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-This file is intended to give you an overview of the default keys used
-by speakup for it's review functions.  You may change them to be
-anything you want but that will take some familiarity with key
-mapping.
-
-We have remapped the insert or zero key on the keypad to act as a
-shift key.  Well, actually as an altgr key.  So in the following list
-InsKeyPad-period means hold down the insert key like a shift key and
-hit the keypad period.
-
-KeyPad-8               Say current Line
-InsKeyPad-8            say from top of screen to reading cursor.
-KeyPad-7               Say Previous Line (UP one line)
-KeyPad-9               Say Next Line (down one line)
-KeyPad-5               Say Current Word
-InsKeyPad-5            Spell Current Word
-KeyPad-4               Say Previous Word (left one word)
-InsKeyPad-4            say from left edge of line to reading cursor.
-KeyPad-6               Say Next Word (right one word)
-InsKeyPad-6            Say from reading cursor to right edge of line.
-KeyPad-2               Say Current Letter
-InsKeyPad-2            say current letter phonetically
-KeyPad-1               Say Previous Character (left one letter)
-KeyPad-3               Say Next Character (right one letter)
-KeyPad-plus            Say Entire Screen
-InsKeyPad-plus         Say from reading cursor line to bottom of screen.
-KeyPad-Minus           Park reading cursor (toggle)
-InsKeyPad-minus                Say character hex and decimal value.
-KeyPad-period          Say Position (current line, position and console)
-InsKeyPad-period       say colour attributes of current position.
-InsKeyPad-9            Move reading cursor to top of screen (insert pgup)
-InsKeyPad-3            Move reading cursor to bottom of screen (insert pgdn)
-InsKeyPad-7            Move reading cursor to left edge of screen (insert home)
-InsKeyPad-1            Move reading cursor to right edge of screen (insert end)
-ControlKeyPad-1                Move reading cursor to last character on current line.
-KeyPad-Enter           Shut Up (until another key is hit) and sync reading cursor
-InsKeyPad-Enter                Shut Up (until toggled back on).
-InsKeyPad-star n<x|y>  go to line (y) or column (x). Where 'n' is any
-               allowed value for the row or column for your current screen.
-KeyPad-/               Mark and Cut screen region.
-InsKeyPad-/            Paste screen region into any console.
-
-Hitting any key while speakup is outputting speech will quiet the
-synth until it has caught up with what is being printed on the
-console.
-
diff --git a/drivers/staging/speakup/Kconfig b/drivers/staging/speakup/Kconfig
deleted file mode 100644 (file)
index 0803c20..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-menu "Speakup console speech"
-
-config SPEAKUP
-       depends on VT
-       tristate "Speakup core"
-       help
-               This is the Speakup screen reader.  Think of it as a
-               video console for blind people.  If built in to the
-               kernel, it can speak everything on the text console from
-               boot up to shutdown.  For more information on Speakup,
-               point your browser at <http://www.linux-speakup.org/>.
-               There is also a mailing list at the above url that you
-               can subscribe to.
-
-               Supported synthesizers are accent sa, accent pc,
-               appollo II., Auddapter, Braille 'n Speak, Dectalk
-               external (old), Dectalk PC (full length isa board),
-               Dectalk express, Doubletalk, Doubletalk LT or
-               Litetalk, Keynote Gold internal PC, software
-               synthesizers, Speakout, transport, and a dummy module
-               that can be used with a plain text terminal.
-
-               Speakup can either be built in or compiled as a module
-               by answering y or m.  If you answer y here, then you
-               must answer either y or m to at least one of the
-               synthesizer drivers below.  If you answer m here, then
-               the synthesizer drivers below can only be built as
-               modules.
-
-               These drivers are not standalone drivers, but must be
-               used in conjunction with Speakup.  Think of them as
-               video cards for blind people.
-
-
-               The Dectalk pc driver can only be built as a module, and
-               requires software to be pre-loaded on to the card before
-               the module can be loaded.  See the decpc choice below
-               for more details.
-
-               If you are not a blind person, or don't have access to
-               one of the listed synthesizers, you should say n.
-
-if SPEAKUP
-config SPEAKUP_SYNTH_ACNTSA
-       tristate "Accent SA synthesizer support"
-       help
-               This is the Speakup driver for the Accent SA
-               synthesizer.  You can say y to build it into the kernel,
-               or m to build it as a module.  See the configuration
-               help on the Speakup choice above for more info.
-
-config SPEAKUP_SYNTH_ACNTPC
-       tristate "Accent PC synthesizer support"
-       depends on ISA || COMPILE_TEST
-       help
-               This is the Speakup driver for the accent pc
-               synthesizer.  You can say y to build it into the kernel,
-               or m to build it as a module.  See the configuration
-               help on the Speakup choice above for more info.
-
-config SPEAKUP_SYNTH_APOLLO
-       tristate "Apollo II synthesizer support"
-       help
-               This is the Speakup driver for the Apollo II
-               synthesizer.  You can say y to build it into the kernel,
-               or m to build it as a module.  See the configuration
-               help on the Speakup choice above for more info.
-
-config SPEAKUP_SYNTH_AUDPTR
-       tristate "Audapter synthesizer support"
-       help
-               This is the Speakup driver for the Audapter synthesizer.
-                You can say y to build it into the kernel, or m to
-               build it as a module.  See the configuration help on the
-               Speakup choice above for more info.
-
-config SPEAKUP_SYNTH_BNS
-       tristate "Braille 'n' Speak synthesizer support"
-       help
-               This is the Speakup driver for the Braille 'n' Speak
-               synthesizer.  You can say y to build it into the kernel,
-               or m to build it as a module.  See the configuration
-               help on the Speakup choice above for more info.
-
-config SPEAKUP_SYNTH_DECTLK
-       tristate "DECtalk Express synthesizer support"
-       help
-
-               This is the Speakup driver for the DecTalk Express
-               synthesizer.  You can say y to build it into the kernel,
-               or m to build it as a module.  See the configuration
-               help on the Speakup choice above for more info.
-
-config SPEAKUP_SYNTH_DECEXT
-       tristate "DECtalk External (old) synthesizer support"
-       help
-
-               This is the Speakup driver for the DecTalk External
-               (old) synthesizer.  You can say y to build it into the
-               kernel, or m to build it as a module.  See the
-               configuration help on the Speakup choice above for more
-               info.
-
-config SPEAKUP_SYNTH_DECPC
-       depends on m
-       depends on ISA || COMPILE_TEST
-       tristate "DECtalk PC (big ISA card) synthesizer support"
-       help
-
-               This is the Speakup driver for the DecTalk PC (full
-               length ISA) synthesizer.  You can say m to build it as
-               a module.  See the configuration help on the Speakup
-               choice above for more info.
-
-               In order to use the DecTalk PC driver, you must download
-               the dec_pc.tgz file from linux-speakup.org.  It is in
-               the pub/linux/goodies directory.  The dec_pc.tgz file
-               contains the software which must be pre-loaded on to the
-               DecTalk PC board in order to use it with this driver.
-               This driver must be built as a module, and can not be
-               loaded until the file system is mounted and the DecTalk
-               PC software has been pre-loaded on to the board.
-
-               See the README file in the dec_pc.tgz file for more
-               details.
-
-config SPEAKUP_SYNTH_DTLK
-       tristate "DoubleTalk PC synthesizer support"
-       depends on ISA || COMPILE_TEST
-       help
-
-               This is the Speakup driver for the internal DoubleTalk
-               PC synthesizer.  You can say y to build it into the
-               kernel, or m to build it as a module.  See the
-               configuration help on the Speakup choice above for more
-               info.
-
-config SPEAKUP_SYNTH_KEYPC
-       tristate "Keynote Gold PC synthesizer support"
-       depends on ISA || COMPILE_TEST
-       help
-
-               This is the Speakup driver for the Keynote Gold
-               PC synthesizer.  You can say y to build it into the
-               kernel, or m to build it as a module.  See the
-               configuration help on the Speakup choice above for more
-               info.
-
-config SPEAKUP_SYNTH_LTLK
-       tristate "DoubleTalk LT/LiteTalk synthesizer support"
-help
-
-               This is the Speakup driver for the LiteTalk/DoubleTalk
-               LT synthesizer.  You can say y to build it into the
-               kernel, or m to build it as a module.  See the
-               configuration help on the Speakup choice above for more
-               info.
-
-config SPEAKUP_SYNTH_SOFT
-       tristate "Userspace software synthesizer support"
-       help
-
-               This is the software synthesizer device node.  It will
-               register a device /dev/softsynth which midware programs
-               and speech daemons may open and read to provide kernel
-               output to software synths such as espeak, festival,
-               flite and so forth.  You can select 'y' or 'm' to have
-               it built-in to the kernel or loaded as a module.
-
-config SPEAKUP_SYNTH_SPKOUT
-       tristate "Speak Out synthesizer support"
-       help
-
-               This is the Speakup driver for the Speakout synthesizer.
-                You can say y to build it into the kernel, or m to
-               build it as a module.  See the configuration help on the
-               Speakup choice above for more info.
-
-config SPEAKUP_SYNTH_TXPRT
-       tristate "Transport synthesizer support"
-       help
-
-               This is the Speakup driver for the Transport
-               synthesizer.  You can say y to build it into the kernel,
-               or m to build it as a module.  See the configuration
-               help on the Speakup choice above for more info.
-
-config SPEAKUP_SYNTH_DUMMY
-       tristate "Dummy synthesizer driver (for testing)"
-       help
-
-               This is a dummy Speakup driver for plugging a mere serial
-               terminal.  This is handy if you want to test speakup but
-               don't have the hardware.  You can say y to build it into
-               the kernel, or m to build it as a module.  See the
-               configuration help on the Speakup choice above for more info.
-
-endif  # SPEAKUP
-endmenu
diff --git a/drivers/staging/speakup/Makefile b/drivers/staging/speakup/Makefile
deleted file mode 100644 (file)
index 5befb49..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_SPEAKUP_SYNTH_ACNTSA) += speakup_acntsa.o
-obj-$(CONFIG_SPEAKUP_SYNTH_ACNTPC) += speakup_acntpc.o
-obj-$(CONFIG_SPEAKUP_SYNTH_APOLLO) += speakup_apollo.o
-obj-$(CONFIG_SPEAKUP_SYNTH_AUDPTR) += speakup_audptr.o
-obj-$(CONFIG_SPEAKUP_SYNTH_BNS) += speakup_bns.o
-obj-$(CONFIG_SPEAKUP_SYNTH_DECTLK) += speakup_dectlk.o
-obj-$(CONFIG_SPEAKUP_SYNTH_DECEXT) += speakup_decext.o
-obj-$(CONFIG_SPEAKUP_SYNTH_DECPC) += speakup_decpc.o
-obj-$(CONFIG_SPEAKUP_SYNTH_DTLK) += speakup_dtlk.o
-obj-$(CONFIG_SPEAKUP_SYNTH_KEYPC) += speakup_keypc.o
-obj-$(CONFIG_SPEAKUP_SYNTH_LTLK) += speakup_ltlk.o
-obj-$(CONFIG_SPEAKUP_SYNTH_SOFT) += speakup_soft.o
-obj-$(CONFIG_SPEAKUP_SYNTH_SPKOUT) += speakup_spkout.o
-obj-$(CONFIG_SPEAKUP_SYNTH_TXPRT) += speakup_txprt.o
-obj-$(CONFIG_SPEAKUP_SYNTH_DUMMY) += speakup_dummy.o
-
-obj-$(CONFIG_SPEAKUP) += speakup.o
-speakup-y := \
-       buffers.o \
-       devsynth.o \
-       i18n.o \
-       fakekey.o \
-       main.o \
-       keyhelp.o \
-       kobjects.o \
-       selection.o \
-       serialio.o \
-       spk_ttyio.o \
-       synth.o \
-       thread.o \
-       varhandlers.o
diff --git a/drivers/staging/speakup/TODO b/drivers/staging/speakup/TODO
deleted file mode 100644 (file)
index d4ca093..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Speakup project home:  http://www.linux-speakup.org
-
-Mailing List:  speakup@linux-speakup.org
-
-Speakup is a kernel based screen review package for the linux operating
-system.  It allows blind users to interact with applications on the
-linux console by means of synthetic speech.
-
-Currently, speakup has one issue we know of.
-
-It seems to only happen on SMP systems. It seems that text in the output buffer
-gets garbled because a lock is not set. This bug happens regularly, but no one
-has been able to find a situation which produces it consistently.
-
-Patches, suggestions, corrections, etc, are definitely welcome.
-
-We prefer that you contact us on the mailing list; however, if you do
-not want to subscribe to a mailing list, send your email to all of the
-following:
-
-okash.khawaja@gmail.com, w.d.hubbs@gmail.com, chris@the-brannons.com,
-kirk@reisers.ca and samuel.thibault@ens-lyon.org.
diff --git a/drivers/staging/speakup/buffers.c b/drivers/staging/speakup/buffers.c
deleted file mode 100644 (file)
index 1371ced..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/console.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-
-#include "speakup.h"
-#include "spk_priv.h"
-
-#define SYNTH_BUF_SIZE 8192    /* currently 8K bytes */
-
-static u16 synth_buffer[SYNTH_BUF_SIZE];       /* guess what this is for! */
-static u16 *buff_in = synth_buffer;
-static u16 *buff_out = synth_buffer;
-static u16 *buffer_end = synth_buffer + SYNTH_BUF_SIZE - 1;
-
-/* These try to throttle applications by stopping the TTYs
- * Note: we need to make sure that we will restart them eventually, which is
- * usually not possible to do from the notifiers. TODO: it should be possible
- * starting from linux 2.6.26.
- *
- * So we only stop when we know alive == 1 (else we discard the data anyway),
- * and the alive synth will eventually call start_ttys from the thread context.
- */
-void speakup_start_ttys(void)
-{
-       int i;
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (speakup_console[i] && speakup_console[i]->tty_stopped)
-                       continue;
-               if (vc_cons[i].d && vc_cons[i].d->port.tty)
-                       start_tty(vc_cons[i].d->port.tty);
-       }
-}
-EXPORT_SYMBOL_GPL(speakup_start_ttys);
-
-static void speakup_stop_ttys(void)
-{
-       int i;
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               if (vc_cons[i].d && vc_cons[i].d->port.tty)
-                       stop_tty(vc_cons[i].d->port.tty);
-}
-
-static int synth_buffer_free(void)
-{
-       int chars_free;
-
-       if (buff_in >= buff_out)
-               chars_free = SYNTH_BUF_SIZE - (buff_in - buff_out);
-       else
-               chars_free = buff_out - buff_in;
-       return chars_free;
-}
-
-int synth_buffer_empty(void)
-{
-       return (buff_in == buff_out);
-}
-EXPORT_SYMBOL_GPL(synth_buffer_empty);
-
-void synth_buffer_add(u16 ch)
-{
-       if (!synth->alive) {
-               /* This makes sure that we won't stop TTYs if there is no synth
-                * to restart them
-                */
-               return;
-       }
-       if (synth_buffer_free() <= 100) {
-               synth_start();
-               speakup_stop_ttys();
-       }
-       if (synth_buffer_free() <= 1)
-               return;
-       *buff_in++ = ch;
-       if (buff_in > buffer_end)
-               buff_in = synth_buffer;
-       /* We have written something to the speech synthesis, so we are not
-        * paused any more.
-        */
-       spk_paused = false;
-}
-
-u16 synth_buffer_getc(void)
-{
-       u16 ch;
-
-       if (buff_out == buff_in)
-               return 0;
-       ch = *buff_out++;
-       if (buff_out > buffer_end)
-               buff_out = synth_buffer;
-       return ch;
-}
-EXPORT_SYMBOL_GPL(synth_buffer_getc);
-
-u16 synth_buffer_peek(void)
-{
-       if (buff_out == buff_in)
-               return 0;
-       return *buff_out;
-}
-EXPORT_SYMBOL_GPL(synth_buffer_peek);
-
-void synth_buffer_skip_nonlatin1(void)
-{
-       while (buff_out != buff_in) {
-               if (*buff_out < 0x100)
-                       return;
-               buff_out++;
-               if (buff_out > buffer_end)
-                       buff_out = synth_buffer;
-       }
-}
-EXPORT_SYMBOL_GPL(synth_buffer_skip_nonlatin1);
-
-void synth_buffer_clear(void)
-{
-       buff_in = synth_buffer;
-       buff_out = synth_buffer;
-}
-EXPORT_SYMBOL_GPL(synth_buffer_clear);
diff --git a/drivers/staging/speakup/devsynth.c b/drivers/staging/speakup/devsynth.c
deleted file mode 100644 (file)
index d305716..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/errno.h>
-#include <linux/miscdevice.h>  /* for misc_register, and MISC_DYNAMIC_MINOR */
-#include <linux/types.h>
-#include <linux/uaccess.h>
-
-#include "speakup.h"
-#include "spk_priv.h"
-
-static int misc_registered;
-static int dev_opened;
-
-static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,
-                                 size_t nbytes, loff_t *ppos)
-{
-       size_t count = nbytes;
-       const char __user *ptr = buffer;
-       size_t bytes;
-       unsigned long flags;
-       u_char buf[256];
-
-       if (!synth)
-               return -ENODEV;
-       while (count > 0) {
-               bytes = min(count, sizeof(buf));
-               if (copy_from_user(buf, ptr, bytes))
-                       return -EFAULT;
-               count -= bytes;
-               ptr += bytes;
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               synth_write(buf, bytes);
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       }
-       return (ssize_t)nbytes;
-}
-
-static ssize_t speakup_file_read(struct file *fp, char __user *buf,
-                                size_t nbytes, loff_t *ppos)
-{
-       return 0;
-}
-
-static int speakup_file_open(struct inode *ip, struct file *fp)
-{
-       if (!synth)
-               return -ENODEV;
-       if (xchg(&dev_opened, 1))
-               return -EBUSY;
-       return 0;
-}
-
-static int speakup_file_release(struct inode *ip, struct file *fp)
-{
-       dev_opened = 0;
-       return 0;
-}
-
-static const struct file_operations synth_fops = {
-       .read = speakup_file_read,
-       .write = speakup_file_write,
-       .open = speakup_file_open,
-       .release = speakup_file_release,
-};
-
-static struct miscdevice synth_device = {
-       .minor = MISC_DYNAMIC_MINOR,
-       .name = "synth",
-       .fops = &synth_fops,
-};
-
-void speakup_register_devsynth(void)
-{
-       if (misc_registered != 0)
-               return;
-/* zero it so if register fails, deregister will not ref invalid ptrs */
-       if (misc_register(&synth_device)) {
-               pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
-       } else {
-               pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
-                       MISC_MAJOR, synth_device.minor);
-               misc_registered = 1;
-       }
-}
-
-void speakup_unregister_devsynth(void)
-{
-       if (!misc_registered)
-               return;
-       pr_info("speakup: unregistering synth device /dev/synth\n");
-       misc_deregister(&synth_device);
-       misc_registered = 0;
-}
diff --git a/drivers/staging/speakup/fakekey.c b/drivers/staging/speakup/fakekey.c
deleted file mode 100644 (file)
index cd02996..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/* fakekey.c
- * Functions for simulating keypresses.
- *
- * Copyright (C) 2010 the Speakup Team
- */
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/preempt.h>
-#include <linux/percpu.h>
-#include <linux/input.h>
-
-#include "speakup.h"
-
-#define PRESSED 1
-#define RELEASED 0
-
-static DEFINE_PER_CPU(int, reporting_keystroke);
-
-static struct input_dev *virt_keyboard;
-
-int speakup_add_virtual_keyboard(void)
-{
-       int err;
-
-       virt_keyboard = input_allocate_device();
-
-       if (!virt_keyboard)
-               return -ENOMEM;
-
-       virt_keyboard->name = "Speakup";
-       virt_keyboard->id.bustype = BUS_VIRTUAL;
-       virt_keyboard->phys = "speakup/input0";
-       virt_keyboard->dev.parent = NULL;
-
-       __set_bit(EV_KEY, virt_keyboard->evbit);
-       __set_bit(KEY_DOWN, virt_keyboard->keybit);
-
-       err = input_register_device(virt_keyboard);
-       if (err) {
-               input_free_device(virt_keyboard);
-               virt_keyboard = NULL;
-       }
-
-       return err;
-}
-
-void speakup_remove_virtual_keyboard(void)
-{
-       if (virt_keyboard) {
-               input_unregister_device(virt_keyboard);
-               virt_keyboard = NULL;
-       }
-}
-
-/*
- * Send a simulated down-arrow to the application.
- */
-void speakup_fake_down_arrow(void)
-{
-       unsigned long flags;
-
-       /* disable keyboard interrupts */
-       local_irq_save(flags);
-       /* don't change CPU */
-       preempt_disable();
-
-       __this_cpu_write(reporting_keystroke, true);
-       input_report_key(virt_keyboard, KEY_DOWN, PRESSED);
-       input_report_key(virt_keyboard, KEY_DOWN, RELEASED);
-       input_sync(virt_keyboard);
-       __this_cpu_write(reporting_keystroke, false);
-
-       /* reenable preemption */
-       preempt_enable();
-       /* reenable keyboard interrupts */
-       local_irq_restore(flags);
-}
-
-/*
- * Are we handling a simulated keypress on the current CPU?
- * Returns a boolean.
- */
-bool speakup_fake_key_pressed(void)
-{
-       return this_cpu_read(reporting_keystroke);
-}
diff --git a/drivers/staging/speakup/i18n.c b/drivers/staging/speakup/i18n.c
deleted file mode 100644 (file)
index ee240d3..0000000
+++ /dev/null
@@ -1,625 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Internationalization implementation.  Includes definitions of English
- * string arrays, and the i18n pointer.
- */
-
-#include <linux/slab.h>                /* For kmalloc. */
-#include <linux/ctype.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include "speakup.h"
-#include "spk_priv.h"
-
-static char *speakup_msgs[MSG_LAST_INDEX];
-static char *speakup_default_msgs[MSG_LAST_INDEX] = {
-       [MSG_BLANK] = "blank",
-       [MSG_IAM_ALIVE] = "I'm aLive!",
-       [MSG_YOU_KILLED_SPEAKUP] = "You killed speakup!",
-       [MSG_HEY_THATS_BETTER] = "hey. That's better!",
-       [MSG_YOU_TURNED_ME_OFF] = "You turned me off!",
-       [MSG_PARKED] = "parked!",
-       [MSG_UNPARKED] = "unparked!",
-       [MSG_MARK] = "mark",
-       [MSG_CUT] = "cut",
-       [MSG_MARK_CLEARED] = "mark, cleared",
-       [MSG_PASTE] = "paste",
-       [MSG_BRIGHT] = "bright",
-       [MSG_ON_BLINKING] = "on blinking",
-       [MSG_OFF] = "off",
-       [MSG_ON] = "on",
-       [MSG_NO_WINDOW] = "no window",
-       [MSG_CURSORING_OFF] = "cursoring off",
-       [MSG_CURSORING_ON] = "cursoring on",
-       [MSG_HIGHLIGHT_TRACKING] = "highlight tracking",
-       [MSG_READ_WINDOW] = "read windo",
-       [MSG_READ_ALL] = "read all",
-       [MSG_EDIT_DONE] = "edit done",
-       [MSG_WINDOW_ALREADY_SET] = "window already set, clear then reset",
-       [MSG_END_BEFORE_START] = "error end before start",
-       [MSG_WINDOW_CLEARED] = "window cleared",
-       [MSG_WINDOW_SILENCED] = "window silenced",
-       [MSG_WINDOW_SILENCE_DISABLED] = "window silence disabled",
-       [MSG_ERROR] = "error",
-       [MSG_GOTO_CANCELED] = "goto canceled",
-       [MSG_GOTO] = "go to?",
-       [MSG_LEAVING_HELP] = "leaving help",
-       [MSG_IS_UNASSIGNED] = "is unassigned",
-       [MSG_HELP_INFO] =
-       "press space to exit, up or down to scroll, or a letter to go to a command",
-       [MSG_EDGE_TOP] = "top,",
-       [MSG_EDGE_BOTTOM] = "bottom,",
-       [MSG_EDGE_LEFT] = "left,",
-       [MSG_EDGE_RIGHT] = "right,",
-       [MSG_NUMBER] = "number",
-       [MSG_SPACE] = "space",
-       [MSG_START] = "start",
-       [MSG_END] = "end",
-       [MSG_CTRL] = "control-",
-       [MSG_DISJUNCTION] = "or",
-
-/* Messages with embedded format specifiers. */
-       [MSG_POS_INFO] = "line %ld, col %ld, t t y %d",
-       [MSG_CHAR_INFO] = "hex %02x, decimal %d",
-       [MSG_REPEAT_DESC] = "times %d .",
-       [MSG_REPEAT_DESC2] = "repeated %d .",
-       [MSG_WINDOW_LINE] = "window is line %d",
-       [MSG_WINDOW_BOUNDARY] = "%s at line %d, column %d",
-       [MSG_EDIT_PROMPT] = "edit  %s, press space when done",
-       [MSG_NO_COMMAND] = "no commands for %c",
-       [MSG_KEYDESC] = "is %s",
-
-       /* Control keys. */
-       /* Most of these duplicate the entries in state names. */
-       [MSG_CTL_SHIFT] = "shift",
-       [MSG_CTL_ALTGR] = "altgr",
-       [MSG_CTL_CONTROL] = "control",
-       [MSG_CTL_ALT] = "alt",
-       [MSG_CTL_LSHIFT] = "l shift",
-       [MSG_CTL_SPEAKUP] = "speakup",
-       [MSG_CTL_LCONTROL] = "l control",
-       [MSG_CTL_RCONTROL] = "r control",
-       [MSG_CTL_CAPSSHIFT] = "caps shift",
-
-       /* Color names. */
-       [MSG_COLOR_BLACK] = "black",
-       [MSG_COLOR_BLUE] = "blue",
-       [MSG_COLOR_GREEN] = "green",
-       [MSG_COLOR_CYAN] = "cyan",
-       [MSG_COLOR_RED] = "red",
-       [MSG_COLOR_MAGENTA] = "magenta",
-       [MSG_COLOR_YELLOW] = "yellow",
-       [MSG_COLOR_WHITE] = "white",
-       [MSG_COLOR_GREY] = "grey",
-
-       /* Names of key states. */
-       [MSG_STATE_DOUBLE] = "double",
-       [MSG_STATE_SPEAKUP] = "speakup",
-       [MSG_STATE_ALT] = "alt",
-       [MSG_STATE_CONTROL] = "ctrl",
-       [MSG_STATE_ALTGR] = "altgr",
-       [MSG_STATE_SHIFT] = "shift",
-
-       /* Key names. */
-       [MSG_KEYNAME_ESC] = "escape",
-       [MSG_KEYNAME_1] = "1",
-       [MSG_KEYNAME_2] = "2",
-       [MSG_KEYNAME_3] = "3",
-       [MSG_KEYNAME_4] = "4",
-       [MSG_KEYNAME_5] = "5",
-       [MSG_KEYNAME_6] = "6",
-       [MSG_KEYNAME_7] = "7",
-       [MSG_KEYNAME_8] = "8",
-       [MSG_KEYNAME_9] = "9",
-       [MSG_KEYNAME_0] = "0",
-       [MSG_KEYNAME_DASH] = "minus",
-       [MSG_KEYNAME_EQUAL] = "equal",
-       [MSG_KEYNAME_BS] = "back space",
-       [MSG_KEYNAME_TAB] = "tab",
-       [MSG_KEYNAME_Q] = "q",
-       [MSG_KEYNAME_W] = "w",
-       [MSG_KEYNAME_E] = "e",
-       [MSG_KEYNAME_R] = "r",
-       [MSG_KEYNAME_T] = "t",
-       [MSG_KEYNAME_Y] = "y",
-       [MSG_KEYNAME_U] = "u",
-       [MSG_KEYNAME_I] = "i",
-       [MSG_KEYNAME_O] = "o",
-       [MSG_KEYNAME_P] = "p",
-       [MSG_KEYNAME_LEFTBRACE] = "left brace",
-       [MSG_KEYNAME_RIGHTBRACE] = "right brace",
-       [MSG_KEYNAME_ENTER] = "enter",
-       [MSG_KEYNAME_LEFTCTRL] = "left control",
-       [MSG_KEYNAME_A] = "a",
-       [MSG_KEYNAME_S] = "s",
-       [MSG_KEYNAME_D] = "d",
-       [MSG_KEYNAME_F] = "f",
-       [MSG_KEYNAME_G] = "g",
-       [MSG_KEYNAME_H] = "h",
-       [MSG_KEYNAME_J] = "j",
-       [MSG_KEYNAME_K] = "k",
-       [MSG_KEYNAME_L] = "l",
-       [MSG_KEYNAME_SEMICOLON] = "semicolon",
-       [MSG_KEYNAME_SINGLEQUOTE] = "apostrophe",
-       [MSG_KEYNAME_GRAVE] = "accent",
-       [MSG_KEYNAME_LEFTSHFT] = "left shift",
-       [MSG_KEYNAME_BACKSLASH] = "back slash",
-       [MSG_KEYNAME_Z] = "z",
-       [MSG_KEYNAME_X] = "x",
-       [MSG_KEYNAME_C] = "c",
-       [MSG_KEYNAME_V] = "v",
-       [MSG_KEYNAME_B] = "b",
-       [MSG_KEYNAME_N] = "n",
-       [MSG_KEYNAME_M] = "m",
-       [MSG_KEYNAME_COMMA] = "comma",
-       [MSG_KEYNAME_DOT] = "dot",
-       [MSG_KEYNAME_SLASH] = "slash",
-       [MSG_KEYNAME_RIGHTSHFT] = "right shift",
-       [MSG_KEYNAME_KPSTAR] = "keypad asterisk",
-       [MSG_KEYNAME_LEFTALT] = "left alt",
-       [MSG_KEYNAME_SPACE] = "space",
-       [MSG_KEYNAME_CAPSLOCK] = "caps lock",
-       [MSG_KEYNAME_F1] = "f1",
-       [MSG_KEYNAME_F2] = "f2",
-       [MSG_KEYNAME_F3] = "f3",
-       [MSG_KEYNAME_F4] = "f4",
-       [MSG_KEYNAME_F5] = "f5",
-       [MSG_KEYNAME_F6] = "f6",
-       [MSG_KEYNAME_F7] = "f7",
-       [MSG_KEYNAME_F8] = "f8",
-       [MSG_KEYNAME_F9] = "f9",
-       [MSG_KEYNAME_F10] = "f10",
-       [MSG_KEYNAME_NUMLOCK] = "num lock",
-       [MSG_KEYNAME_SCROLLLOCK] = "scroll lock",
-       [MSG_KEYNAME_KP7] = "keypad 7",
-       [MSG_KEYNAME_KP8] = "keypad 8",
-       [MSG_KEYNAME_KP9] = "keypad 9",
-       [MSG_KEYNAME_KPMINUS] = "keypad minus",
-       [MSG_KEYNAME_KP4] = "keypad 4",
-       [MSG_KEYNAME_KP5] = "keypad 5",
-       [MSG_KEYNAME_KP6] = "keypad 6",
-       [MSG_KEYNAME_KPPLUS] = "keypad plus",
-       [MSG_KEYNAME_KP1] = "keypad 1",
-       [MSG_KEYNAME_KP2] = "keypad 2",
-       [MSG_KEYNAME_KP3] = "keypad 3",
-       [MSG_KEYNAME_KP0] = "keypad 0",
-       [MSG_KEYNAME_KPDOT] = "keypad dot",
-       [MSG_KEYNAME_103RD] = "103rd",
-       [MSG_KEYNAME_F13] = "f13",
-       [MSG_KEYNAME_102ND] = "102nd",
-       [MSG_KEYNAME_F11] = "f11",
-       [MSG_KEYNAME_F12] = "f12",
-       [MSG_KEYNAME_F14] = "f14",
-       [MSG_KEYNAME_F15] = "f15",
-       [MSG_KEYNAME_F16] = "f16",
-       [MSG_KEYNAME_F17] = "f17",
-       [MSG_KEYNAME_F18] = "f18",
-       [MSG_KEYNAME_F19] = "f19",
-       [MSG_KEYNAME_F20] = "f20",
-       [MSG_KEYNAME_KPENTER] = "keypad enter",
-       [MSG_KEYNAME_RIGHTCTRL] = "right control",
-       [MSG_KEYNAME_KPSLASH] = "keypad slash",
-       [MSG_KEYNAME_SYSRQ] = "sysrq",
-       [MSG_KEYNAME_RIGHTALT] = "right alt",
-       [MSG_KEYNAME_LF] = "line feed",
-       [MSG_KEYNAME_HOME] = "home",
-       [MSG_KEYNAME_UP] = "up",
-       [MSG_KEYNAME_PGUP] = "page up",
-       [MSG_KEYNAME_LEFT] = "left",
-       [MSG_KEYNAME_RIGHT] = "right",
-       [MSG_KEYNAME_END] = "end",
-       [MSG_KEYNAME_DOWN] = "down",
-       [MSG_KEYNAME_PGDN] = "page down",
-       [MSG_KEYNAME_INS] = "insert",
-       [MSG_KEYNAME_DEL] = "delete",
-       [MSG_KEYNAME_MACRO] = "macro",
-       [MSG_KEYNAME_MUTE] = "mute",
-       [MSG_KEYNAME_VOLDOWN] = "volume down",
-       [MSG_KEYNAME_VOLUP] = "volume up",
-       [MSG_KEYNAME_POWER] = "power",
-       [MSG_KEYNAME_KPEQUAL] = "keypad equal",
-       [MSG_KEYNAME_KPPLUSDASH] = "keypad plusminus",
-       [MSG_KEYNAME_PAUSE] = "pause",
-       [MSG_KEYNAME_F21] = "f21",
-       [MSG_KEYNAME_F22] = "f22",
-       [MSG_KEYNAME_F23] = "f23",
-       [MSG_KEYNAME_F24] = "f24",
-       [MSG_KEYNAME_KPCOMMA] = "keypad comma",
-       [MSG_KEYNAME_LEFTMETA] = "left meta",
-       [MSG_KEYNAME_RIGHTMETA] = "right meta",
-       [MSG_KEYNAME_COMPOSE] = "compose",
-       [MSG_KEYNAME_STOP] = "stop",
-       [MSG_KEYNAME_AGAIN] = "again",
-       [MSG_KEYNAME_PROPS] = "props",
-       [MSG_KEYNAME_UNDO] = "undo",
-       [MSG_KEYNAME_FRONT] = "front",
-       [MSG_KEYNAME_COPY] = "copy",
-       [MSG_KEYNAME_OPEN] = "open",
-       [MSG_KEYNAME_PASTE] = "paste",
-       [MSG_KEYNAME_FIND] = "find",
-       [MSG_KEYNAME_CUT] = "cut",
-       [MSG_KEYNAME_HELP] = "help",
-       [MSG_KEYNAME_MENU] = "menu",
-       [MSG_KEYNAME_CALC] = "calc",
-       [MSG_KEYNAME_SETUP] = "setup",
-       [MSG_KEYNAME_SLEEP] = "sleep",
-       [MSG_KEYNAME_WAKEUP] = "wakeup",
-       [MSG_KEYNAME_FILE] = "file",
-       [MSG_KEYNAME_SENDFILE] = "send file",
-       [MSG_KEYNAME_DELFILE] = "delete file",
-       [MSG_KEYNAME_XFER] = "transfer",
-       [MSG_KEYNAME_PROG1] = "prog1",
-       [MSG_KEYNAME_PROG2] = "prog2",
-       [MSG_KEYNAME_WWW] = "www",
-       [MSG_KEYNAME_MSDOS] = "msdos",
-       [MSG_KEYNAME_COFFEE] = "coffee",
-       [MSG_KEYNAME_DIRECTION] = "direction",
-       [MSG_KEYNAME_CYCLEWINDOWS] = "cycle windows",
-       [MSG_KEYNAME_MAIL] = "mail",
-       [MSG_KEYNAME_BOOKMARKS] = "bookmarks",
-       [MSG_KEYNAME_COMPUTER] = "computer",
-       [MSG_KEYNAME_BACK] = "back",
-       [MSG_KEYNAME_FORWARD] = "forward",
-       [MSG_KEYNAME_CLOSECD] = "close cd",
-       [MSG_KEYNAME_EJECTCD] = "eject cd",
-       [MSG_KEYNAME_EJECTCLOSE] = "eject close cd",
-       [MSG_KEYNAME_NEXTSONG] = "next song",
-       [MSG_KEYNAME_PLAYPAUSE] = "play pause",
-       [MSG_KEYNAME_PREVSONG] = "previous song",
-       [MSG_KEYNAME_STOPCD] = "stop cd",
-       [MSG_KEYNAME_RECORD] = "record",
-       [MSG_KEYNAME_REWIND] = "rewind",
-       [MSG_KEYNAME_PHONE] = "phone",
-       [MSG_KEYNAME_ISO] = "iso",
-       [MSG_KEYNAME_CONFIG] = "config",
-       [MSG_KEYNAME_HOMEPG] = "home page",
-       [MSG_KEYNAME_REFRESH] = "refresh",
-       [MSG_KEYNAME_EXIT] = "exit",
-       [MSG_KEYNAME_MOVE] = "move",
-       [MSG_KEYNAME_EDIT] = "edit",
-       [MSG_KEYNAME_SCROLLUP] = "scroll up",
-       [MSG_KEYNAME_SCROLLDN] = "scroll down",
-       [MSG_KEYNAME_KPLEFTPAR] = "keypad left paren",
-       [MSG_KEYNAME_KPRIGHTPAR] = "keypad right paren",
-
-       /* Function names. */
-       [MSG_FUNCNAME_ATTRIB_BLEEP_DEC] = "attribute bleep decrement",
-       [MSG_FUNCNAME_ATTRIB_BLEEP_INC] = "attribute bleep increment",
-       [MSG_FUNCNAME_BLEEPS_DEC] = "bleeps decrement",
-       [MSG_FUNCNAME_BLEEPS_INC] = "bleeps increment",
-       [MSG_FUNCNAME_CHAR_FIRST] = "character, first",
-       [MSG_FUNCNAME_CHAR_LAST] = "character, last",
-       [MSG_FUNCNAME_CHAR_CURRENT] = "character, say current",
-       [MSG_FUNCNAME_CHAR_HEX_AND_DEC] = "character, say hex and decimal",
-       [MSG_FUNCNAME_CHAR_NEXT] = "character, say next",
-       [MSG_FUNCNAME_CHAR_PHONETIC] = "character, say phonetic",
-       [MSG_FUNCNAME_CHAR_PREVIOUS] = "character, say previous",
-       [MSG_FUNCNAME_CURSOR_PARK] = "cursor park",
-       [MSG_FUNCNAME_CUT] = "cut",
-       [MSG_FUNCNAME_EDIT_DELIM] = "edit delimiters",
-       [MSG_FUNCNAME_EDIT_EXNUM] = "edit exnum",
-       [MSG_FUNCNAME_EDIT_MOST] = "edit most",
-       [MSG_FUNCNAME_EDIT_REPEATS] = "edit repeats",
-       [MSG_FUNCNAME_EDIT_SOME] = "edit some",
-       [MSG_FUNCNAME_GOTO] = "go to",
-       [MSG_FUNCNAME_GOTO_BOTTOM] = "go to bottom edge",
-       [MSG_FUNCNAME_GOTO_LEFT] = "go to left edge",
-       [MSG_FUNCNAME_GOTO_RIGHT] = "go to right edge",
-       [MSG_FUNCNAME_GOTO_TOP] = "go to top edge",
-       [MSG_FUNCNAME_HELP] = "help",
-       [MSG_FUNCNAME_LINE_SAY_CURRENT] = "line, say current",
-       [MSG_FUNCNAME_LINE_SAY_NEXT] = "line, say next",
-       [MSG_FUNCNAME_LINE_SAY_PREVIOUS] = "line, say previous",
-       [MSG_FUNCNAME_LINE_SAY_WITH_INDENT] = "line, say with indent",
-       [MSG_FUNCNAME_PASTE] = "paste",
-       [MSG_FUNCNAME_PITCH_DEC] = "pitch decrement",
-       [MSG_FUNCNAME_PITCH_INC] = "pitch increment",
-       [MSG_FUNCNAME_PUNC_DEC] = "punctuation decrement",
-       [MSG_FUNCNAME_PUNC_INC] = "punctuation increment",
-       [MSG_FUNCNAME_PUNC_LEVEL_DEC] = "punc level decrement",
-       [MSG_FUNCNAME_PUNC_LEVEL_INC] = "punc level increment",
-       [MSG_FUNCNAME_QUIET] = "quiet",
-       [MSG_FUNCNAME_RATE_DEC] = "rate decrement",
-       [MSG_FUNCNAME_RATE_INC] = "rate increment",
-       [MSG_FUNCNAME_READING_PUNC_DEC] = "reading punctuation decrement",
-       [MSG_FUNCNAME_READING_PUNC_INC] = "reading punctuation increment",
-       [MSG_FUNCNAME_SAY_ATTRIBUTES] = "say attributes",
-       [MSG_FUNCNAME_SAY_FROM_LEFT] = "say from left",
-       [MSG_FUNCNAME_SAY_FROM_TOP] = "say from top",
-       [MSG_FUNCNAME_SAY_POSITION] = "say position",
-       [MSG_FUNCNAME_SAY_SCREEN] = "say screen",
-       [MSG_FUNCNAME_SAY_TO_BOTTOM] = "say to bottom",
-       [MSG_FUNCNAME_SAY_TO_RIGHT] = "say to right",
-       [MSG_FUNCNAME_SPEAKUP] = "speakup",
-       [MSG_FUNCNAME_SPEAKUP_LOCK] = "speakup lock",
-       [MSG_FUNCNAME_SPEAKUP_OFF] = "speakup off",
-       [MSG_FUNCNAME_SPEECH_KILL] = "speech kill",
-       [MSG_FUNCNAME_SPELL_DELAY_DEC] = "spell delay decrement",
-       [MSG_FUNCNAME_SPELL_DELAY_INC] = "spell delay increment",
-       [MSG_FUNCNAME_SPELL_WORD] = "spell word",
-       [MSG_FUNCNAME_SPELL_WORD_PHONETICALLY] = "spell word phonetically",
-       [MSG_FUNCNAME_TONE_DEC] = "tone decrement",
-       [MSG_FUNCNAME_TONE_INC] = "tone increment",
-       [MSG_FUNCNAME_VOICE_DEC] = "voice decrement",
-       [MSG_FUNCNAME_VOICE_INC] = "voice increment",
-       [MSG_FUNCNAME_VOLUME_DEC] = "volume decrement",
-       [MSG_FUNCNAME_VOLUME_INC] = "volume increment",
-       [MSG_FUNCNAME_WINDOW_CLEAR] = "window, clear",
-       [MSG_FUNCNAME_WINDOW_SAY] = "window, say",
-       [MSG_FUNCNAME_WINDOW_SET] = "window, set",
-       [MSG_FUNCNAME_WINDOW_SILENCE] = "window, silence",
-       [MSG_FUNCNAME_WORD_SAY_CURRENT] = "word, say current",
-       [MSG_FUNCNAME_WORD_SAY_NEXT] = "word, say next",
-       [MSG_FUNCNAME_WORD_SAY_PREVIOUS] = "word, say previous",
-};
-
-static struct msg_group_t all_groups[] = {
-       {
-               .name = "ctl_keys",
-               .start = MSG_CTL_START,
-               .end = MSG_CTL_END,
-       },
-       {
-               .name = "colors",
-               .start = MSG_COLORS_START,
-               .end = MSG_COLORS_END,
-       },
-       {
-               .name = "formatted",
-               .start = MSG_FORMATTED_START,
-               .end = MSG_FORMATTED_END,
-       },
-       {
-               .name = "function_names",
-               .start = MSG_FUNCNAMES_START,
-               .end = MSG_FUNCNAMES_END,
-       },
-       {
-               .name = "key_names",
-               .start = MSG_KEYNAMES_START,
-               .end = MSG_KEYNAMES_END,
-       },
-       {
-               .name = "announcements",
-               .start = MSG_ANNOUNCEMENTS_START,
-               .end = MSG_ANNOUNCEMENTS_END,
-       },
-       {
-               .name = "states",
-               .start = MSG_STATES_START,
-               .end = MSG_STATES_END,
-       },
-};
-
-static const  int num_groups = ARRAY_SIZE(all_groups);
-
-char *spk_msg_get(enum msg_index_t index)
-{
-       return speakup_msgs[index];
-}
-
-/*
- * Function: next_specifier
- * Finds the start of the next format specifier in the argument string.
- * Return value: pointer to start of format
- * specifier, or NULL if no specifier exists.
- */
-static char *next_specifier(char *input)
-{
-       int found = 0;
-       char *next_percent = input;
-
-       while (next_percent && !found) {
-               next_percent = strchr(next_percent, '%');
-               if (next_percent) {
-                       /* skip over doubled percent signs */
-                       while (next_percent[0] == '%' &&
-                              next_percent[1] == '%')
-                               next_percent += 2;
-                       if (*next_percent == '%')
-                               found = 1;
-                       else if (*next_percent == '\0')
-                               next_percent = NULL;
-               }
-       }
-
-       return next_percent;
-}
-
-/* Skip over 0 or more flags. */
-static char *skip_flags(char *input)
-{
-       while ((*input != '\0') && strchr(" 0+-#", *input))
-               input++;
-       return input;
-}
-
-/* Skip over width.precision, if it exists. */
-static char *skip_width(char *input)
-{
-       while (isdigit(*input))
-               input++;
-       if (*input == '.') {
-               input++;
-               while (isdigit(*input))
-                       input++;
-       }
-       return input;
-}
-
-/*
- * Skip past the end of the conversion part.
- * Note that this code only accepts a handful of conversion specifiers:
- * c d s x and ld.  Not accidental; these are exactly the ones used in
- * the default group of formatted messages.
- */
-static char *skip_conversion(char *input)
-{
-       if ((input[0] == 'l') && (input[1] == 'd'))
-               input += 2;
-       else if ((*input != '\0') && strchr("cdsx", *input))
-               input++;
-       return input;
-}
-
-/*
- * Function: find_specifier_end
- * Return a pointer to the end of the format specifier.
- */
-static char *find_specifier_end(char *input)
-{
-       input++;                /* Advance over %. */
-       input = skip_flags(input);
-       input = skip_width(input);
-       input = skip_conversion(input);
-       return input;
-}
-
-/*
- * Function: compare_specifiers
- * Compare the format specifiers pointed to by *input1 and *input2.
- * Return true if they are the same, false otherwise.
- * Advance *input1 and *input2 so that they point to the character following
- * the end of the specifier.
- */
-static bool compare_specifiers(char **input1, char **input2)
-{
-       bool same = false;
-       char *end1 = find_specifier_end(*input1);
-       char *end2 = find_specifier_end(*input2);
-       size_t length1 = end1 - *input1;
-       size_t length2 = end2 - *input2;
-
-       if ((length1 == length2) && !memcmp(*input1, *input2, length1))
-               same = true;
-
-       *input1 = end1;
-       *input2 = end2;
-       return same;
-}
-
-/*
- * Function: fmt_validate
- * Check that two format strings contain the same number of format specifiers,
- * and that the order of specifiers is the same in both strings.
- * Return true if the condition holds, false if it doesn't.
- */
-static bool fmt_validate(char *template, char *user)
-{
-       bool valid = true;
-       bool still_comparing = true;
-       char *template_ptr = template;
-       char *user_ptr = user;
-
-       while (still_comparing && valid) {
-               template_ptr = next_specifier(template_ptr);
-               user_ptr = next_specifier(user_ptr);
-               if (template_ptr && user_ptr) {
-                       /* Both have at least one more specifier. */
-                       valid = compare_specifiers(&template_ptr, &user_ptr);
-               } else {
-                       /* No more format specifiers in one or both strings. */
-                       still_comparing = false;
-                       /* See if one has more specifiers than the other. */
-                       if (template_ptr || user_ptr)
-                               valid = false;
-               }
-       }
-       return valid;
-}
-
-/*
- * Function: msg_set
- * Description: Add a user-supplied message to the user_messages array.
- * The message text is copied to a memory area allocated with kmalloc.
- * If the function fails, then user_messages is untouched.
- * Arguments:
- * - index: a message number, as found in i18n.h.
- * - text:  text of message.  Not NUL-terminated.
- * - length: number of bytes in text.
- * Failure conditions:
- * -EINVAL -  Invalid format specifiers in formatted message or illegal index.
- * -ENOMEM -  Unable to allocate memory.
- */
-ssize_t spk_msg_set(enum msg_index_t index, char *text, size_t length)
-{
-       char *newstr = NULL;
-       unsigned long flags;
-
-       if ((index < MSG_FIRST_INDEX) || (index >= MSG_LAST_INDEX))
-               return -EINVAL;
-
-       newstr = kmalloc(length + 1, GFP_KERNEL);
-       if (!newstr)
-               return -ENOMEM;
-
-       memcpy(newstr, text, length);
-       newstr[length] = '\0';
-       if (index >= MSG_FORMATTED_START &&
-           index <= MSG_FORMATTED_END &&
-           !fmt_validate(speakup_default_msgs[index], newstr)) {
-               kfree(newstr);
-               return -EINVAL;
-       }
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       if (speakup_msgs[index] != speakup_default_msgs[index])
-               kfree(speakup_msgs[index]);
-       speakup_msgs[index] = newstr;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return 0;
-}
-
-/*
- * Find a message group, given its name.  Return a pointer to the structure
- * if found, or NULL otherwise.
- */
-struct msg_group_t *spk_find_msg_group(const char *group_name)
-{
-       struct msg_group_t *group = NULL;
-       int i;
-
-       for (i = 0; i < num_groups; i++) {
-               if (!strcmp(all_groups[i].name, group_name)) {
-                       group = &all_groups[i];
-                       break;
-               }
-       }
-       return group;
-}
-
-void spk_reset_msg_group(struct msg_group_t *group)
-{
-       unsigned long flags;
-       enum msg_index_t i;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-
-       for (i = group->start; i <= group->end; i++) {
-               if (speakup_msgs[i] != speakup_default_msgs[i])
-                       kfree(speakup_msgs[i]);
-               speakup_msgs[i] = speakup_default_msgs[i];
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-}
-
-/* Called at initialization time, to establish default messages. */
-void spk_initialize_msgs(void)
-{
-       memcpy(speakup_msgs, speakup_default_msgs,
-              sizeof(speakup_default_msgs));
-}
-
-/* Free user-supplied strings when module is unloaded: */
-void spk_free_user_msgs(void)
-{
-       enum msg_index_t index;
-       unsigned long flags;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       for (index = MSG_FIRST_INDEX; index < MSG_LAST_INDEX; index++) {
-               if (speakup_msgs[index] != speakup_default_msgs[index]) {
-                       kfree(speakup_msgs[index]);
-                       speakup_msgs[index] = speakup_default_msgs[index];
-               }
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-}
diff --git a/drivers/staging/speakup/i18n.h b/drivers/staging/speakup/i18n.h
deleted file mode 100644 (file)
index 2ec6e65..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef I18N_H
-#define I18N_H
-/* Internationalization declarations */
-
-enum msg_index_t {
-       MSG_FIRST_INDEX,
-       MSG_ANNOUNCEMENTS_START = MSG_FIRST_INDEX,
-       MSG_BLANK = MSG_ANNOUNCEMENTS_START,
-       MSG_IAM_ALIVE,
-       MSG_YOU_KILLED_SPEAKUP,
-       MSG_HEY_THATS_BETTER,
-       MSG_YOU_TURNED_ME_OFF,
-       MSG_PARKED,
-       MSG_UNPARKED,
-       MSG_MARK,
-       MSG_CUT,
-       MSG_MARK_CLEARED,
-       MSG_PASTE,
-       MSG_BRIGHT,
-       MSG_ON_BLINKING,
-       MSG_STATUS_START,
-       MSG_OFF = MSG_STATUS_START,
-       MSG_ON,
-       MSG_NO_WINDOW,
-       MSG_CURSOR_MSGS_START,
-       MSG_CURSORING_OFF = MSG_CURSOR_MSGS_START,
-       MSG_CURSORING_ON,
-       MSG_HIGHLIGHT_TRACKING,
-       MSG_READ_WINDOW,
-       MSG_READ_ALL,
-       MSG_EDIT_DONE,
-       MSG_WINDOW_ALREADY_SET,
-       MSG_END_BEFORE_START,
-       MSG_WINDOW_CLEARED,
-       MSG_WINDOW_SILENCED,
-       MSG_WINDOW_SILENCE_DISABLED,
-       MSG_ERROR,
-       MSG_GOTO_CANCELED,
-       MSG_GOTO,
-       MSG_LEAVING_HELP,
-       MSG_IS_UNASSIGNED,
-       MSG_HELP_INFO,
-       MSG_EDGE_MSGS_START,
-       MSG_EDGE_TOP  = MSG_EDGE_MSGS_START,
-       MSG_EDGE_BOTTOM,
-       MSG_EDGE_LEFT,
-       MSG_EDGE_RIGHT,
-       MSG_NUMBER,
-       MSG_SPACE,
-       MSG_START, /* A little confusing, given our convention. */
-       MSG_END, /* A little confusing, given our convention. */
-       MSG_CTRL,
-
-/* A message containing the single word "or". */
-       MSG_DISJUNCTION,
-       MSG_ANNOUNCEMENTS_END = MSG_DISJUNCTION,
-
-/* Messages with format specifiers. */
-       MSG_FORMATTED_START,
-       MSG_POS_INFO = MSG_FORMATTED_START,
-       MSG_CHAR_INFO,
-       MSG_REPEAT_DESC,
-       MSG_REPEAT_DESC2,
-       MSG_WINDOW_LINE,
-       MSG_WINDOW_BOUNDARY,
-       MSG_EDIT_PROMPT,
-       MSG_NO_COMMAND,
-       MSG_KEYDESC,
-       MSG_FORMATTED_END = MSG_KEYDESC,
-
-       /* Control keys. */
-       MSG_CTL_START,
-       MSG_CTL_SHIFT = MSG_CTL_START,
-       MSG_CTL_ALTGR,
-       MSG_CTL_CONTROL,
-       MSG_CTL_ALT,
-       MSG_CTL_LSHIFT,
-       MSG_CTL_SPEAKUP,
-       MSG_CTL_LCONTROL,
-       MSG_CTL_RCONTROL,
-       MSG_CTL_CAPSSHIFT,
-       MSG_CTL_END = MSG_CTL_CAPSSHIFT,
-
-       /* Colors. */
-       MSG_COLORS_START,
-       MSG_COLOR_BLACK = MSG_COLORS_START,
-       MSG_COLOR_BLUE,
-       MSG_COLOR_GREEN,
-       MSG_COLOR_CYAN,
-       MSG_COLOR_RED,
-       MSG_COLOR_MAGENTA,
-       MSG_COLOR_YELLOW,
-       MSG_COLOR_WHITE,
-       MSG_COLOR_GREY,
-       MSG_COLORS_END = MSG_COLOR_GREY,
-
-       MSG_STATES_START,
-       MSG_STATE_DOUBLE = MSG_STATES_START,
-       MSG_STATE_SPEAKUP,
-       MSG_STATE_ALT,
-       MSG_STATE_CONTROL,
-       MSG_STATE_ALTGR,
-       MSG_STATE_SHIFT,
-       MSG_STATES_END = MSG_STATE_SHIFT,
-
-       MSG_KEYNAMES_START,
-       MSG_KEYNAME_ESC = MSG_KEYNAMES_START,
-       MSG_KEYNAME_1, MSG_KEYNAME_2, MSG_KEYNAME_3, MSG_KEYNAME_4,
-       MSG_KEYNAME_5, MSG_KEYNAME_6, MSG_KEYNAME_7, MSG_KEYNAME_8,
-       MSG_KEYNAME_9,
-       MSG_KEYNAME_0, MSG_KEYNAME_DASH, MSG_KEYNAME_EQUAL, MSG_KEYNAME_BS,
-       MSG_KEYNAME_TAB,
-       MSG_KEYNAME_Q, MSG_KEYNAME_W, MSG_KEYNAME_E, MSG_KEYNAME_R,
-       MSG_KEYNAME_T, MSG_KEYNAME_Y, MSG_KEYNAME_U, MSG_KEYNAME_I,
-       MSG_KEYNAME_O, MSG_KEYNAME_P,
-       MSG_KEYNAME_LEFTBRACE, MSG_KEYNAME_RIGHTBRACE, MSG_KEYNAME_ENTER,
-       MSG_KEYNAME_LEFTCTRL, MSG_KEYNAME_A,
-       MSG_KEYNAME_S, MSG_KEYNAME_D, MSG_KEYNAME_F, MSG_KEYNAME_G,
-       MSG_KEYNAME_H, MSG_KEYNAME_J, MSG_KEYNAME_K, MSG_KEYNAME_L,
-       MSG_KEYNAME_SEMICOLON,
-       MSG_KEYNAME_SINGLEQUOTE, MSG_KEYNAME_GRAVE,
-       MSG_KEYNAME_LEFTSHFT, MSG_KEYNAME_BACKSLASH, MSG_KEYNAME_Z,
-       MSG_KEYNAME_X, MSG_KEYNAME_C, MSG_KEYNAME_V, MSG_KEYNAME_B,
-       MSG_KEYNAME_N, MSG_KEYNAME_M, MSG_KEYNAME_COMMA, MSG_KEYNAME_DOT,
-       MSG_KEYNAME_SLASH, MSG_KEYNAME_RIGHTSHFT,
-       MSG_KEYNAME_KPSTAR,
-       MSG_KEYNAME_LEFTALT, MSG_KEYNAME_SPACE, MSG_KEYNAME_CAPSLOCK,
-       MSG_KEYNAME_F1, MSG_KEYNAME_F2,
-       MSG_KEYNAME_F3, MSG_KEYNAME_F4, MSG_KEYNAME_F5, MSG_KEYNAME_F6,
-       MSG_KEYNAME_F7,
-       MSG_KEYNAME_F8, MSG_KEYNAME_F9, MSG_KEYNAME_F10, MSG_KEYNAME_NUMLOCK,
-       MSG_KEYNAME_SCROLLLOCK,
-       MSG_KEYNAME_KP7, MSG_KEYNAME_KP8, MSG_KEYNAME_KP9, MSG_KEYNAME_KPMINUS,
-       MSG_KEYNAME_KP4,
-       MSG_KEYNAME_KP5, MSG_KEYNAME_KP6, MSG_KEYNAME_KPPLUS, MSG_KEYNAME_KP1,
-       MSG_KEYNAME_KP2,
-       MSG_KEYNAME_KP3, MSG_KEYNAME_KP0, MSG_KEYNAME_KPDOT, MSG_KEYNAME_103RD,
-       MSG_KEYNAME_F13,
-       MSG_KEYNAME_102ND, MSG_KEYNAME_F11, MSG_KEYNAME_F12, MSG_KEYNAME_F14,
-       MSG_KEYNAME_F15,
-       MSG_KEYNAME_F16, MSG_KEYNAME_F17, MSG_KEYNAME_F18, MSG_KEYNAME_F19,
-       MSG_KEYNAME_F20,
-       MSG_KEYNAME_KPENTER, MSG_KEYNAME_RIGHTCTRL, MSG_KEYNAME_KPSLASH,
-       MSG_KEYNAME_SYSRQ, MSG_KEYNAME_RIGHTALT,
-       MSG_KEYNAME_LF, MSG_KEYNAME_HOME, MSG_KEYNAME_UP, MSG_KEYNAME_PGUP,
-       MSG_KEYNAME_LEFT,
-       MSG_KEYNAME_RIGHT, MSG_KEYNAME_END, MSG_KEYNAME_DOWN, MSG_KEYNAME_PGDN,
-       MSG_KEYNAME_INS,
-       MSG_KEYNAME_DEL, MSG_KEYNAME_MACRO, MSG_KEYNAME_MUTE,
-       MSG_KEYNAME_VOLDOWN, MSG_KEYNAME_VOLUP,
-       MSG_KEYNAME_POWER, MSG_KEYNAME_KPEQUAL, MSG_KEYNAME_KPPLUSDASH,
-       MSG_KEYNAME_PAUSE, MSG_KEYNAME_F21, MSG_KEYNAME_F22, MSG_KEYNAME_F23,
-       MSG_KEYNAME_F24, MSG_KEYNAME_KPCOMMA, MSG_KEYNAME_LEFTMETA,
-       MSG_KEYNAME_RIGHTMETA, MSG_KEYNAME_COMPOSE, MSG_KEYNAME_STOP,
-       MSG_KEYNAME_AGAIN, MSG_KEYNAME_PROPS,
-       MSG_KEYNAME_UNDO, MSG_KEYNAME_FRONT, MSG_KEYNAME_COPY, MSG_KEYNAME_OPEN,
-       MSG_KEYNAME_PASTE,
-       MSG_KEYNAME_FIND, MSG_KEYNAME_CUT, MSG_KEYNAME_HELP, MSG_KEYNAME_MENU,
-       MSG_KEYNAME_CALC,
-       MSG_KEYNAME_SETUP, MSG_KEYNAME_SLEEP, MSG_KEYNAME_WAKEUP,
-       MSG_KEYNAME_FILE, MSG_KEYNAME_SENDFILE,
-       MSG_KEYNAME_DELFILE, MSG_KEYNAME_XFER, MSG_KEYNAME_PROG1,
-       MSG_KEYNAME_PROG2, MSG_KEYNAME_WWW,
-       MSG_KEYNAME_MSDOS, MSG_KEYNAME_COFFEE, MSG_KEYNAME_DIRECTION,
-       MSG_KEYNAME_CYCLEWINDOWS, MSG_KEYNAME_MAIL,
-       MSG_KEYNAME_BOOKMARKS, MSG_KEYNAME_COMPUTER, MSG_KEYNAME_BACK,
-       MSG_KEYNAME_FORWARD, MSG_KEYNAME_CLOSECD,
-       MSG_KEYNAME_EJECTCD, MSG_KEYNAME_EJECTCLOSE, MSG_KEYNAME_NEXTSONG,
-       MSG_KEYNAME_PLAYPAUSE, MSG_KEYNAME_PREVSONG,
-       MSG_KEYNAME_STOPCD, MSG_KEYNAME_RECORD, MSG_KEYNAME_REWIND,
-       MSG_KEYNAME_PHONE, MSG_KEYNAME_ISO,
-       MSG_KEYNAME_CONFIG, MSG_KEYNAME_HOMEPG, MSG_KEYNAME_REFRESH,
-       MSG_KEYNAME_EXIT, MSG_KEYNAME_MOVE,
-       MSG_KEYNAME_EDIT, MSG_KEYNAME_SCROLLUP, MSG_KEYNAME_SCROLLDN,
-       MSG_KEYNAME_KPLEFTPAR, MSG_KEYNAME_KPRIGHTPAR,
-       MSG_KEYNAMES_END = MSG_KEYNAME_KPRIGHTPAR,
-
-       MSG_FUNCNAMES_START,
-       MSG_FUNCNAME_ATTRIB_BLEEP_DEC = MSG_FUNCNAMES_START,
-       MSG_FUNCNAME_ATTRIB_BLEEP_INC,
-       MSG_FUNCNAME_BLEEPS_DEC, MSG_FUNCNAME_BLEEPS_INC,
-       MSG_FUNCNAME_CHAR_FIRST, MSG_FUNCNAME_CHAR_LAST,
-       MSG_FUNCNAME_CHAR_CURRENT, MSG_FUNCNAME_CHAR_HEX_AND_DEC,
-       MSG_FUNCNAME_CHAR_NEXT,
-       MSG_FUNCNAME_CHAR_PHONETIC, MSG_FUNCNAME_CHAR_PREVIOUS,
-       MSG_FUNCNAME_CURSOR_PARK, MSG_FUNCNAME_CUT,
-       MSG_FUNCNAME_EDIT_DELIM, MSG_FUNCNAME_EDIT_EXNUM,
-       MSG_FUNCNAME_EDIT_MOST, MSG_FUNCNAME_EDIT_REPEATS,
-       MSG_FUNCNAME_EDIT_SOME,
-       MSG_FUNCNAME_GOTO, MSG_FUNCNAME_GOTO_BOTTOM, MSG_FUNCNAME_GOTO_LEFT,
-       MSG_FUNCNAME_GOTO_RIGHT, MSG_FUNCNAME_GOTO_TOP, MSG_FUNCNAME_HELP,
-       MSG_FUNCNAME_LINE_SAY_CURRENT, MSG_FUNCNAME_LINE_SAY_NEXT,
-       MSG_FUNCNAME_LINE_SAY_PREVIOUS, MSG_FUNCNAME_LINE_SAY_WITH_INDENT,
-       MSG_FUNCNAME_PASTE, MSG_FUNCNAME_PITCH_DEC, MSG_FUNCNAME_PITCH_INC,
-       MSG_FUNCNAME_PUNC_DEC, MSG_FUNCNAME_PUNC_INC,
-       MSG_FUNCNAME_PUNC_LEVEL_DEC, MSG_FUNCNAME_PUNC_LEVEL_INC,
-       MSG_FUNCNAME_QUIET,
-       MSG_FUNCNAME_RATE_DEC, MSG_FUNCNAME_RATE_INC,
-       MSG_FUNCNAME_READING_PUNC_DEC, MSG_FUNCNAME_READING_PUNC_INC,
-       MSG_FUNCNAME_SAY_ATTRIBUTES,
-       MSG_FUNCNAME_SAY_FROM_LEFT, MSG_FUNCNAME_SAY_FROM_TOP,
-       MSG_FUNCNAME_SAY_POSITION, MSG_FUNCNAME_SAY_SCREEN,
-       MSG_FUNCNAME_SAY_TO_BOTTOM, MSG_FUNCNAME_SAY_TO_RIGHT,
-       MSG_FUNCNAME_SPEAKUP, MSG_FUNCNAME_SPEAKUP_LOCK,
-       MSG_FUNCNAME_SPEAKUP_OFF, MSG_FUNCNAME_SPEECH_KILL,
-       MSG_FUNCNAME_SPELL_DELAY_DEC, MSG_FUNCNAME_SPELL_DELAY_INC,
-       MSG_FUNCNAME_SPELL_WORD, MSG_FUNCNAME_SPELL_WORD_PHONETICALLY,
-       MSG_FUNCNAME_TONE_DEC, MSG_FUNCNAME_TONE_INC,
-       MSG_FUNCNAME_VOICE_DEC, MSG_FUNCNAME_VOICE_INC,
-       MSG_FUNCNAME_VOLUME_DEC, MSG_FUNCNAME_VOLUME_INC,
-       MSG_FUNCNAME_WINDOW_CLEAR, MSG_FUNCNAME_WINDOW_SAY,
-       MSG_FUNCNAME_WINDOW_SET, MSG_FUNCNAME_WINDOW_SILENCE,
-       MSG_FUNCNAME_WORD_SAY_CURRENT, MSG_FUNCNAME_WORD_SAY_NEXT,
-       MSG_FUNCNAME_WORD_SAY_PREVIOUS,
-       MSG_FUNCNAMES_END = MSG_FUNCNAME_WORD_SAY_PREVIOUS,
-
-       /* all valid indices must be above this */
-       MSG_LAST_INDEX
-};
-
-struct msg_group_t {
-       char *name;
-       enum msg_index_t start;
-       enum msg_index_t end;
-};
-
-char *spk_msg_get(enum msg_index_t index);
-ssize_t spk_msg_set(enum msg_index_t index, char *text, size_t length);
-struct msg_group_t *spk_find_msg_group(const char *group_name);
-void spk_reset_msg_group(struct msg_group_t *group);
-void spk_initialize_msgs(void);
-void spk_free_user_msgs(void);
-
-#endif
diff --git a/drivers/staging/speakup/keyhelp.c b/drivers/staging/speakup/keyhelp.c
deleted file mode 100644 (file)
index 822ceac..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/* speakup_keyhelp.c
- * help module for speakup
- *
- *written by David Borowski.
- *
- *  Copyright (C) 2003  David Borowski.
- */
-
-#include <linux/keyboard.h>
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define MAXFUNCS 130
-#define MAXKEYS 256
-static const int num_key_names = MSG_KEYNAMES_END - MSG_KEYNAMES_START + 1;
-static u_short key_offsets[MAXFUNCS], key_data[MAXKEYS];
-static u_short masks[] = { 32, 16, 8, 4, 2, 1 };
-
-static short letter_offsets[26] = {
-       -1, -1, -1, -1, -1, -1, -1, -1,
-       -1, -1, -1, -1, -1, -1, -1, -1,
-       -1, -1, -1, -1, -1, -1, -1, -1,
-       -1, -1 };
-
-static u_char funcvals[] = {
-       ATTRIB_BLEEP_DEC, ATTRIB_BLEEP_INC, BLEEPS_DEC, BLEEPS_INC,
-       SAY_FIRST_CHAR, SAY_LAST_CHAR, SAY_CHAR, SAY_CHAR_NUM,
-       SAY_NEXT_CHAR, SAY_PHONETIC_CHAR, SAY_PREV_CHAR, SPEAKUP_PARKED,
-       SPEAKUP_CUT, EDIT_DELIM, EDIT_EXNUM, EDIT_MOST,
-       EDIT_REPEAT, EDIT_SOME, SPEAKUP_GOTO, BOTTOM_EDGE,
-       LEFT_EDGE, RIGHT_EDGE, TOP_EDGE, SPEAKUP_HELP,
-       SAY_LINE, SAY_NEXT_LINE, SAY_PREV_LINE, SAY_LINE_INDENT,
-       SPEAKUP_PASTE, PITCH_DEC, PITCH_INC, PUNCT_DEC,
-       PUNCT_INC, PUNC_LEVEL_DEC, PUNC_LEVEL_INC, SPEAKUP_QUIET,
-       RATE_DEC, RATE_INC, READING_PUNC_DEC, READING_PUNC_INC,
-       SAY_ATTRIBUTES, SAY_FROM_LEFT, SAY_FROM_TOP, SAY_POSITION,
-       SAY_SCREEN, SAY_TO_BOTTOM, SAY_TO_RIGHT, SPK_KEY,
-       SPK_LOCK, SPEAKUP_OFF, SPEECH_KILL, SPELL_DELAY_DEC,
-       SPELL_DELAY_INC, SPELL_WORD, SPELL_PHONETIC, TONE_DEC,
-       TONE_INC, VOICE_DEC, VOICE_INC, VOL_DEC,
-       VOL_INC, CLEAR_WIN, SAY_WIN, SET_WIN,
-       ENABLE_WIN, SAY_WORD, SAY_NEXT_WORD, SAY_PREV_WORD, 0
-};
-
-static u_char *state_tbl;
-static int cur_item, nstates;
-
-static void build_key_data(void)
-{
-       u_char *kp, counters[MAXFUNCS], ch, ch1;
-       u_short *p_key, key;
-       int i, offset = 1;
-
-       nstates = (int)(state_tbl[-1]);
-       memset(counters, 0, sizeof(counters));
-       memset(key_offsets, 0, sizeof(key_offsets));
-       kp = state_tbl + nstates + 1;
-       while (*kp++) {
-               /* count occurrences of each function */
-               for (i = 0; i < nstates; i++, kp++) {
-                       if (!*kp)
-                               continue;
-                       if ((state_tbl[i] & 16) != 0 && *kp == SPK_KEY)
-                               continue;
-                       counters[*kp]++;
-               }
-       }
-       for (i = 0; i < MAXFUNCS; i++) {
-               if (counters[i] == 0)
-                       continue;
-               key_offsets[i] = offset;
-               offset += (counters[i] + 1);
-               if (offset >= MAXKEYS)
-                       break;
-       }
-/* leave counters set so high keycodes come first.
- * this is done so num pad and other extended keys maps are spoken before
- * the alpha with speakup type mapping.
- */
-       kp = state_tbl + nstates + 1;
-       while ((ch = *kp++)) {
-               for (i = 0; i < nstates; i++) {
-                       ch1 = *kp++;
-                       if (!ch1)
-                               continue;
-                       if ((state_tbl[i] & 16) != 0 && ch1 == SPK_KEY)
-                               continue;
-                       key = (state_tbl[i] << 8) + ch;
-                       counters[ch1]--;
-                       offset = key_offsets[ch1];
-                       if (!offset)
-                               continue;
-                       p_key = key_data + offset + counters[ch1];
-                       *p_key = key;
-               }
-       }
-}
-
-static void say_key(int key)
-{
-       int i, state = key >> 8;
-
-       key &= 0xff;
-       for (i = 0; i < 6; i++) {
-               if (state & masks[i])
-                       synth_printf(" %s", spk_msg_get(MSG_STATES_START + i));
-       }
-       if ((key > 0) && (key <= num_key_names))
-               synth_printf(" %s\n",
-                            spk_msg_get(MSG_KEYNAMES_START + (key - 1)));
-}
-
-static int help_init(void)
-{
-       char start = SPACE;
-       int i;
-       int num_funcs = MSG_FUNCNAMES_END - MSG_FUNCNAMES_START + 1;
-
-       state_tbl = spk_our_keys[0] + SHIFT_TBL_SIZE + 2;
-       for (i = 0; i < num_funcs; i++) {
-               char *cur_funcname = spk_msg_get(MSG_FUNCNAMES_START + i);
-
-               if (start == *cur_funcname)
-                       continue;
-               start = *cur_funcname;
-               letter_offsets[(start & 31) - 1] = i;
-       }
-       return 0;
-}
-
-int spk_handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key)
-{
-       int i, n;
-       char *name;
-       u_char func, *kp;
-       u_short *p_keys, val;
-
-       if (letter_offsets[0] == -1)
-               help_init();
-       if (type == KT_LATIN) {
-               if (ch == SPACE) {
-                       spk_special_handler = NULL;
-                       synth_printf("%s\n", spk_msg_get(MSG_LEAVING_HELP));
-                       return 1;
-               }
-               ch |= 32; /* lower case */
-               if (ch < 'a' || ch > 'z')
-                       return -1;
-               if (letter_offsets[ch - 'a'] == -1) {
-                       synth_printf(spk_msg_get(MSG_NO_COMMAND), ch);
-                       synth_printf("\n");
-                       return 1;
-               }
-               cur_item = letter_offsets[ch - 'a'];
-       } else if (type == KT_CUR) {
-               if (ch == 0 &&
-                   (MSG_FUNCNAMES_START + cur_item + 1) <= MSG_FUNCNAMES_END)
-                       cur_item++;
-               else if (ch == 3 && cur_item > 0)
-                       cur_item--;
-               else
-                       return -1;
-       } else if (type == KT_SPKUP && ch == SPEAKUP_HELP &&
-                  !spk_special_handler) {
-               spk_special_handler = spk_handle_help;
-               synth_printf("%s\n", spk_msg_get(MSG_HELP_INFO));
-               build_key_data(); /* rebuild each time in case new mapping */
-               return 1;
-       } else {
-               name = NULL;
-               if ((type != KT_SPKUP) && (key > 0) && (key <= num_key_names)) {
-                       synth_printf("%s\n",
-                                    spk_msg_get(MSG_KEYNAMES_START + key - 1));
-                       return 1;
-               }
-               for (i = 0; funcvals[i] != 0 && !name; i++) {
-                       if (ch == funcvals[i])
-                               name = spk_msg_get(MSG_FUNCNAMES_START + i);
-               }
-               if (!name)
-                       return -1;
-               kp = spk_our_keys[key] + 1;
-               for (i = 0; i < nstates; i++) {
-                       if (ch == kp[i])
-                               break;
-               }
-               key += (state_tbl[i] << 8);
-               say_key(key);
-               synth_printf(spk_msg_get(MSG_KEYDESC), name);
-               synth_printf("\n");
-               return 1;
-       }
-       name = spk_msg_get(MSG_FUNCNAMES_START + cur_item);
-       func = funcvals[cur_item];
-       synth_printf("%s", name);
-       if (key_offsets[func] == 0) {
-               synth_printf(" %s\n", spk_msg_get(MSG_IS_UNASSIGNED));
-               return 1;
-       }
-       p_keys = key_data + key_offsets[func];
-       for (n = 0; p_keys[n]; n++) {
-               val = p_keys[n];
-               if (n > 0)
-                       synth_printf("%s ", spk_msg_get(MSG_DISJUNCTION));
-               say_key(val);
-       }
-       return 1;
-}
diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c
deleted file mode 100644 (file)
index 41ae24a..0000000
+++ /dev/null
@@ -1,1056 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Speakup kobject implementation
- *
- * Copyright (C) 2009 William Hubbs
- *
- * This code is based on kobject-example.c, which came with linux 2.6.x.
- *
- * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2007 Novell Inc.
- *
- * Released under the GPL version 2 only.
- *
- */
-#include <linux/slab.h>                /* For kmalloc. */
-#include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/string.h>
-#include <linux/string_helpers.h>
-#include <linux/sysfs.h>
-#include <linux/ctype.h>
-
-#include "speakup.h"
-#include "spk_priv.h"
-
-/*
- * This is called when a user reads the characters or chartab sys file.
- */
-static ssize_t chars_chartab_show(struct kobject *kobj,
-                                 struct kobj_attribute *attr, char *buf)
-{
-       int i;
-       int len = 0;
-       char *cp;
-       char *buf_pointer = buf;
-       size_t bufsize = PAGE_SIZE;
-       unsigned long flags;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       *buf_pointer = '\0';
-       for (i = 0; i < 256; i++) {
-               if (bufsize <= 1)
-                       break;
-               if (strcmp("characters", attr->attr.name) == 0) {
-                       len = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
-                                       i, spk_characters[i]);
-               } else {        /* show chartab entry */
-                       if (IS_TYPE(i, B_CTL))
-                               cp = "B_CTL";
-                       else if (IS_TYPE(i, WDLM))
-                               cp = "WDLM";
-                       else if (IS_TYPE(i, A_PUNC))
-                               cp = "A_PUNC";
-                       else if (IS_TYPE(i, PUNC))
-                               cp = "PUNC";
-                       else if (IS_TYPE(i, NUM))
-                               cp = "NUM";
-                       else if (IS_TYPE(i, A_CAP))
-                               cp = "A_CAP";
-                       else if (IS_TYPE(i, ALPHA))
-                               cp = "ALPHA";
-                       else if (IS_TYPE(i, B_CAPSYM))
-                               cp = "B_CAPSYM";
-                       else if (IS_TYPE(i, B_SYM))
-                               cp = "B_SYM";
-                       else
-                               cp = "0";
-                       len =
-                           scnprintf(buf_pointer, bufsize, "%d\t%s\n", i, cp);
-               }
-               bufsize -= len;
-               buf_pointer += len;
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return buf_pointer - buf;
-}
-
-/*
- * Print informational messages or warnings after updating
- * character descriptions or chartab entries.
- */
-static void report_char_chartab_status(int reset, int received, int used,
-                                      int rejected, int do_characters)
-{
-       static char const *object_type[] = {
-               "character class entries",
-               "character descriptions",
-       };
-       int len;
-       char buf[80];
-
-       if (reset) {
-               pr_info("%s reset to defaults\n", object_type[do_characters]);
-       } else if (received) {
-               len = snprintf(buf, sizeof(buf),
-                              " updated %d of %d %s\n",
-                              used, received, object_type[do_characters]);
-               if (rejected)
-                       snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
-                                " with %d reject%s\n",
-                                rejected, rejected > 1 ? "s" : "");
-               pr_info("%s", buf);
-       }
-}
-
-/*
- * This is called when a user changes the characters or chartab parameters.
- */
-static ssize_t chars_chartab_store(struct kobject *kobj,
-                                  struct kobj_attribute *attr,
-                                  const char *buf, size_t count)
-{
-       char *cp = (char *)buf;
-       char *end = cp + count; /* the null at the end of the buffer */
-       char *linefeed = NULL;
-       char keyword[MAX_DESC_LEN + 1];
-       char *outptr = NULL;    /* Will hold keyword or desc. */
-       char *temp = NULL;
-       char *desc = NULL;
-       ssize_t retval = count;
-       unsigned long flags;
-       unsigned long index = 0;
-       int charclass = 0;
-       int received = 0;
-       int used = 0;
-       int rejected = 0;
-       int reset = 0;
-       int do_characters = !strcmp(attr->attr.name, "characters");
-       size_t desc_length = 0;
-       int i;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       while (cp < end) {
-               while ((cp < end) && (*cp == ' ' || *cp == '\t'))
-                       cp++;
-
-               if (cp == end)
-                       break;
-               if ((*cp == '\n') || strchr("dDrR", *cp)) {
-                       reset = 1;
-                       break;
-               }
-               received++;
-
-               linefeed = strchr(cp, '\n');
-               if (!linefeed) {
-                       rejected++;
-                       break;
-               }
-
-               if (!isdigit(*cp)) {
-                       rejected++;
-                       cp = linefeed + 1;
-                       continue;
-               }
-
-               /*
-                * Do not replace with kstrtoul:
-                * here we need temp to be updated
-                */
-               index = simple_strtoul(cp, &temp, 10);
-               if (index > 255) {
-                       rejected++;
-                       cp = linefeed + 1;
-                       continue;
-               }
-
-               while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
-                       temp++;
-
-               desc_length = linefeed - temp;
-               if (desc_length > MAX_DESC_LEN) {
-                       rejected++;
-                       cp = linefeed + 1;
-                       continue;
-               }
-               if (do_characters) {
-                       desc = kmalloc(desc_length + 1, GFP_ATOMIC);
-                       if (!desc) {
-                               retval = -ENOMEM;
-                               reset = 1;      /* just reset on error. */
-                               break;
-                       }
-                       outptr = desc;
-               } else {
-                       outptr = keyword;
-               }
-
-               for (i = 0; i < desc_length; i++)
-                       outptr[i] = temp[i];
-               outptr[desc_length] = '\0';
-
-               if (do_characters) {
-                       if (spk_characters[index] != spk_default_chars[index])
-                               kfree(spk_characters[index]);
-                       spk_characters[index] = desc;
-                       used++;
-               } else {
-                       charclass = spk_chartab_get_value(keyword);
-                       if (charclass == 0) {
-                               rejected++;
-                               cp = linefeed + 1;
-                               continue;
-                       }
-                       if (charclass != spk_chartab[index]) {
-                               spk_chartab[index] = charclass;
-                               used++;
-                       }
-               }
-               cp = linefeed + 1;
-       }
-
-       if (reset) {
-               if (do_characters)
-                       spk_reset_default_chars();
-               else
-                       spk_reset_default_chartab();
-       }
-
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       report_char_chartab_status(reset, received, used, rejected,
-                                  do_characters);
-       return retval;
-}
-
-/*
- * This is called when a user reads the keymap parameter.
- */
-static ssize_t keymap_show(struct kobject *kobj, struct kobj_attribute *attr,
-                          char *buf)
-{
-       char *cp = buf;
-       int i;
-       int n;
-       int num_keys;
-       int nstates;
-       u_char *cp1;
-       u_char ch;
-       unsigned long flags;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       cp1 = spk_key_buf + SHIFT_TBL_SIZE;
-       num_keys = (int)(*cp1);
-       nstates = (int)cp1[1];
-       cp += sprintf(cp, "%d, %d, %d,\n", KEY_MAP_VER, num_keys, nstates);
-       cp1 += 2; /* now pointing at shift states */
-       /* dump num_keys+1 as first row is shift states + flags,
-        * each subsequent row is key + states
-        */
-       for (n = 0; n <= num_keys; n++) {
-               for (i = 0; i <= nstates; i++) {
-                       ch = *cp1++;
-                       cp += sprintf(cp, "%d,", (int)ch);
-                       *cp++ = (i < nstates) ? SPACE : '\n';
-               }
-       }
-       cp += sprintf(cp, "0, %d\n", KEY_MAP_VER);
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return (int)(cp - buf);
-}
-
-/*
- * This is called when a user changes the keymap parameter.
- */
-static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr,
-                           const char *buf, size_t count)
-{
-       int i;
-       ssize_t ret = count;
-       char *in_buff = NULL;
-       char *cp;
-       u_char *cp1;
-       unsigned long flags;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       in_buff = kmemdup(buf, count + 1, GFP_ATOMIC);
-       if (!in_buff) {
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return -ENOMEM;
-       }
-       if (strchr("dDrR", *in_buff)) {
-               spk_set_key_info(spk_key_defaults, spk_key_buf);
-               pr_info("keymap set to default values\n");
-               kfree(in_buff);
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return count;
-       }
-       if (in_buff[count - 1] == '\n')
-               in_buff[count - 1] = '\0';
-       cp = in_buff;
-       cp1 = (u_char *)in_buff;
-       for (i = 0; i < 3; i++) {
-               cp = spk_s2uchar(cp, cp1);
-               cp1++;
-       }
-       i = (int)cp1[-2] + 1;
-       i *= (int)cp1[-1] + 1;
-       i += 2; /* 0 and last map ver */
-       if (cp1[-3] != KEY_MAP_VER || cp1[-1] > 10 ||
-           i + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
-               pr_warn("i %d %d %d %d\n", i,
-                       (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
-               kfree(in_buff);
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return -EINVAL;
-       }
-       while (--i >= 0) {
-               cp = spk_s2uchar(cp, cp1);
-               cp1++;
-               if (!(*cp))
-                       break;
-       }
-       if (i != 0 || cp1[-1] != KEY_MAP_VER || cp1[-2] != 0) {
-               ret = -EINVAL;
-               pr_warn("end %d %d %d %d\n", i,
-                       (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]);
-       } else {
-               if (spk_set_key_info(in_buff, spk_key_buf)) {
-                       spk_set_key_info(spk_key_defaults, spk_key_buf);
-                       ret = -EINVAL;
-                       pr_warn("set key failed\n");
-               }
-       }
-       kfree(in_buff);
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return ret;
-}
-
-/*
- * This is called when a user changes the value of the silent parameter.
- */
-static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr,
-                           const char *buf, size_t count)
-{
-       int len;
-       struct vc_data *vc = vc_cons[fg_console].d;
-       char ch = 0;
-       char shut;
-       unsigned long flags;
-
-       len = strlen(buf);
-       if (len > 0 && len < 3) {
-               ch = buf[0];
-               if (ch == '\n')
-                       ch = '0';
-       }
-       if (ch < '0' || ch > '7') {
-               pr_warn("silent value '%c' not in range (0,7)\n", ch);
-               return -EINVAL;
-       }
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       if (ch & 2) {
-               shut = 1;
-               spk_do_flush();
-       } else {
-               shut = 0;
-       }
-       if (ch & 4)
-               shut |= 0x40;
-       if (ch & 1)
-               spk_shut_up |= shut;
-       else
-               spk_shut_up &= ~shut;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return count;
-}
-
-/*
- * This is called when a user reads the synth setting.
- */
-static ssize_t synth_show(struct kobject *kobj, struct kobj_attribute *attr,
-                         char *buf)
-{
-       int rv;
-
-       if (!synth)
-               rv = sprintf(buf, "%s\n", "none");
-       else
-               rv = sprintf(buf, "%s\n", synth->name);
-       return rv;
-}
-
-/*
- * This is called when a user requests to change synthesizers.
- */
-static ssize_t synth_store(struct kobject *kobj, struct kobj_attribute *attr,
-                          const char *buf, size_t count)
-{
-       int len;
-       char new_synth_name[10];
-
-       len = strlen(buf);
-       if (len < 2 || len > 9)
-               return -EINVAL;
-       memcpy(new_synth_name, buf, len);
-       if (new_synth_name[len - 1] == '\n')
-               len--;
-       new_synth_name[len] = '\0';
-       spk_strlwr(new_synth_name);
-       if (synth && !strcmp(new_synth_name, synth->name)) {
-               pr_warn("%s already in use\n", new_synth_name);
-       } else if (synth_init(new_synth_name) != 0) {
-               pr_warn("failed to init synth %s\n", new_synth_name);
-               return -ENODEV;
-       }
-       return count;
-}
-
-/*
- * This is called when text is sent to the synth via the synth_direct file.
- */
-static ssize_t synth_direct_store(struct kobject *kobj,
-                                 struct kobj_attribute *attr,
-                                 const char *buf, size_t count)
-{
-       u_char tmp[256];
-       int len;
-       int bytes;
-       const char *ptr = buf;
-       unsigned long flags;
-
-       if (!synth)
-               return -EPERM;
-
-       len = strlen(buf);
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       while (len > 0) {
-               bytes = min_t(size_t, len, 250);
-               strncpy(tmp, ptr, bytes);
-               tmp[bytes] = '\0';
-               string_unescape_any_inplace(tmp);
-               synth_printf("%s", tmp);
-               ptr += bytes;
-               len -= bytes;
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return count;
-}
-
-/*
- * This function is called when a user reads the version.
- */
-static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr,
-                           char *buf)
-{
-       char *cp;
-
-       cp = buf;
-       cp += sprintf(cp, "Speakup version %s\n", SPEAKUP_VERSION);
-       if (synth)
-               cp += sprintf(cp, "%s synthesizer driver version %s\n",
-               synth->name, synth->version);
-       return cp - buf;
-}
-
-/*
- * This is called when a user reads the punctuation settings.
- */
-static ssize_t punc_show(struct kobject *kobj, struct kobj_attribute *attr,
-                        char *buf)
-{
-       int i;
-       char *cp = buf;
-       struct st_var_header *p_header;
-       struct punc_var_t *var;
-       struct st_bits_data *pb;
-       short mask;
-       unsigned long flags;
-
-       p_header = spk_var_header_by_name(attr->attr.name);
-       if (!p_header) {
-               pr_warn("p_header is null, attr->attr.name is %s\n",
-                       attr->attr.name);
-               return -EINVAL;
-       }
-
-       var = spk_get_punc_var(p_header->var_id);
-       if (!var) {
-               pr_warn("var is null, p_header->var_id is %i\n",
-                       p_header->var_id);
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       pb = (struct st_bits_data *)&spk_punc_info[var->value];
-       mask = pb->mask;
-       for (i = 33; i < 128; i++) {
-               if (!(spk_chartab[i] & mask))
-                       continue;
-               *cp++ = (char)i;
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return cp - buf;
-}
-
-/*
- * This is called when a user changes the punctuation settings.
- */
-static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr,
-                         const char *buf, size_t count)
-{
-       int x;
-       struct st_var_header *p_header;
-       struct punc_var_t *var;
-       char punc_buf[100];
-       unsigned long flags;
-
-       x = strlen(buf);
-       if (x < 1 || x > 99)
-               return -EINVAL;
-
-       p_header = spk_var_header_by_name(attr->attr.name);
-       if (!p_header) {
-               pr_warn("p_header is null, attr->attr.name is %s\n",
-                       attr->attr.name);
-               return -EINVAL;
-       }
-
-       var = spk_get_punc_var(p_header->var_id);
-       if (!var) {
-               pr_warn("var is null, p_header->var_id is %i\n",
-                       p_header->var_id);
-               return -EINVAL;
-       }
-
-       memcpy(punc_buf, buf, x);
-
-       while (x && punc_buf[x - 1] == '\n')
-               x--;
-       punc_buf[x] = '\0';
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-
-       if (*punc_buf == 'd' || *punc_buf == 'r')
-               x = spk_set_mask_bits(NULL, var->value, 3);
-       else
-               x = spk_set_mask_bits(punc_buf, var->value, 3);
-
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return count;
-}
-
-/*
- * This function is called when a user reads one of the variable parameters.
- */
-ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
-                    char *buf)
-{
-       int rv = 0;
-       struct st_var_header *param;
-       struct var_t *var;
-       char *cp1;
-       char *cp;
-       char ch;
-       unsigned long flags;
-
-       param = spk_var_header_by_name(attr->attr.name);
-       if (!param)
-               return -EINVAL;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       var = (struct var_t *)param->data;
-       switch (param->var_type) {
-       case VAR_NUM:
-       case VAR_TIME:
-               if (var)
-                       rv = sprintf(buf, "%i\n", var->u.n.value);
-               else
-                       rv = sprintf(buf, "0\n");
-               break;
-       case VAR_STRING:
-               if (var) {
-                       cp1 = buf;
-                       *cp1++ = '"';
-                       for (cp = (char *)param->p_val; (ch = *cp); cp++) {
-                               if (ch >= ' ' && ch < '~')
-                                       *cp1++ = ch;
-                               else
-                                       cp1 += sprintf(cp1, "\\x%02x", ch);
-                       }
-                       *cp1++ = '"';
-                       *cp1++ = '\n';
-                       *cp1 = '\0';
-                       rv = cp1 - buf;
-               } else {
-                       rv = sprintf(buf, "\"\"\n");
-               }
-               break;
-       default:
-               rv = sprintf(buf, "Bad parameter  %s, type %i\n",
-                            param->name, param->var_type);
-               break;
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return rv;
-}
-EXPORT_SYMBOL_GPL(spk_var_show);
-
-/*
- * Used to reset either default_pitch or default_vol.
- */
-static inline void spk_reset_default_value(char *header_name,
-                                          int *synth_default_value, int idx)
-{
-       struct st_var_header *param;
-
-       if (synth && synth_default_value) {
-               param = spk_var_header_by_name(header_name);
-               if (param)  {
-                       spk_set_num_var(synth_default_value[idx],
-                                       param, E_NEW_DEFAULT);
-                       spk_set_num_var(0, param, E_DEFAULT);
-                       pr_info("%s reset to default value\n", param->name);
-               }
-       }
-}
-
-/*
- * This function is called when a user echos a value to one of the
- * variable parameters.
- */
-ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
-                     const char *buf, size_t count)
-{
-       struct st_var_header *param;
-       int ret;
-       int len;
-       char *cp;
-       struct var_t *var_data;
-       long value;
-       unsigned long flags;
-
-       param = spk_var_header_by_name(attr->attr.name);
-       if (!param)
-               return -EINVAL;
-       if (!param->data)
-               return 0;
-       ret = 0;
-       cp = (char *)buf;
-       string_unescape_any_inplace(cp);
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       switch (param->var_type) {
-       case VAR_NUM:
-       case VAR_TIME:
-               if (*cp == 'd' || *cp == 'r' || *cp == '\0')
-                       len = E_DEFAULT;
-               else if (*cp == '+' || *cp == '-')
-                       len = E_INC;
-               else
-                       len = E_SET;
-               if (kstrtol(cp, 10, &value) == 0)
-                       ret = spk_set_num_var(value, param, len);
-               else
-                       pr_warn("overflow or parsing error has occurred");
-               if (ret == -ERANGE) {
-                       var_data = param->data;
-                       pr_warn("value for %s out of range, expect %d to %d\n",
-                               param->name,
-                               var_data->u.n.low, var_data->u.n.high);
-               }
-
-              /*
-               * If voice was just changed, we might need to reset our default
-               * pitch and volume.
-               */
-               if (param->var_id == VOICE && synth &&
-                   (ret == 0 || ret == -ERESTART)) {
-                       var_data = param->data;
-                       value = var_data->u.n.value;
-                       spk_reset_default_value("pitch", synth->default_pitch,
-                                               value);
-                       spk_reset_default_value("vol", synth->default_vol,
-                                               value);
-               }
-               break;
-       case VAR_STRING:
-               len = strlen(cp);
-               if ((len >= 1) && (cp[len - 1] == '\n'))
-                       --len;
-               if ((len >= 2) && (cp[0] == '"') && (cp[len - 1] == '"')) {
-                       ++cp;
-                       len -= 2;
-               }
-               cp[len] = '\0';
-               ret = spk_set_string_var(cp, param, len);
-               if (ret == -E2BIG)
-                       pr_warn("value too long for %s\n",
-                               param->name);
-               break;
-       default:
-               pr_warn("%s unknown type %d\n",
-                       param->name, (int)param->var_type);
-       break;
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-
-       if (ret == -ERESTART)
-               pr_info("%s reset to default value\n", param->name);
-       return count;
-}
-EXPORT_SYMBOL_GPL(spk_var_store);
-
-/*
- * Functions for reading and writing lists of i18n messages.  Incomplete.
- */
-
-static ssize_t message_show_helper(char *buf, enum msg_index_t first,
-                                  enum msg_index_t last)
-{
-       size_t bufsize = PAGE_SIZE;
-       char *buf_pointer = buf;
-       int printed;
-       enum msg_index_t cursor;
-       int index = 0;
-       *buf_pointer = '\0'; /* buf_pointer always looking at a NUL byte. */
-
-       for (cursor = first; cursor <= last; cursor++, index++) {
-               if (bufsize <= 1)
-                       break;
-               printed = scnprintf(buf_pointer, bufsize, "%d\t%s\n",
-                                   index, spk_msg_get(cursor));
-               buf_pointer += printed;
-               bufsize -= printed;
-       }
-
-       return buf_pointer - buf;
-}
-
-static void report_msg_status(int reset, int received, int used,
-                             int rejected, char *groupname)
-{
-       int len;
-       char buf[160];
-
-       if (reset) {
-               pr_info("i18n messages from group %s reset to defaults\n",
-                       groupname);
-       } else if (received) {
-               len = snprintf(buf, sizeof(buf),
-                              " updated %d of %d i18n messages from group %s\n",
-                                      used, received, groupname);
-               if (rejected)
-                       snprintf(buf + (len - 1), sizeof(buf) - (len - 1),
-                                " with %d reject%s\n",
-                                rejected, rejected > 1 ? "s" : "");
-               pr_info("%s", buf);
-       }
-}
-
-static ssize_t message_store_helper(const char *buf, size_t count,
-                                   struct msg_group_t *group)
-{
-       char *cp = (char *)buf;
-       char *end = cp + count;
-       char *linefeed = NULL;
-       char *temp = NULL;
-       ssize_t msg_stored = 0;
-       ssize_t retval = count;
-       size_t desc_length = 0;
-       unsigned long index = 0;
-       int received = 0;
-       int used = 0;
-       int rejected = 0;
-       int reset = 0;
-       enum msg_index_t firstmessage = group->start;
-       enum msg_index_t lastmessage = group->end;
-       enum msg_index_t curmessage;
-
-       while (cp < end) {
-               while ((cp < end) && (*cp == ' ' || *cp == '\t'))
-                       cp++;
-
-               if (cp == end)
-                       break;
-               if (strchr("dDrR", *cp)) {
-                       reset = 1;
-                       break;
-               }
-               received++;
-
-               linefeed = strchr(cp, '\n');
-               if (!linefeed) {
-                       rejected++;
-                       break;
-               }
-
-               if (!isdigit(*cp)) {
-                       rejected++;
-                       cp = linefeed + 1;
-                       continue;
-               }
-
-               /*
-                * Do not replace with kstrtoul:
-                * here we need temp to be updated
-                */
-               index = simple_strtoul(cp, &temp, 10);
-
-               while ((temp < linefeed) && (*temp == ' ' || *temp == '\t'))
-                       temp++;
-
-               desc_length = linefeed - temp;
-               curmessage = firstmessage + index;
-
-               /*
-                * Note the check (curmessage < firstmessage).  It is not
-                * redundant.  Suppose that the user gave us an index
-                * equal to ULONG_MAX - 1.  If firstmessage > 1, then
-                * firstmessage + index < firstmessage!
-                */
-
-               if ((curmessage < firstmessage) || (curmessage > lastmessage)) {
-                       rejected++;
-                       cp = linefeed + 1;
-                       continue;
-               }
-
-               msg_stored = spk_msg_set(curmessage, temp, desc_length);
-               if (msg_stored < 0) {
-                       retval = msg_stored;
-                       if (msg_stored == -ENOMEM)
-                               reset = 1;
-                       break;
-               }
-
-               used++;
-
-               cp = linefeed + 1;
-       }
-
-       if (reset)
-               spk_reset_msg_group(group);
-
-       report_msg_status(reset, received, used, rejected, group->name);
-       return retval;
-}
-
-static ssize_t message_show(struct kobject *kobj,
-                           struct kobj_attribute *attr, char *buf)
-{
-       ssize_t retval = 0;
-       struct msg_group_t *group = spk_find_msg_group(attr->attr.name);
-       unsigned long flags;
-
-       if (WARN_ON(!group))
-               return -EINVAL;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       retval = message_show_helper(buf, group->start, group->end);
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return retval;
-}
-
-static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr,
-                            const char *buf, size_t count)
-{
-       struct msg_group_t *group = spk_find_msg_group(attr->attr.name);
-
-       if (WARN_ON(!group))
-               return -EINVAL;
-
-       return message_store_helper(buf, count, group);
-}
-
-/*
- * Declare the attributes.
- */
-static struct kobj_attribute keymap_attribute =
-       __ATTR_RW(keymap);
-static struct kobj_attribute silent_attribute =
-       __ATTR_WO(silent);
-static struct kobj_attribute synth_attribute =
-       __ATTR_RW(synth);
-static struct kobj_attribute synth_direct_attribute =
-       __ATTR_WO(synth_direct);
-static struct kobj_attribute version_attribute =
-       __ATTR_RO(version);
-
-static struct kobj_attribute delimiters_attribute =
-       __ATTR(delimiters, 0644, punc_show, punc_store);
-static struct kobj_attribute ex_num_attribute =
-       __ATTR(ex_num, 0644, punc_show, punc_store);
-static struct kobj_attribute punc_all_attribute =
-       __ATTR(punc_all, 0644, punc_show, punc_store);
-static struct kobj_attribute punc_most_attribute =
-       __ATTR(punc_most, 0644, punc_show, punc_store);
-static struct kobj_attribute punc_some_attribute =
-       __ATTR(punc_some, 0644, punc_show, punc_store);
-static struct kobj_attribute repeats_attribute =
-       __ATTR(repeats, 0644, punc_show, punc_store);
-
-static struct kobj_attribute attrib_bleep_attribute =
-       __ATTR(attrib_bleep, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute bell_pos_attribute =
-       __ATTR(bell_pos, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute bleep_time_attribute =
-       __ATTR(bleep_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute bleeps_attribute =
-       __ATTR(bleeps, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute cursor_time_attribute =
-       __ATTR(cursor_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute key_echo_attribute =
-       __ATTR(key_echo, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute no_interrupt_attribute =
-       __ATTR(no_interrupt, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute punc_level_attribute =
-       __ATTR(punc_level, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute reading_punc_attribute =
-       __ATTR(reading_punc, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute say_control_attribute =
-       __ATTR(say_control, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute say_word_ctl_attribute =
-       __ATTR(say_word_ctl, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute spell_delay_attribute =
-       __ATTR(spell_delay, 0644, spk_var_show, spk_var_store);
-
-/*
- * These attributes are i18n related.
- */
-static struct kobj_attribute announcements_attribute =
-       __ATTR(announcements, 0644, message_show, message_store);
-static struct kobj_attribute characters_attribute =
-       __ATTR(characters, 0644, chars_chartab_show,
-              chars_chartab_store);
-static struct kobj_attribute chartab_attribute =
-       __ATTR(chartab, 0644, chars_chartab_show,
-              chars_chartab_store);
-static struct kobj_attribute ctl_keys_attribute =
-       __ATTR(ctl_keys, 0644, message_show, message_store);
-static struct kobj_attribute colors_attribute =
-       __ATTR(colors, 0644, message_show, message_store);
-static struct kobj_attribute formatted_attribute =
-       __ATTR(formatted, 0644, message_show, message_store);
-static struct kobj_attribute function_names_attribute =
-       __ATTR(function_names, 0644, message_show, message_store);
-static struct kobj_attribute key_names_attribute =
-       __ATTR(key_names, 0644, message_show, message_store);
-static struct kobj_attribute states_attribute =
-       __ATTR(states, 0644, message_show, message_store);
-
-/*
- * Create groups of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *main_attrs[] = {
-       &keymap_attribute.attr,
-       &silent_attribute.attr,
-       &synth_attribute.attr,
-       &synth_direct_attribute.attr,
-       &version_attribute.attr,
-       &delimiters_attribute.attr,
-       &ex_num_attribute.attr,
-       &punc_all_attribute.attr,
-       &punc_most_attribute.attr,
-       &punc_some_attribute.attr,
-       &repeats_attribute.attr,
-       &attrib_bleep_attribute.attr,
-       &bell_pos_attribute.attr,
-       &bleep_time_attribute.attr,
-       &bleeps_attribute.attr,
-       &cursor_time_attribute.attr,
-       &key_echo_attribute.attr,
-       &no_interrupt_attribute.attr,
-       &punc_level_attribute.attr,
-       &reading_punc_attribute.attr,
-       &say_control_attribute.attr,
-       &say_word_ctl_attribute.attr,
-       &spell_delay_attribute.attr,
-       NULL,
-};
-
-static struct attribute *i18n_attrs[] = {
-       &announcements_attribute.attr,
-       &characters_attribute.attr,
-       &chartab_attribute.attr,
-       &ctl_keys_attribute.attr,
-       &colors_attribute.attr,
-       &formatted_attribute.attr,
-       &function_names_attribute.attr,
-       &key_names_attribute.attr,
-       &states_attribute.attr,
-       NULL,
-};
-
-/*
- * An unnamed attribute group will put all of the attributes directly in
- * the kobject directory.  If we specify a name, a subdirectory will be
- * created for the attributes with the directory being the name of the
- * attribute group.
- */
-static const struct attribute_group main_attr_group = {
-       .attrs = main_attrs,
-};
-
-static const struct attribute_group i18n_attr_group = {
-       .attrs = i18n_attrs,
-       .name = "i18n",
-};
-
-static struct kobject *accessibility_kobj;
-struct kobject *speakup_kobj;
-
-int speakup_kobj_init(void)
-{
-       int retval;
-
-       /*
-        * Create a simple kobject with the name of "accessibility",
-        * located under /sys/
-        *
-        * As this is a simple directory, no uevent will be sent to
-        * userspace.  That is why this function should not be used for
-        * any type of dynamic kobjects, where the name and number are
-        * not known ahead of time.
-        */
-       accessibility_kobj = kobject_create_and_add("accessibility", NULL);
-       if (!accessibility_kobj) {
-               retval = -ENOMEM;
-               goto out;
-       }
-
-       speakup_kobj = kobject_create_and_add("speakup", accessibility_kobj);
-       if (!speakup_kobj) {
-               retval = -ENOMEM;
-               goto err_acc;
-       }
-
-       /* Create the files associated with this kobject */
-       retval = sysfs_create_group(speakup_kobj, &main_attr_group);
-       if (retval)
-               goto err_speakup;
-
-       retval = sysfs_create_group(speakup_kobj, &i18n_attr_group);
-       if (retval)
-               goto err_group;
-
-       goto out;
-
-err_group:
-       sysfs_remove_group(speakup_kobj, &main_attr_group);
-err_speakup:
-       kobject_put(speakup_kobj);
-err_acc:
-       kobject_put(accessibility_kobj);
-out:
-       return retval;
-}
-
-void speakup_kobj_exit(void)
-{
-       sysfs_remove_group(speakup_kobj, &i18n_attr_group);
-       sysfs_remove_group(speakup_kobj, &main_attr_group);
-       kobject_put(speakup_kobj);
-       kobject_put(accessibility_kobj);
-}
diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c
deleted file mode 100644 (file)
index 02471d9..0000000
+++ /dev/null
@@ -1,2460 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/* speakup.c
- * review functions for the speakup screen review package.
- * originally written by: Kirk Reiser and Andy Berdan.
- *
- * extensively modified by David Borowski.
- *
- ** Copyright (C) 1998  Kirk Reiser.
- *  Copyright (C) 2003  David Borowski.
- */
-
-#include <linux/kernel.h>
-#include <linux/vt.h>
-#include <linux/tty.h>
-#include <linux/mm.h>          /* __get_free_page() and friends */
-#include <linux/vt_kern.h>
-#include <linux/ctype.h>
-#include <linux/selection.h>
-#include <linux/unistd.h>
-#include <linux/jiffies.h>
-#include <linux/kthread.h>
-#include <linux/keyboard.h>    /* for KT_SHIFT */
-#include <linux/kbd_kern.h>    /* for vc_kbd_* and friends */
-#include <linux/input.h>
-#include <linux/kmod.h>
-
-/* speakup_*_selection */
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/consolemap.h>
-
-#include <linux/spinlock.h>
-#include <linux/notifier.h>
-
-#include <linux/uaccess.h>     /* copy_from|to|user() and others */
-
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define MAX_DELAY msecs_to_jiffies(500)
-#define MINECHOCHAR SPACE
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
-MODULE_DESCRIPTION("Speakup console speech");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(SPEAKUP_VERSION);
-
-char *synth_name;
-module_param_named(synth, synth_name, charp, 0444);
-module_param_named(quiet, spk_quiet_boot, bool, 0444);
-
-MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
-MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
-
-special_func spk_special_handler;
-
-short spk_pitch_shift, synth_flags;
-static u16 buf[256];
-int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
-int spk_no_intr, spk_spell_delay;
-int spk_key_echo, spk_say_word_ctl;
-int spk_say_ctrl, spk_bell_pos;
-short spk_punc_mask;
-int spk_punc_level, spk_reading_punc;
-char spk_str_caps_start[MAXVARLEN + 1] = "\0";
-char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
-char spk_str_pause[MAXVARLEN + 1] = "\0";
-bool spk_paused;
-const struct st_bits_data spk_punc_info[] = {
-       {"none", "", 0},
-       {"some", "/$%&@", SOME},
-       {"most", "$%&#()=+*/@^<>|\\", MOST},
-       {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
-       {"delimiters", "", B_WDLM},
-       {"repeats", "()", CH_RPT},
-       {"extended numeric", "", B_EXNUM},
-       {"symbols", "", B_SYM},
-       {NULL, NULL}
-};
-
-static char mark_cut_flag;
-#define MAX_KEY 160
-static u_char *spk_shift_table;
-u_char *spk_our_keys[MAX_KEY];
-u_char spk_key_buf[600];
-const u_char spk_key_defaults[] = {
-#include "speakupmap.h"
-};
-
-/* Speakup Cursor Track Variables */
-static int cursor_track = 1, prev_cursor_track = 1;
-
-/* cursor track modes, must be ordered same as cursor_msgs */
-enum {
-       CT_Off = 0,
-       CT_On,
-       CT_Highlight,
-       CT_Window,
-       CT_Max
-};
-
-#define read_all_mode CT_Max
-
-static struct tty_struct *tty;
-
-static void spkup_write(const u16 *in_buf, int count);
-
-static char *phonetic[] = {
-       "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
-       "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
-           "papa",
-       "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
-       "x ray", "yankee", "zulu"
-};
-
-/* array of 256 char pointers (one for each character description)
- * initialized to default_chars and user selectable via
- * /proc/speakup/characters
- */
-char *spk_characters[256];
-
-char *spk_default_chars[256] = {
-/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
-/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
-/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
-/*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
-           "control",
-/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
-           "tick",
-/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
-           "dot",
-       "slash",
-/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
-       "eight", "nine",
-/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
-/*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
-/*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
-/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
-/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
-           "caret",
-       "line",
-/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
-/*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
-/*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
-/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
-/*127*/ "del", "control", "control", "control", "control", "control",
-           "control", "control", "control", "control", "control",
-/*138*/ "control", "control", "control", "control", "control",
-           "control", "control", "control", "control", "control",
-           "control", "control",
-/*150*/ "control", "control", "control", "control", "control",
-           "control", "control", "control", "control", "control",
-/*160*/ "nbsp", "inverted bang",
-/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
-/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
-/*172*/ "not", "soft hyphen", "registered", "macron",
-/*176*/ "degrees", "plus or minus", "super two", "super three",
-/*180*/ "acute accent", "micro", "pilcrow", "middle dot",
-/*184*/ "cedilla", "super one", "male ordinal", "double right angle",
-/*188*/ "one quarter", "one half", "three quarters",
-           "inverted question",
-/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
-           "A RING",
-/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
-           "E OOMLAUT",
-/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
-           "N TILDE",
-/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
-/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
-           "U CIRCUMFLEX",
-/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
-/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
-/*230*/ "ae", "c cidella", "e grave", "e acute",
-/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
-           "i circumflex",
-/*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
-           "o circumflex",
-/*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
-           "u acute",
-/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
-};
-
-/* array of 256 u_short (one for each character)
- * initialized to default_chartab and user selectable via
- * /sys/module/speakup/parameters/chartab
- */
-u_short spk_chartab[256];
-
-static u_short default_chartab[256] = {
-       B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
-       B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
-       B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
-       B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
-       WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,     /*  !"#$%&' */
-       PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC,   /* ()*+, -./ */
-       NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
-       NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,       /* 89:;<=>? */
-       PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,  /* @ABCDEFG */
-       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
-       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
-       A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC,      /* XYZ[\]^_ */
-       PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,  /* `abcdefg */
-       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
-       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
-       ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
-       B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
-       B_SYM,  /* 135 */
-       B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
-       B_CAPSYM,       /* 143 */
-       B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
-       B_SYM,  /* 151 */
-       B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
-       B_SYM,  /* 159 */
-       WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
-       B_SYM,  /* 167 */
-       B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
-       B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
-       B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
-       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
-       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
-       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
-       A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
-       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
-       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
-       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
-       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA  /* 248-255 */
-};
-
-struct task_struct *speakup_task;
-struct bleep spk_unprocessed_sound;
-static int spk_keydown;
-static u16 spk_lastkey;
-static u_char spk_close_press, keymap_flags;
-static u_char last_keycode, this_speakup_key;
-static u_long last_spk_jiffy;
-
-struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
-
-DEFINE_MUTEX(spk_mutex);
-
-static int keyboard_notifier_call(struct notifier_block *,
-                                 unsigned long code, void *param);
-
-static struct notifier_block keyboard_notifier_block = {
-       .notifier_call = keyboard_notifier_call,
-};
-
-static int vt_notifier_call(struct notifier_block *,
-                           unsigned long code, void *param);
-
-static struct notifier_block vt_notifier_block = {
-       .notifier_call = vt_notifier_call,
-};
-
-static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
-{
-       pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
-       return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
-}
-
-static void speakup_date(struct vc_data *vc)
-{
-       spk_x = spk_cx = vc->vc_x;
-       spk_y = spk_cy = vc->vc_y;
-       spk_pos = spk_cp = vc->vc_pos;
-       spk_old_attr = spk_attr;
-       spk_attr = get_attributes(vc, (u_short *)spk_pos);
-}
-
-static void bleep(u_short val)
-{
-       static const short vals[] = {
-               350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
-       };
-       short freq;
-       int time = spk_bleep_time;
-
-       freq = vals[val % 12];
-       if (val > 11)
-               freq *= (1 << (val / 12));
-       spk_unprocessed_sound.freq = freq;
-       spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
-       spk_unprocessed_sound.active = 1;
-       /* We can only have 1 active sound at a time. */
-}
-
-static void speakup_shut_up(struct vc_data *vc)
-{
-       if (spk_killed)
-               return;
-       spk_shut_up |= 0x01;
-       spk_parked &= 0xfe;
-       speakup_date(vc);
-       if (synth)
-               spk_do_flush();
-}
-
-static void speech_kill(struct vc_data *vc)
-{
-       char val = synth->is_alive(synth);
-
-       if (val == 0)
-               return;
-
-       /* re-enables synth, if disabled */
-       if (val == 2 || spk_killed) {
-               /* dead */
-               spk_shut_up &= ~0x40;
-               synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
-       } else {
-               synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
-               spk_shut_up |= 0x40;
-       }
-}
-
-static void speakup_off(struct vc_data *vc)
-{
-       if (spk_shut_up & 0x80) {
-               spk_shut_up &= 0x7f;
-               synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
-       } else {
-               spk_shut_up |= 0x80;
-               synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
-       }
-       speakup_date(vc);
-}
-
-static void speakup_parked(struct vc_data *vc)
-{
-       if (spk_parked & 0x80) {
-               spk_parked = 0;
-               synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
-       } else {
-               spk_parked |= 0x80;
-               synth_printf("%s\n", spk_msg_get(MSG_PARKED));
-       }
-}
-
-static void speakup_cut(struct vc_data *vc)
-{
-       static const char err_buf[] = "set selection failed";
-       int ret;
-
-       if (!mark_cut_flag) {
-               mark_cut_flag = 1;
-               spk_xs = (u_short)spk_x;
-               spk_ys = (u_short)spk_y;
-               spk_sel_cons = vc;
-               synth_printf("%s\n", spk_msg_get(MSG_MARK));
-               return;
-       }
-       spk_xe = (u_short)spk_x;
-       spk_ye = (u_short)spk_y;
-       mark_cut_flag = 0;
-       synth_printf("%s\n", spk_msg_get(MSG_CUT));
-
-       speakup_clear_selection();
-       ret = speakup_set_selection(tty);
-
-       switch (ret) {
-       case 0:
-               break;          /* no error */
-       case -EFAULT:
-               pr_warn("%sEFAULT\n", err_buf);
-               break;
-       case -EINVAL:
-               pr_warn("%sEINVAL\n", err_buf);
-               break;
-       case -ENOMEM:
-               pr_warn("%sENOMEM\n", err_buf);
-               break;
-       }
-}
-
-static void speakup_paste(struct vc_data *vc)
-{
-       if (mark_cut_flag) {
-               mark_cut_flag = 0;
-               synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
-       } else {
-               synth_printf("%s\n", spk_msg_get(MSG_PASTE));
-               speakup_paste_selection(tty);
-       }
-}
-
-static void say_attributes(struct vc_data *vc)
-{
-       int fg = spk_attr & 0x0f;
-       int bg = spk_attr >> 4;
-
-       if (fg > 8) {
-               synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
-               fg -= 8;
-       }
-       synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
-       if (bg > 7) {
-               synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
-               bg -= 8;
-       } else {
-               synth_printf(" %s ", spk_msg_get(MSG_ON));
-       }
-       synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
-}
-
-enum {
-       edge_top = 1,
-       edge_bottom,
-       edge_left,
-       edge_right,
-       edge_quiet
-};
-
-static void announce_edge(struct vc_data *vc, int msg_id)
-{
-       if (spk_bleeps & 1)
-               bleep(spk_y);
-       if ((spk_bleeps & 2) && (msg_id < edge_quiet))
-               synth_printf("%s\n",
-                            spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
-}
-
-static void speak_char(u16 ch)
-{
-       char *cp;
-       struct var_t *direct = spk_get_var(DIRECT);
-
-       if (ch >= 0x100 || (direct && direct->u.n.value)) {
-               if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
-                       spk_pitch_shift++;
-                       synth_printf("%s", spk_str_caps_start);
-               }
-               synth_putwc_s(ch);
-               if (ch < 0x100 && IS_CHAR(ch, B_CAP))
-                       synth_printf("%s", spk_str_caps_stop);
-               return;
-       }
-
-       cp = spk_characters[ch];
-       if (!cp) {
-               pr_info("%s: cp == NULL!\n", __func__);
-               return;
-       }
-       if (IS_CHAR(ch, B_CAP)) {
-               spk_pitch_shift++;
-               synth_printf("%s %s %s",
-                            spk_str_caps_start, cp, spk_str_caps_stop);
-       } else {
-               if (*cp == '^') {
-                       cp++;
-                       synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
-               } else {
-                       synth_printf(" %s ", cp);
-               }
-       }
-}
-
-static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
-{
-       u16 ch = ' ';
-
-       if (vc && pos) {
-               u16 w;
-               u16 c;
-
-               pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
-               w = scr_readw(pos);
-               c = w & 0xff;
-
-               if (w & vc->vc_hi_font_mask) {
-                       w &= ~vc->vc_hi_font_mask;
-                       c |= 0x100;
-               }
-
-               ch = inverse_translate(vc, c, 1);
-               *attribs = (w & 0xff00) >> 8;
-       }
-       return ch;
-}
-
-static void say_char(struct vc_data *vc)
-{
-       u16 ch;
-
-       spk_old_attr = spk_attr;
-       ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
-       if (spk_attr != spk_old_attr) {
-               if (spk_attrib_bleep & 1)
-                       bleep(spk_y);
-               if (spk_attrib_bleep & 2)
-                       say_attributes(vc);
-       }
-       speak_char(ch);
-}
-
-static void say_phonetic_char(struct vc_data *vc)
-{
-       u16 ch;
-
-       spk_old_attr = spk_attr;
-       ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
-       if (ch <= 0x7f && isalpha(ch)) {
-               ch &= 0x1f;
-               synth_printf("%s\n", phonetic[--ch]);
-       } else {
-               if (ch < 0x100 && IS_CHAR(ch, B_NUM))
-                       synth_printf("%s ", spk_msg_get(MSG_NUMBER));
-               speak_char(ch);
-       }
-}
-
-static void say_prev_char(struct vc_data *vc)
-{
-       spk_parked |= 0x01;
-       if (spk_x == 0) {
-               announce_edge(vc, edge_left);
-               return;
-       }
-       spk_x--;
-       spk_pos -= 2;
-       say_char(vc);
-}
-
-static void say_next_char(struct vc_data *vc)
-{
-       spk_parked |= 0x01;
-       if (spk_x == vc->vc_cols - 1) {
-               announce_edge(vc, edge_right);
-               return;
-       }
-       spk_x++;
-       spk_pos += 2;
-       say_char(vc);
-}
-
-/* get_word - will first check to see if the character under the
- * reading cursor is a space and if spk_say_word_ctl is true it will
- * return the word space.  If spk_say_word_ctl is not set it will check to
- * see if there is a word starting on the next position to the right
- * and return that word if it exists.  If it does not exist it will
- * move left to the beginning of any previous word on the line or the
- * beginning off the line whichever comes first..
- */
-
-static u_long get_word(struct vc_data *vc)
-{
-       u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
-       u16 ch;
-       u16 attr_ch;
-       u_char temp;
-
-       spk_old_attr = spk_attr;
-       ch = get_char(vc, (u_short *)tmp_pos, &temp);
-
-/* decided to take out the sayword if on a space (mis-information */
-       if (spk_say_word_ctl && ch == SPACE) {
-               *buf = '\0';
-               synth_printf("%s\n", spk_msg_get(MSG_SPACE));
-               return 0;
-       } else if (tmpx < vc->vc_cols - 2 &&
-                  (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
-                  get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
-               tmp_pos += 2;
-               tmpx++;
-       } else {
-               while (tmpx > 0) {
-                       ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
-                       if ((ch == SPACE || ch == 0 ||
-                            (ch < 0x100 && IS_WDLM(ch))) &&
-                           get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
-                               break;
-                       tmp_pos -= 2;
-                       tmpx--;
-               }
-       }
-       attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
-       buf[cnt++] = attr_ch;
-       while (tmpx < vc->vc_cols - 1) {
-               tmp_pos += 2;
-               tmpx++;
-               ch = get_char(vc, (u_short *)tmp_pos, &temp);
-               if (ch == SPACE || ch == 0 ||
-                   (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
-                    ch > SPACE))
-                       break;
-               buf[cnt++] = ch;
-       }
-       buf[cnt] = '\0';
-       return cnt;
-}
-
-static void say_word(struct vc_data *vc)
-{
-       u_long cnt = get_word(vc);
-       u_short saved_punc_mask = spk_punc_mask;
-
-       if (cnt == 0)
-               return;
-       spk_punc_mask = PUNC;
-       buf[cnt++] = SPACE;
-       spkup_write(buf, cnt);
-       spk_punc_mask = saved_punc_mask;
-}
-
-static void say_prev_word(struct vc_data *vc)
-{
-       u_char temp;
-       u16 ch;
-       u_short edge_said = 0, last_state = 0, state = 0;
-
-       spk_parked |= 0x01;
-
-       if (spk_x == 0) {
-               if (spk_y == 0) {
-                       announce_edge(vc, edge_top);
-                       return;
-               }
-               spk_y--;
-               spk_x = vc->vc_cols;
-               edge_said = edge_quiet;
-       }
-       while (1) {
-               if (spk_x == 0) {
-                       if (spk_y == 0) {
-                               edge_said = edge_top;
-                               break;
-                       }
-                       if (edge_said != edge_quiet)
-                               edge_said = edge_left;
-                       if (state > 0)
-                               break;
-                       spk_y--;
-                       spk_x = vc->vc_cols - 1;
-               } else {
-                       spk_x--;
-               }
-               spk_pos -= 2;
-               ch = get_char(vc, (u_short *)spk_pos, &temp);
-               if (ch == SPACE || ch == 0)
-                       state = 0;
-               else if (ch < 0x100 && IS_WDLM(ch))
-                       state = 1;
-               else
-                       state = 2;
-               if (state < last_state) {
-                       spk_pos += 2;
-                       spk_x++;
-                       break;
-               }
-               last_state = state;
-       }
-       if (spk_x == 0 && edge_said == edge_quiet)
-               edge_said = edge_left;
-       if (edge_said > 0 && edge_said < edge_quiet)
-               announce_edge(vc, edge_said);
-       say_word(vc);
-}
-
-static void say_next_word(struct vc_data *vc)
-{
-       u_char temp;
-       u16 ch;
-       u_short edge_said = 0, last_state = 2, state = 0;
-
-       spk_parked |= 0x01;
-       if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
-               announce_edge(vc, edge_bottom);
-               return;
-       }
-       while (1) {
-               ch = get_char(vc, (u_short *)spk_pos, &temp);
-               if (ch == SPACE || ch == 0)
-                       state = 0;
-               else if (ch < 0x100 && IS_WDLM(ch))
-                       state = 1;
-               else
-                       state = 2;
-               if (state > last_state)
-                       break;
-               if (spk_x >= vc->vc_cols - 1) {
-                       if (spk_y == vc->vc_rows - 1) {
-                               edge_said = edge_bottom;
-                               break;
-                       }
-                       state = 0;
-                       spk_y++;
-                       spk_x = 0;
-                       edge_said = edge_right;
-               } else {
-                       spk_x++;
-               }
-               spk_pos += 2;
-               last_state = state;
-       }
-       if (edge_said > 0)
-               announce_edge(vc, edge_said);
-       say_word(vc);
-}
-
-static void spell_word(struct vc_data *vc)
-{
-       static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
-       u16 *cp = buf;
-       char *cp1;
-       char *str_cap = spk_str_caps_stop;
-       char *last_cap = spk_str_caps_stop;
-       struct var_t *direct = spk_get_var(DIRECT);
-       u16 ch;
-
-       if (!get_word(vc))
-               return;
-       while ((ch = *cp)) {
-               if (cp != buf)
-                       synth_printf(" %s ", delay_str[spk_spell_delay]);
-               /* FIXME: Non-latin1 considered as lower case */
-               if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
-                       str_cap = spk_str_caps_start;
-                       if (*spk_str_caps_stop)
-                               spk_pitch_shift++;
-                       else    /* synth has no pitch */
-                               last_cap = spk_str_caps_stop;
-               } else {
-                       str_cap = spk_str_caps_stop;
-               }
-               if (str_cap != last_cap) {
-                       synth_printf("%s", str_cap);
-                       last_cap = str_cap;
-               }
-               if (ch >= 0x100 || (direct && direct->u.n.value)) {
-                       synth_putwc_s(ch);
-               } else if (this_speakup_key == SPELL_PHONETIC &&
-                   ch <= 0x7f && isalpha(ch)) {
-                       ch &= 0x1f;
-                       cp1 = phonetic[--ch];
-                       synth_printf("%s", cp1);
-               } else {
-                       cp1 = spk_characters[ch];
-                       if (*cp1 == '^') {
-                               synth_printf("%s", spk_msg_get(MSG_CTRL));
-                               cp1++;
-                       }
-                       synth_printf("%s", cp1);
-               }
-               cp++;
-       }
-       if (str_cap != spk_str_caps_stop)
-               synth_printf("%s", spk_str_caps_stop);
-}
-
-static int get_line(struct vc_data *vc)
-{
-       u_long tmp = spk_pos - (spk_x * 2);
-       int i = 0;
-       u_char tmp2;
-
-       spk_old_attr = spk_attr;
-       spk_attr = get_attributes(vc, (u_short *)spk_pos);
-       for (i = 0; i < vc->vc_cols; i++) {
-               buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
-               tmp += 2;
-       }
-       for (--i; i >= 0; i--)
-               if (buf[i] != SPACE)
-                       break;
-       return ++i;
-}
-
-static void say_line(struct vc_data *vc)
-{
-       int i = get_line(vc);
-       u16 *cp;
-       u_short saved_punc_mask = spk_punc_mask;
-
-       if (i == 0) {
-               synth_printf("%s\n", spk_msg_get(MSG_BLANK));
-               return;
-       }
-       buf[i++] = '\n';
-       if (this_speakup_key == SAY_LINE_INDENT) {
-               cp = buf;
-               while (*cp == SPACE)
-                       cp++;
-               synth_printf("%zd, ", (cp - buf) + 1);
-       }
-       spk_punc_mask = spk_punc_masks[spk_reading_punc];
-       spkup_write(buf, i);
-       spk_punc_mask = saved_punc_mask;
-}
-
-static void say_prev_line(struct vc_data *vc)
-{
-       spk_parked |= 0x01;
-       if (spk_y == 0) {
-               announce_edge(vc, edge_top);
-               return;
-       }
-       spk_y--;
-       spk_pos -= vc->vc_size_row;
-       say_line(vc);
-}
-
-static void say_next_line(struct vc_data *vc)
-{
-       spk_parked |= 0x01;
-       if (spk_y == vc->vc_rows - 1) {
-               announce_edge(vc, edge_bottom);
-               return;
-       }
-       spk_y++;
-       spk_pos += vc->vc_size_row;
-       say_line(vc);
-}
-
-static int say_from_to(struct vc_data *vc, u_long from, u_long to,
-                      int read_punc)
-{
-       int i = 0;
-       u_char tmp;
-       u_short saved_punc_mask = spk_punc_mask;
-
-       spk_old_attr = spk_attr;
-       spk_attr = get_attributes(vc, (u_short *)from);
-       while (from < to) {
-               buf[i++] = get_char(vc, (u_short *)from, &tmp);
-               from += 2;
-               if (i >= vc->vc_size_row)
-                       break;
-       }
-       for (--i; i >= 0; i--)
-               if (buf[i] != SPACE)
-                       break;
-       buf[++i] = SPACE;
-       buf[++i] = '\0';
-       if (i < 1)
-               return i;
-       if (read_punc)
-               spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
-       spkup_write(buf, i);
-       if (read_punc)
-               spk_punc_mask = saved_punc_mask;
-       return i - 1;
-}
-
-static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
-                            int read_punc)
-{
-       u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
-       u_long end = start + (to * 2);
-
-       start += from * 2;
-       if (say_from_to(vc, start, end, read_punc) <= 0)
-               if (cursor_track != read_all_mode)
-                       synth_printf("%s\n", spk_msg_get(MSG_BLANK));
-}
-
-/* Sentence Reading Commands */
-
-static int currsentence;
-static int numsentences[2];
-static u16 *sentbufend[2];
-static u16 *sentmarks[2][10];
-static int currbuf;
-static int bn;
-static u16 sentbuf[2][256];
-
-static int say_sentence_num(int num, int prev)
-{
-       bn = currbuf;
-       currsentence = num + 1;
-       if (prev && --bn == -1)
-               bn = 1;
-
-       if (num > numsentences[bn])
-               return 0;
-
-       spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
-       return 1;
-}
-
-static int get_sentence_buf(struct vc_data *vc, int read_punc)
-{
-       u_long start, end;
-       int i, bn;
-       u_char tmp;
-
-       currbuf++;
-       if (currbuf == 2)
-               currbuf = 0;
-       bn = currbuf;
-       start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
-       end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
-
-       numsentences[bn] = 0;
-       sentmarks[bn][0] = &sentbuf[bn][0];
-       i = 0;
-       spk_old_attr = spk_attr;
-       spk_attr = get_attributes(vc, (u_short *)start);
-
-       while (start < end) {
-               sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
-               if (i > 0) {
-                       if (sentbuf[bn][i] == SPACE &&
-                           sentbuf[bn][i - 1] == '.' &&
-                           numsentences[bn] < 9) {
-                               /* Sentence Marker */
-                               numsentences[bn]++;
-                               sentmarks[bn][numsentences[bn]] =
-                                   &sentbuf[bn][i];
-                       }
-               }
-               i++;
-               start += 2;
-               if (i >= vc->vc_size_row)
-                       break;
-       }
-
-       for (--i; i >= 0; i--)
-               if (sentbuf[bn][i] != SPACE)
-                       break;
-
-       if (i < 1)
-               return -1;
-
-       sentbuf[bn][++i] = SPACE;
-       sentbuf[bn][++i] = '\0';
-
-       sentbufend[bn] = &sentbuf[bn][i];
-       return numsentences[bn];
-}
-
-static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
-{
-       u_long start = vc->vc_origin, end;
-
-       if (from > 0)
-               start += from * vc->vc_size_row;
-       if (to > vc->vc_rows)
-               to = vc->vc_rows;
-       end = vc->vc_origin + (to * vc->vc_size_row);
-       for (from = start; from < end; from = to) {
-               to = from + vc->vc_size_row;
-               say_from_to(vc, from, to, 1);
-       }
-}
-
-static void say_screen(struct vc_data *vc)
-{
-       say_screen_from_to(vc, 0, vc->vc_rows);
-}
-
-static void speakup_win_say(struct vc_data *vc)
-{
-       u_long start, end, from, to;
-
-       if (win_start < 2) {
-               synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
-               return;
-       }
-       start = vc->vc_origin + (win_top * vc->vc_size_row);
-       end = vc->vc_origin + (win_bottom * vc->vc_size_row);
-       while (start <= end) {
-               from = start + (win_left * 2);
-               to = start + (win_right * 2);
-               say_from_to(vc, from, to, 1);
-               start += vc->vc_size_row;
-       }
-}
-
-static void top_edge(struct vc_data *vc)
-{
-       spk_parked |= 0x01;
-       spk_pos = vc->vc_origin + 2 * spk_x;
-       spk_y = 0;
-       say_line(vc);
-}
-
-static void bottom_edge(struct vc_data *vc)
-{
-       spk_parked |= 0x01;
-       spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
-       spk_y = vc->vc_rows - 1;
-       say_line(vc);
-}
-
-static void left_edge(struct vc_data *vc)
-{
-       spk_parked |= 0x01;
-       spk_pos -= spk_x * 2;
-       spk_x = 0;
-       say_char(vc);
-}
-
-static void right_edge(struct vc_data *vc)
-{
-       spk_parked |= 0x01;
-       spk_pos += (vc->vc_cols - spk_x - 1) * 2;
-       spk_x = vc->vc_cols - 1;
-       say_char(vc);
-}
-
-static void say_first_char(struct vc_data *vc)
-{
-       int i, len = get_line(vc);
-       u16 ch;
-
-       spk_parked |= 0x01;
-       if (len == 0) {
-               synth_printf("%s\n", spk_msg_get(MSG_BLANK));
-               return;
-       }
-       for (i = 0; i < len; i++)
-               if (buf[i] != SPACE)
-                       break;
-       ch = buf[i];
-       spk_pos -= (spk_x - i) * 2;
-       spk_x = i;
-       synth_printf("%d, ", ++i);
-       speak_char(ch);
-}
-
-static void say_last_char(struct vc_data *vc)
-{
-       int len = get_line(vc);
-       u16 ch;
-
-       spk_parked |= 0x01;
-       if (len == 0) {
-               synth_printf("%s\n", spk_msg_get(MSG_BLANK));
-               return;
-       }
-       ch = buf[--len];
-       spk_pos -= (spk_x - len) * 2;
-       spk_x = len;
-       synth_printf("%d, ", ++len);
-       speak_char(ch);
-}
-
-static void say_position(struct vc_data *vc)
-{
-       synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
-                    vc->vc_num + 1);
-       synth_printf("\n");
-}
-
-/* Added by brianb */
-static void say_char_num(struct vc_data *vc)
-{
-       u_char tmp;
-       u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
-
-       synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
-}
-
-/* these are stub functions to keep keyboard.c happy. */
-
-static void say_from_top(struct vc_data *vc)
-{
-       say_screen_from_to(vc, 0, spk_y);
-}
-
-static void say_to_bottom(struct vc_data *vc)
-{
-       say_screen_from_to(vc, spk_y, vc->vc_rows);
-}
-
-static void say_from_left(struct vc_data *vc)
-{
-       say_line_from_to(vc, 0, spk_x, 1);
-}
-
-static void say_to_right(struct vc_data *vc)
-{
-       say_line_from_to(vc, spk_x, vc->vc_cols, 1);
-}
-
-/* end of stub functions. */
-
-static void spkup_write(const u16 *in_buf, int count)
-{
-       static int rep_count;
-       static u16 ch = '\0', old_ch = '\0';
-       static u_short char_type, last_type;
-       int in_count = count;
-
-       spk_keydown = 0;
-       while (count--) {
-               if (cursor_track == read_all_mode) {
-                       /* Insert Sentence Index */
-                       if ((in_buf == sentmarks[bn][currsentence]) &&
-                           (currsentence <= numsentences[bn]))
-                               synth_insert_next_index(currsentence++);
-               }
-               ch = *in_buf++;
-               if (ch < 0x100)
-                       char_type = spk_chartab[ch];
-               else
-                       char_type = ALPHA;
-               if (ch == old_ch && !(char_type & B_NUM)) {
-                       if (++rep_count > 2)
-                               continue;
-               } else {
-                       if ((last_type & CH_RPT) && rep_count > 2) {
-                               synth_printf(" ");
-                               synth_printf(spk_msg_get(MSG_REPEAT_DESC),
-                                            ++rep_count);
-                               synth_printf(" ");
-                       }
-                       rep_count = 0;
-               }
-               if (ch == spk_lastkey) {
-                       rep_count = 0;
-                       if (spk_key_echo == 1 && ch >= MINECHOCHAR)
-                               speak_char(ch);
-               } else if (char_type & B_ALPHA) {
-                       if ((synth_flags & SF_DEC) && (last_type & PUNC))
-                               synth_buffer_add(SPACE);
-                       synth_putwc_s(ch);
-               } else if (char_type & B_NUM) {
-                       rep_count = 0;
-                       synth_putwc_s(ch);
-               } else if (char_type & spk_punc_mask) {
-                       speak_char(ch);
-                       char_type &= ~PUNC;     /* for dec nospell processing */
-               } else if (char_type & SYNTH_OK) {
-                       /* these are usually puncts like . and , which synth
-                        * needs for expression.
-                        * suppress multiple to get rid of long pauses and
-                        * clear repeat count
-                        * so if someone has
-                        * repeats on you don't get nothing repeated count
-                        */
-                       if (ch != old_ch)
-                               synth_putwc_s(ch);
-                       else
-                               rep_count = 0;
-               } else {
-/* send space and record position, if next is num overwrite space */
-                       if (old_ch != ch)
-                               synth_buffer_add(SPACE);
-                       else
-                               rep_count = 0;
-               }
-               old_ch = ch;
-               last_type = char_type;
-       }
-       spk_lastkey = 0;
-       if (in_count > 2 && rep_count > 2) {
-               if (last_type & CH_RPT) {
-                       synth_printf(" ");
-                       synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
-                                    ++rep_count);
-                       synth_printf(" ");
-               }
-               rep_count = 0;
-       }
-}
-
-static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
-
-static void read_all_doc(struct vc_data *vc);
-static void cursor_done(struct timer_list *unused);
-static DEFINE_TIMER(cursor_timer, cursor_done);
-
-static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
-{
-       unsigned long flags;
-
-       if (!synth || up_flag || spk_killed)
-               return;
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       if (cursor_track == read_all_mode) {
-               switch (value) {
-               case KVAL(K_SHIFT):
-                       del_timer(&cursor_timer);
-                       spk_shut_up &= 0xfe;
-                       spk_do_flush();
-                       read_all_doc(vc);
-                       break;
-               case KVAL(K_CTRL):
-                       del_timer(&cursor_timer);
-                       cursor_track = prev_cursor_track;
-                       spk_shut_up &= 0xfe;
-                       spk_do_flush();
-                       break;
-               }
-       } else {
-               spk_shut_up &= 0xfe;
-               spk_do_flush();
-       }
-       if (spk_say_ctrl && value < NUM_CTL_LABELS)
-               synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-}
-
-static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       if (up_flag) {
-               spk_lastkey = 0;
-               spk_keydown = 0;
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return;
-       }
-       if (!synth || spk_killed) {
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return;
-       }
-       spk_shut_up &= 0xfe;
-       spk_lastkey = value;
-       spk_keydown++;
-       spk_parked &= 0xfe;
-       if (spk_key_echo == 2 && value >= MINECHOCHAR)
-               speak_char(value);
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-}
-
-int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
-{
-       int i = 0, states, key_data_len;
-       const u_char *cp = key_info;
-       u_char *cp1 = k_buffer;
-       u_char ch, version, num_keys;
-
-       version = *cp++;
-       if (version != KEY_MAP_VER) {
-               pr_debug("version found %d should be %d\n",
-                        version, KEY_MAP_VER);
-               return -EINVAL;
-       }
-       num_keys = *cp;
-       states = (int)cp[1];
-       key_data_len = (states + 1) * (num_keys + 1);
-       if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
-               pr_debug("too many key_infos (%d over %u)\n",
-                        key_data_len + SHIFT_TBL_SIZE + 4,
-                        (unsigned int)(sizeof(spk_key_buf)));
-               return -EINVAL;
-       }
-       memset(k_buffer, 0, SHIFT_TBL_SIZE);
-       memset(spk_our_keys, 0, sizeof(spk_our_keys));
-       spk_shift_table = k_buffer;
-       spk_our_keys[0] = spk_shift_table;
-       cp1 += SHIFT_TBL_SIZE;
-       memcpy(cp1, cp, key_data_len + 3);
-       /* get num_keys, states and data */
-       cp1 += 2;               /* now pointing at shift states */
-       for (i = 1; i <= states; i++) {
-               ch = *cp1++;
-               if (ch >= SHIFT_TBL_SIZE) {
-                       pr_debug("(%d) not valid shift state (max_allowed = %d)\n",
-                                ch, SHIFT_TBL_SIZE);
-                       return -EINVAL;
-               }
-               spk_shift_table[ch] = i;
-       }
-       keymap_flags = *cp1++;
-       while ((ch = *cp1)) {
-               if (ch >= MAX_KEY) {
-                       pr_debug("(%d), not valid key, (max_allowed = %d)\n",
-                                ch, MAX_KEY);
-                       return -EINVAL;
-               }
-               spk_our_keys[ch] = cp1;
-               cp1 += states + 1;
-       }
-       return 0;
-}
-
-static struct var_t spk_vars[] = {
-       /* bell must be first to set high limit */
-       {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
-       {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
-       {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
-       {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
-       {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
-       {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
-       {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
-       {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
-       {SAY_CONTROL, TOGGLE_0},
-       {SAY_WORD_CTL, TOGGLE_0},
-       {NO_INTERRUPT, TOGGLE_0},
-       {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
-       V_LAST_VAR
-};
-
-static void toggle_cursoring(struct vc_data *vc)
-{
-       if (cursor_track == read_all_mode)
-               cursor_track = prev_cursor_track;
-       if (++cursor_track >= CT_Max)
-               cursor_track = 0;
-       synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
-}
-
-void spk_reset_default_chars(void)
-{
-       int i;
-
-       /* First, free any non-default */
-       for (i = 0; i < 256; i++) {
-               if (spk_characters[i] &&
-                   (spk_characters[i] != spk_default_chars[i]))
-                       kfree(spk_characters[i]);
-       }
-
-       memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
-}
-
-void spk_reset_default_chartab(void)
-{
-       memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
-}
-
-static const struct st_bits_data *pb_edit;
-
-static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
-{
-       short mask = pb_edit->mask, ch_type = spk_chartab[ch];
-
-       if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
-               return -1;
-       if (ch == SPACE) {
-               synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
-               spk_special_handler = NULL;
-               return 1;
-       }
-       if (mask < PUNC && !(ch_type & PUNC))
-               return -1;
-       spk_chartab[ch] ^= mask;
-       speak_char(ch);
-       synth_printf(" %s\n",
-                    (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
-                    spk_msg_get(MSG_OFF));
-       return 1;
-}
-
-/* Allocation concurrency is protected by the console semaphore */
-static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
-{
-       int vc_num;
-
-       vc_num = vc->vc_num;
-       if (!speakup_console[vc_num]) {
-               speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
-                                                 gfp_flags);
-               if (!speakup_console[vc_num])
-                       return -ENOMEM;
-               speakup_date(vc);
-       } else if (!spk_parked) {
-               speakup_date(vc);
-       }
-
-       return 0;
-}
-
-static void speakup_deallocate(struct vc_data *vc)
-{
-       int vc_num;
-
-       vc_num = vc->vc_num;
-       kfree(speakup_console[vc_num]);
-       speakup_console[vc_num] = NULL;
-}
-
-static u_char is_cursor;
-static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
-static int cursor_con;
-
-static void reset_highlight_buffers(struct vc_data *);
-
-static int read_all_key;
-
-static int in_keyboard_notifier;
-
-static void start_read_all_timer(struct vc_data *vc, int command);
-
-enum {
-       RA_NOTHING,
-       RA_NEXT_SENT,
-       RA_PREV_LINE,
-       RA_NEXT_LINE,
-       RA_PREV_SENT,
-       RA_DOWN_ARROW,
-       RA_TIMER,
-       RA_FIND_NEXT_SENT,
-       RA_FIND_PREV_SENT,
-};
-
-static void kbd_fakekey2(struct vc_data *vc, int command)
-{
-       del_timer(&cursor_timer);
-       speakup_fake_down_arrow();
-       start_read_all_timer(vc, command);
-}
-
-static void read_all_doc(struct vc_data *vc)
-{
-       if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
-               return;
-       if (!synth_supports_indexing())
-               return;
-       if (cursor_track != read_all_mode)
-               prev_cursor_track = cursor_track;
-       cursor_track = read_all_mode;
-       spk_reset_index_count(0);
-       if (get_sentence_buf(vc, 0) == -1) {
-               del_timer(&cursor_timer);
-               if (!in_keyboard_notifier)
-                       speakup_fake_down_arrow();
-               start_read_all_timer(vc, RA_DOWN_ARROW);
-       } else {
-               say_sentence_num(0, 0);
-               synth_insert_next_index(0);
-               start_read_all_timer(vc, RA_TIMER);
-       }
-}
-
-static void stop_read_all(struct vc_data *vc)
-{
-       del_timer(&cursor_timer);
-       cursor_track = prev_cursor_track;
-       spk_shut_up &= 0xfe;
-       spk_do_flush();
-}
-
-static void start_read_all_timer(struct vc_data *vc, int command)
-{
-       struct var_t *cursor_timeout;
-
-       cursor_con = vc->vc_num;
-       read_all_key = command;
-       cursor_timeout = spk_get_var(CURSOR_TIME);
-       mod_timer(&cursor_timer,
-                 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
-}
-
-static void handle_cursor_read_all(struct vc_data *vc, int command)
-{
-       int indcount, sentcount, rv, sn;
-
-       switch (command) {
-       case RA_NEXT_SENT:
-               /* Get Current Sentence */
-               spk_get_index_count(&indcount, &sentcount);
-               /*printk("%d %d  ", indcount, sentcount); */
-               spk_reset_index_count(sentcount + 1);
-               if (indcount == 1) {
-                       if (!say_sentence_num(sentcount + 1, 0)) {
-                               kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
-                               return;
-                       }
-                       synth_insert_next_index(0);
-               } else {
-                       sn = 0;
-                       if (!say_sentence_num(sentcount + 1, 1)) {
-                               sn = 1;
-                               spk_reset_index_count(sn);
-                       } else {
-                               synth_insert_next_index(0);
-                       }
-                       if (!say_sentence_num(sn, 0)) {
-                               kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
-                               return;
-                       }
-                       synth_insert_next_index(0);
-               }
-               start_read_all_timer(vc, RA_TIMER);
-               break;
-       case RA_PREV_SENT:
-               break;
-       case RA_NEXT_LINE:
-               read_all_doc(vc);
-               break;
-       case RA_PREV_LINE:
-               break;
-       case RA_DOWN_ARROW:
-               if (get_sentence_buf(vc, 0) == -1) {
-                       kbd_fakekey2(vc, RA_DOWN_ARROW);
-               } else {
-                       say_sentence_num(0, 0);
-                       synth_insert_next_index(0);
-                       start_read_all_timer(vc, RA_TIMER);
-               }
-               break;
-       case RA_FIND_NEXT_SENT:
-               rv = get_sentence_buf(vc, 0);
-               if (rv == -1)
-                       read_all_doc(vc);
-               if (rv == 0) {
-                       kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
-               } else {
-                       say_sentence_num(1, 0);
-                       synth_insert_next_index(0);
-                       start_read_all_timer(vc, RA_TIMER);
-               }
-               break;
-       case RA_FIND_PREV_SENT:
-               break;
-       case RA_TIMER:
-               spk_get_index_count(&indcount, &sentcount);
-               if (indcount < 2)
-                       kbd_fakekey2(vc, RA_DOWN_ARROW);
-               else
-                       start_read_all_timer(vc, RA_TIMER);
-               break;
-       }
-}
-
-static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       if (cursor_track == read_all_mode) {
-               spk_parked &= 0xfe;
-               if (!synth || up_flag || spk_shut_up) {
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       return NOTIFY_STOP;
-               }
-               del_timer(&cursor_timer);
-               spk_shut_up &= 0xfe;
-               spk_do_flush();
-               start_read_all_timer(vc, value + 1);
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return NOTIFY_STOP;
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return NOTIFY_OK;
-}
-
-static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
-{
-       unsigned long flags;
-       struct var_t *cursor_timeout;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       spk_parked &= 0xfe;
-       if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return;
-       }
-       spk_shut_up &= 0xfe;
-       if (spk_no_intr)
-               spk_do_flush();
-/* the key press flushes if !no_inter but we want to flush on cursor
- * moves regardless of no_inter state
- */
-       is_cursor = value + 1;
-       old_cursor_pos = vc->vc_pos;
-       old_cursor_x = vc->vc_x;
-       old_cursor_y = vc->vc_y;
-       speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
-       cursor_con = vc->vc_num;
-       if (cursor_track == CT_Highlight)
-               reset_highlight_buffers(vc);
-       cursor_timeout = spk_get_var(CURSOR_TIME);
-       mod_timer(&cursor_timer,
-                 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-}
-
-static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
-{
-       int i, bi, hi;
-       int vc_num = vc->vc_num;
-
-       bi = (vc->vc_attr & 0x70) >> 4;
-       hi = speakup_console[vc_num]->ht.highsize[bi];
-
-       i = 0;
-       if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
-               speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
-               speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
-               speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
-       }
-       while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
-               if (ic[i] > 32) {
-                       speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
-                       hi++;
-               } else if ((ic[i] == 32) && (hi != 0)) {
-                       if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
-                           32) {
-                               speakup_console[vc_num]->ht.highbuf[bi][hi] =
-                                   ic[i];
-                               hi++;
-                       }
-               }
-               i++;
-       }
-       speakup_console[vc_num]->ht.highsize[bi] = hi;
-}
-
-static void reset_highlight_buffers(struct vc_data *vc)
-{
-       int i;
-       int vc_num = vc->vc_num;
-
-       for (i = 0; i < 8; i++)
-               speakup_console[vc_num]->ht.highsize[i] = 0;
-}
-
-static int count_highlight_color(struct vc_data *vc)
-{
-       int i, bg;
-       int cc;
-       int vc_num = vc->vc_num;
-       u16 ch;
-       u16 *start = (u16 *)vc->vc_origin;
-
-       for (i = 0; i < 8; i++)
-               speakup_console[vc_num]->ht.bgcount[i] = 0;
-
-       for (i = 0; i < vc->vc_rows; i++) {
-               u16 *end = start + vc->vc_cols * 2;
-               u16 *ptr;
-
-               for (ptr = start; ptr < end; ptr++) {
-                       ch = get_attributes(vc, ptr);
-                       bg = (ch & 0x70) >> 4;
-                       speakup_console[vc_num]->ht.bgcount[bg]++;
-               }
-               start += vc->vc_size_row;
-       }
-
-       cc = 0;
-       for (i = 0; i < 8; i++)
-               if (speakup_console[vc_num]->ht.bgcount[i] > 0)
-                       cc++;
-       return cc;
-}
-
-static int get_highlight_color(struct vc_data *vc)
-{
-       int i, j;
-       unsigned int cptr[8];
-       int vc_num = vc->vc_num;
-
-       for (i = 0; i < 8; i++)
-               cptr[i] = i;
-
-       for (i = 0; i < 7; i++)
-               for (j = i + 1; j < 8; j++)
-                       if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
-                           speakup_console[vc_num]->ht.bgcount[cptr[j]])
-                               swap(cptr[i], cptr[j]);
-
-       for (i = 0; i < 8; i++)
-               if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
-                       if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
-                               return cptr[i];
-       return -1;
-}
-
-static int speak_highlight(struct vc_data *vc)
-{
-       int hc, d;
-       int vc_num = vc->vc_num;
-
-       if (count_highlight_color(vc) == 1)
-               return 0;
-       hc = get_highlight_color(vc);
-       if (hc != -1) {
-               d = vc->vc_y - speakup_console[vc_num]->ht.cy;
-               if ((d == 1) || (d == -1))
-                       if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
-                               return 0;
-               spk_parked |= 0x01;
-               spk_do_flush();
-               spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
-                           speakup_console[vc_num]->ht.highsize[hc]);
-               spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
-               spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
-               spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
-               return 1;
-       }
-       return 0;
-}
-
-static void cursor_done(struct timer_list *unused)
-{
-       struct vc_data *vc = vc_cons[cursor_con].d;
-       unsigned long flags;
-
-       del_timer(&cursor_timer);
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       if (cursor_con != fg_console) {
-               is_cursor = 0;
-               goto out;
-       }
-       speakup_date(vc);
-       if (win_enabled) {
-               if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
-                   vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
-                       spk_keydown = 0;
-                       is_cursor = 0;
-                       goto out;
-               }
-       }
-       if (cursor_track == read_all_mode) {
-               handle_cursor_read_all(vc, read_all_key);
-               goto out;
-       }
-       if (cursor_track == CT_Highlight) {
-               if (speak_highlight(vc)) {
-                       spk_keydown = 0;
-                       is_cursor = 0;
-                       goto out;
-               }
-       }
-       if (cursor_track == CT_Window)
-               speakup_win_say(vc);
-       else if (is_cursor == 1 || is_cursor == 4)
-               say_line_from_to(vc, 0, vc->vc_cols, 0);
-       else
-               say_char(vc);
-       spk_keydown = 0;
-       is_cursor = 0;
-out:
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-}
-
-/* called by: vt_notifier_call() */
-static void speakup_bs(struct vc_data *vc)
-{
-       unsigned long flags;
-
-       if (!speakup_console[vc->vc_num])
-               return;
-       if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
-               /* Speakup output, discard */
-               return;
-       if (!spk_parked)
-               speakup_date(vc);
-       if (spk_shut_up || !synth) {
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return;
-       }
-       if (vc->vc_num == fg_console && spk_keydown) {
-               spk_keydown = 0;
-               if (!is_cursor)
-                       say_char(vc);
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-}
-
-/* called by: vt_notifier_call() */
-static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
-{
-       unsigned long flags;
-
-       if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
-               return;
-       if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
-               /* Speakup output, discard */
-               return;
-       if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
-               bleep(3);
-       if ((is_cursor) || (cursor_track == read_all_mode)) {
-               if (cursor_track == CT_Highlight)
-                       update_color_buffer(vc, str, len);
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return;
-       }
-       if (win_enabled) {
-               if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
-                   vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       return;
-               }
-       }
-
-       spkup_write(str, len);
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-}
-
-static void speakup_con_update(struct vc_data *vc)
-{
-       unsigned long flags;
-
-       if (!speakup_console[vc->vc_num] || spk_parked)
-               return;
-       if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
-               /* Speakup output, discard */
-               return;
-       speakup_date(vc);
-       if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
-               synth_printf("%s", spk_str_pause);
-               spk_paused = true;
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-}
-
-static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
-{
-       unsigned long flags;
-       int on_off = 2;
-       char *label;
-
-       if (!synth || up_flag || spk_killed)
-               return;
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       spk_shut_up &= 0xfe;
-       if (spk_no_intr)
-               spk_do_flush();
-       switch (value) {
-       case KVAL(K_CAPS):
-               label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
-               on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
-               break;
-       case KVAL(K_NUM):
-               label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
-               on_off = vt_get_leds(fg_console, VC_NUMLOCK);
-               break;
-       case KVAL(K_HOLD):
-               label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
-               on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
-               if (speakup_console[vc->vc_num])
-                       speakup_console[vc->vc_num]->tty_stopped = on_off;
-               break;
-       default:
-               spk_parked &= 0xfe;
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return;
-       }
-       if (on_off < 2)
-               synth_printf("%s %s\n",
-                            label, spk_msg_get(MSG_STATUS_START + on_off));
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-}
-
-static int inc_dec_var(u_char value)
-{
-       struct st_var_header *p_header;
-       struct var_t *var_data;
-       char num_buf[32];
-       char *cp = num_buf;
-       char *pn;
-       int var_id = (int)value - VAR_START;
-       int how = (var_id & 1) ? E_INC : E_DEC;
-
-       var_id = var_id / 2 + FIRST_SET_VAR;
-       p_header = spk_get_var_header(var_id);
-       if (!p_header)
-               return -1;
-       if (p_header->var_type != VAR_NUM)
-               return -1;
-       var_data = p_header->data;
-       if (spk_set_num_var(1, p_header, how) != 0)
-               return -1;
-       if (!spk_close_press) {
-               for (pn = p_header->name; *pn; pn++) {
-                       if (*pn == '_')
-                               *cp = SPACE;
-                       else
-                               *cp++ = *pn;
-               }
-       }
-       snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
-                var_data->u.n.value);
-       synth_printf("%s", num_buf);
-       return 0;
-}
-
-static void speakup_win_set(struct vc_data *vc)
-{
-       char info[40];
-
-       if (win_start > 1) {
-               synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
-               return;
-       }
-       if (spk_x < win_left || spk_y < win_top) {
-               synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
-               return;
-       }
-       if (win_start && spk_x == win_left && spk_y == win_top) {
-               win_left = 0;
-               win_right = vc->vc_cols - 1;
-               win_bottom = spk_y;
-               snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
-                        (int)win_top + 1);
-       } else {
-               if (!win_start) {
-                       win_top = spk_y;
-                       win_left = spk_x;
-               } else {
-                       win_bottom = spk_y;
-                       win_right = spk_x;
-               }
-               snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
-                        (win_start) ?
-                               spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
-                        (int)spk_y + 1, (int)spk_x + 1);
-       }
-       synth_printf("%s\n", info);
-       win_start++;
-}
-
-static void speakup_win_clear(struct vc_data *vc)
-{
-       win_top = 0;
-       win_bottom = 0;
-       win_left = 0;
-       win_right = 0;
-       win_start = 0;
-       synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
-}
-
-static void speakup_win_enable(struct vc_data *vc)
-{
-       if (win_start < 2) {
-               synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
-               return;
-       }
-       win_enabled ^= 1;
-       if (win_enabled)
-               synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
-       else
-               synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
-}
-
-static void speakup_bits(struct vc_data *vc)
-{
-       int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
-
-       if (spk_special_handler || val < 1 || val > 6) {
-               synth_printf("%s\n", spk_msg_get(MSG_ERROR));
-               return;
-       }
-       pb_edit = &spk_punc_info[val];
-       synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
-       spk_special_handler = edit_bits;
-}
-
-static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
-{
-       static u_char goto_buf[8];
-       static int num;
-       int maxlen;
-       char *cp;
-       u16 wch;
-
-       if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
-               goto do_goto;
-       if (type == KT_LATIN && ch == '\n')
-               goto do_goto;
-       if (type != 0)
-               goto oops;
-       if (ch == 8) {
-               u16 wch;
-
-               if (num == 0)
-                       return -1;
-               wch = goto_buf[--num];
-               goto_buf[num] = '\0';
-               spkup_write(&wch, 1);
-               return 1;
-       }
-       if (ch < '+' || ch > 'y')
-               goto oops;
-       wch = ch;
-       goto_buf[num++] = ch;
-       goto_buf[num] = '\0';
-       spkup_write(&wch, 1);
-       maxlen = (*goto_buf >= '0') ? 3 : 4;
-       if ((ch == '+' || ch == '-') && num == 1)
-               return 1;
-       if (ch >= '0' && ch <= '9' && num < maxlen)
-               return 1;
-       if (num < maxlen - 1 || num > maxlen)
-               goto oops;
-       if (ch < 'x' || ch > 'y') {
-oops:
-               if (!spk_killed)
-                       synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
-               goto_buf[num = 0] = '\0';
-               spk_special_handler = NULL;
-               return 1;
-       }
-
-       /* Do not replace with kstrtoul: here we need cp to be updated */
-       goto_pos = simple_strtoul(goto_buf, &cp, 10);
-
-       if (*cp == 'x') {
-               if (*goto_buf < '0')
-                       goto_pos += spk_x;
-               else if (goto_pos > 0)
-                       goto_pos--;
-
-               if (goto_pos >= vc->vc_cols)
-                       goto_pos = vc->vc_cols - 1;
-               goto_x = 1;
-       } else {
-               if (*goto_buf < '0')
-                       goto_pos += spk_y;
-               else if (goto_pos > 0)
-                       goto_pos--;
-
-               if (goto_pos >= vc->vc_rows)
-                       goto_pos = vc->vc_rows - 1;
-               goto_x = 0;
-       }
-       goto_buf[num = 0] = '\0';
-do_goto:
-       spk_special_handler = NULL;
-       spk_parked |= 0x01;
-       if (goto_x) {
-               spk_pos -= spk_x * 2;
-               spk_x = goto_pos;
-               spk_pos += goto_pos * 2;
-               say_word(vc);
-       } else {
-               spk_y = goto_pos;
-               spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
-               say_line(vc);
-       }
-       return 1;
-}
-
-static void speakup_goto(struct vc_data *vc)
-{
-       if (spk_special_handler) {
-               synth_printf("%s\n", spk_msg_get(MSG_ERROR));
-               return;
-       }
-       synth_printf("%s\n", spk_msg_get(MSG_GOTO));
-       spk_special_handler = handle_goto;
-}
-
-static void speakup_help(struct vc_data *vc)
-{
-       spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
-}
-
-static void do_nothing(struct vc_data *vc)
-{
-       return;                 /* flush done in do_spkup */
-}
-
-static u_char key_speakup, spk_key_locked;
-
-static void speakup_lock(struct vc_data *vc)
-{
-       if (!spk_key_locked) {
-               spk_key_locked = 16;
-               key_speakup = 16;
-       } else {
-               spk_key_locked = 0;
-               key_speakup = 0;
-       }
-}
-
-typedef void (*spkup_hand) (struct vc_data *);
-static spkup_hand spkup_handler[] = {
-       /* must be ordered same as defines in speakup.h */
-       do_nothing, speakup_goto, speech_kill, speakup_shut_up,
-       speakup_cut, speakup_paste, say_first_char, say_last_char,
-       say_char, say_prev_char, say_next_char,
-       say_word, say_prev_word, say_next_word,
-       say_line, say_prev_line, say_next_line,
-       top_edge, bottom_edge, left_edge, right_edge,
-       spell_word, spell_word, say_screen,
-       say_position, say_attributes,
-       speakup_off, speakup_parked, say_line,  /* this is for indent */
-       say_from_top, say_to_bottom,
-       say_from_left, say_to_right,
-       say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
-       speakup_bits, speakup_bits, speakup_bits,
-       speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
-       speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
-};
-
-static void do_spkup(struct vc_data *vc, u_char value)
-{
-       if (spk_killed && value != SPEECH_KILL)
-               return;
-       spk_keydown = 0;
-       spk_lastkey = 0;
-       spk_shut_up &= 0xfe;
-       this_speakup_key = value;
-       if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
-               spk_do_flush();
-               (*spkup_handler[value]) (vc);
-       } else {
-               if (inc_dec_var(value) < 0)
-                       bleep(9);
-       }
-}
-
-static const char *pad_chars = "0123456789+-*/\015,.?()";
-
-static int
-speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
-           int up_flag)
-{
-       unsigned long flags;
-       int kh;
-       u_char *key_info;
-       u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
-       u_char shift_info, offset;
-       int ret = 0;
-
-       if (!synth)
-               return 0;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       tty = vc->port.tty;
-       if (type >= 0xf0)
-               type -= 0xf0;
-       if (type == KT_PAD &&
-           (vt_get_leds(fg_console, VC_NUMLOCK))) {
-               if (up_flag) {
-                       spk_keydown = 0;
-                       goto out;
-               }
-               value = pad_chars[value];
-               spk_lastkey = value;
-               spk_keydown++;
-               spk_parked &= 0xfe;
-               goto no_map;
-       }
-       if (keycode >= MAX_KEY)
-               goto no_map;
-       key_info = spk_our_keys[keycode];
-       if (!key_info)
-               goto no_map;
-       /* Check valid read all mode keys */
-       if ((cursor_track == read_all_mode) && (!up_flag)) {
-               switch (value) {
-               case KVAL(K_DOWN):
-               case KVAL(K_UP):
-               case KVAL(K_LEFT):
-               case KVAL(K_RIGHT):
-               case KVAL(K_PGUP):
-               case KVAL(K_PGDN):
-                       break;
-               default:
-                       stop_read_all(vc);
-                       break;
-               }
-       }
-       shift_info = (shift_state & 0x0f) + key_speakup;
-       offset = spk_shift_table[shift_info];
-       if (offset) {
-               new_key = key_info[offset];
-               if (new_key) {
-                       ret = 1;
-                       if (new_key == SPK_KEY) {
-                               if (!spk_key_locked)
-                                       key_speakup = (up_flag) ? 0 : 16;
-                               if (up_flag || spk_killed)
-                                       goto out;
-                               spk_shut_up &= 0xfe;
-                               spk_do_flush();
-                               goto out;
-                       }
-                       if (up_flag)
-                               goto out;
-                       if (last_keycode == keycode &&
-                           time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
-                               spk_close_press = 1;
-                               offset = spk_shift_table[shift_info + 32];
-                               /* double press? */
-                               if (offset && key_info[offset])
-                                       new_key = key_info[offset];
-                       }
-                       last_keycode = keycode;
-                       last_spk_jiffy = jiffies;
-                       type = KT_SPKUP;
-                       value = new_key;
-               }
-       }
-no_map:
-       if (type == KT_SPKUP && !spk_special_handler) {
-               do_spkup(vc, new_key);
-               spk_close_press = 0;
-               ret = 1;
-               goto out;
-       }
-       if (up_flag || spk_killed || type == KT_SHIFT)
-               goto out;
-       spk_shut_up &= 0xfe;
-       kh = (value == KVAL(K_DOWN)) ||
-           (value == KVAL(K_UP)) ||
-           (value == KVAL(K_LEFT)) ||
-           (value == KVAL(K_RIGHT));
-       if ((cursor_track != read_all_mode) || !kh)
-               if (!spk_no_intr)
-                       spk_do_flush();
-       if (spk_special_handler) {
-               if (type == KT_SPEC && value == 1) {
-                       value = '\n';
-                       type = KT_LATIN;
-               } else if (type == KT_LETTER) {
-                       type = KT_LATIN;
-               } else if (value == 0x7f) {
-                       value = 8;      /* make del = backspace */
-               }
-               ret = (*spk_special_handler) (vc, type, value, keycode);
-               spk_close_press = 0;
-               if (ret < 0)
-                       bleep(9);
-               goto out;
-       }
-       last_keycode = 0;
-out:
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return ret;
-}
-
-static int keyboard_notifier_call(struct notifier_block *nb,
-                                 unsigned long code, void *_param)
-{
-       struct keyboard_notifier_param *param = _param;
-       struct vc_data *vc = param->vc;
-       int up = !param->down;
-       int ret = NOTIFY_OK;
-       static int keycode;     /* to hold the current keycode */
-
-       in_keyboard_notifier = 1;
-
-       if (vc->vc_mode == KD_GRAPHICS)
-               goto out;
-
-       /*
-        * First, determine whether we are handling a fake keypress on
-        * the current processor.  If we are, then return NOTIFY_OK,
-        * to pass the keystroke up the chain.  This prevents us from
-        * trying to take the Speakup lock while it is held by the
-        * processor on which the simulated keystroke was generated.
-        * Also, the simulated keystrokes should be ignored by Speakup.
-        */
-
-       if (speakup_fake_key_pressed())
-               goto out;
-
-       switch (code) {
-       case KBD_KEYCODE:
-               /* speakup requires keycode and keysym currently */
-               keycode = param->value;
-               break;
-       case KBD_UNBOUND_KEYCODE:
-               /* not used yet */
-               break;
-       case KBD_UNICODE:
-               /* not used yet */
-               break;
-       case KBD_KEYSYM:
-               if (speakup_key(vc, param->shift, keycode, param->value, up))
-                       ret = NOTIFY_STOP;
-               else if (KTYP(param->value) == KT_CUR)
-                       ret = pre_handle_cursor(vc, KVAL(param->value), up);
-               break;
-       case KBD_POST_KEYSYM:{
-                       unsigned char type = KTYP(param->value) - 0xf0;
-                       unsigned char val = KVAL(param->value);
-
-                       switch (type) {
-                       case KT_SHIFT:
-                               do_handle_shift(vc, val, up);
-                               break;
-                       case KT_LATIN:
-                       case KT_LETTER:
-                               do_handle_latin(vc, val, up);
-                               break;
-                       case KT_CUR:
-                               do_handle_cursor(vc, val, up);
-                               break;
-                       case KT_SPEC:
-                               do_handle_spec(vc, val, up);
-                               break;
-                       }
-                       break;
-               }
-       }
-out:
-       in_keyboard_notifier = 0;
-       return ret;
-}
-
-static int vt_notifier_call(struct notifier_block *nb,
-                           unsigned long code, void *_param)
-{
-       struct vt_notifier_param *param = _param;
-       struct vc_data *vc = param->vc;
-
-       switch (code) {
-       case VT_ALLOCATE:
-               if (vc->vc_mode == KD_TEXT)
-                       speakup_allocate(vc, GFP_ATOMIC);
-               break;
-       case VT_DEALLOCATE:
-               speakup_deallocate(vc);
-               break;
-       case VT_WRITE:
-               if (param->c == '\b') {
-                       speakup_bs(vc);
-               } else {
-                       u16 d = param->c;
-
-                       speakup_con_write(vc, &d, 1);
-               }
-               break;
-       case VT_UPDATE:
-               speakup_con_update(vc);
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-/* called by: module_exit() */
-static void __exit speakup_exit(void)
-{
-       int i;
-
-       unregister_keyboard_notifier(&keyboard_notifier_block);
-       unregister_vt_notifier(&vt_notifier_block);
-       speakup_unregister_devsynth();
-       speakup_cancel_selection();
-       speakup_cancel_paste();
-       del_timer_sync(&cursor_timer);
-       kthread_stop(speakup_task);
-       speakup_task = NULL;
-       mutex_lock(&spk_mutex);
-       synth_release();
-       mutex_unlock(&spk_mutex);
-       spk_ttyio_unregister_ldisc();
-
-       speakup_kobj_exit();
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               kfree(speakup_console[i]);
-
-       speakup_remove_virtual_keyboard();
-
-       for (i = 0; i < MAXVARS; i++)
-               speakup_unregister_var(i);
-
-       for (i = 0; i < 256; i++) {
-               if (spk_characters[i] != spk_default_chars[i])
-                       kfree(spk_characters[i]);
-       }
-
-       spk_free_user_msgs();
-}
-
-/* call by: module_init() */
-static int __init speakup_init(void)
-{
-       int i;
-       long err = 0;
-       struct vc_data *vc = vc_cons[fg_console].d;
-       struct var_t *var;
-
-       /* These first few initializations cannot fail. */
-       spk_initialize_msgs();  /* Initialize arrays for i18n. */
-       spk_reset_default_chars();
-       spk_reset_default_chartab();
-       spk_strlwr(synth_name);
-       spk_vars[0].u.n.high = vc->vc_cols;
-       for (var = spk_vars; var->var_id != MAXVARS; var++)
-               speakup_register_var(var);
-       for (var = synth_time_vars;
-            (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
-               speakup_register_var(var);
-       for (i = 1; spk_punc_info[i].mask != 0; i++)
-               spk_set_mask_bits(NULL, i, 2);
-
-       spk_set_key_info(spk_key_defaults, spk_key_buf);
-
-       /* From here on out, initializations can fail. */
-       err = speakup_add_virtual_keyboard();
-       if (err)
-               goto error_virtkeyboard;
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               if (vc_cons[i].d) {
-                       err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
-                       if (err)
-                               goto error_kobjects;
-               }
-
-       if (spk_quiet_boot)
-               spk_shut_up |= 0x01;
-
-       err = speakup_kobj_init();
-       if (err)
-               goto error_kobjects;
-
-       spk_ttyio_register_ldisc();
-       synth_init(synth_name);
-       speakup_register_devsynth();
-       /*
-        * register_devsynth might fail, but this error is not fatal.
-        * /dev/synth is an extra feature; the rest of Speakup
-        * will work fine without it.
-        */
-
-       err = register_keyboard_notifier(&keyboard_notifier_block);
-       if (err)
-               goto error_kbdnotifier;
-       err = register_vt_notifier(&vt_notifier_block);
-       if (err)
-               goto error_vtnotifier;
-
-       speakup_task = kthread_create(speakup_thread, NULL, "speakup");
-
-       if (IS_ERR(speakup_task)) {
-               err = PTR_ERR(speakup_task);
-               goto error_task;
-       }
-
-       set_user_nice(speakup_task, 10);
-       wake_up_process(speakup_task);
-
-       pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
-       pr_info("synth name on entry is: %s\n", synth_name);
-       goto out;
-
-error_task:
-       unregister_vt_notifier(&vt_notifier_block);
-
-error_vtnotifier:
-       unregister_keyboard_notifier(&keyboard_notifier_block);
-       del_timer(&cursor_timer);
-
-error_kbdnotifier:
-       speakup_unregister_devsynth();
-       mutex_lock(&spk_mutex);
-       synth_release();
-       mutex_unlock(&spk_mutex);
-       speakup_kobj_exit();
-
-error_kobjects:
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               kfree(speakup_console[i]);
-
-       speakup_remove_virtual_keyboard();
-
-error_virtkeyboard:
-       for (i = 0; i < MAXVARS; i++)
-               speakup_unregister_var(i);
-
-       for (i = 0; i < 256; i++) {
-               if (spk_characters[i] != spk_default_chars[i])
-                       kfree(spk_characters[i]);
-       }
-
-       spk_free_user_msgs();
-
-out:
-       return err;
-}
-
-module_init(speakup_init);
-module_exit(speakup_exit);
diff --git a/drivers/staging/speakup/selection.c b/drivers/staging/speakup/selection.c
deleted file mode 100644 (file)
index 032f326..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/slab.h> /* for kmalloc */
-#include <linux/consolemap.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/device.h> /* for dev_warn */
-#include <linux/selection.h>
-#include <linux/workqueue.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/atomic.h>
-#include <linux/console.h>
-
-#include "speakup.h"
-
-unsigned short spk_xs, spk_ys, spk_xe, spk_ye; /* our region points */
-struct vc_data *spk_sel_cons;
-
-struct speakup_selection_work {
-       struct work_struct work;
-       struct tiocl_selection sel;
-       struct tty_struct *tty;
-};
-
-void speakup_clear_selection(void)
-{
-       console_lock();
-       clear_selection();
-       console_unlock();
-}
-
-static void __speakup_set_selection(struct work_struct *work)
-{
-       struct speakup_selection_work *ssw =
-               container_of(work, struct speakup_selection_work, work);
-
-       struct tty_struct *tty;
-       struct tiocl_selection sel;
-
-       sel = ssw->sel;
-
-       /* this ensures we copy sel before releasing the lock below */
-       rmb();
-
-       /* release the lock by setting tty of the struct to NULL */
-       tty = xchg(&ssw->tty, NULL);
-
-       if (spk_sel_cons != vc_cons[fg_console].d) {
-               spk_sel_cons = vc_cons[fg_console].d;
-               pr_warn("Selection: mark console not the same as cut\n");
-               goto unref;
-       }
-
-       set_selection_kernel(&sel, tty);
-
-unref:
-       tty_kref_put(tty);
-}
-
-static struct speakup_selection_work speakup_sel_work = {
-       .work = __WORK_INITIALIZER(speakup_sel_work.work,
-                                  __speakup_set_selection)
-};
-
-int speakup_set_selection(struct tty_struct *tty)
-{
-       /* we get kref here first in order to avoid a subtle race when
-        * cancelling selection work. getting kref first establishes the
-        * invariant that if speakup_sel_work.tty is not NULL when
-        * speakup_cancel_selection() is called, it must be the case that a put
-        * kref is pending.
-        */
-       tty_kref_get(tty);
-       if (cmpxchg(&speakup_sel_work.tty, NULL, tty)) {
-               tty_kref_put(tty);
-               return -EBUSY;
-       }
-       /* now we have the 'lock' by setting tty member of
-        * speakup_selection_work. wmb() ensures that writes to
-        * speakup_sel_work don't happen before cmpxchg() above.
-        */
-       wmb();
-
-       speakup_sel_work.sel.xs = spk_xs + 1;
-       speakup_sel_work.sel.ys = spk_ys + 1;
-       speakup_sel_work.sel.xe = spk_xe + 1;
-       speakup_sel_work.sel.ye = spk_ye + 1;
-       speakup_sel_work.sel.sel_mode = TIOCL_SELCHAR;
-
-       schedule_work_on(WORK_CPU_UNBOUND, &speakup_sel_work.work);
-
-       return 0;
-}
-
-void speakup_cancel_selection(void)
-{
-       struct tty_struct *tty;
-
-       cancel_work_sync(&speakup_sel_work.work);
-       /* setting to null so that if work fails to run and we cancel it,
-        * we can run it again without getting EBUSY forever from there on.
-        * we need to use xchg here to avoid race with speakup_set_selection()
-        */
-       tty = xchg(&speakup_sel_work.tty, NULL);
-       if (tty)
-               tty_kref_put(tty);
-}
-
-static void __speakup_paste_selection(struct work_struct *work)
-{
-       struct speakup_selection_work *ssw =
-               container_of(work, struct speakup_selection_work, work);
-       struct tty_struct *tty = xchg(&ssw->tty, NULL);
-
-       paste_selection(tty);
-       tty_kref_put(tty);
-}
-
-static struct speakup_selection_work speakup_paste_work = {
-       .work = __WORK_INITIALIZER(speakup_paste_work.work,
-                                  __speakup_paste_selection)
-};
-
-int speakup_paste_selection(struct tty_struct *tty)
-{
-       tty_kref_get(tty);
-       if (cmpxchg(&speakup_paste_work.tty, NULL, tty)) {
-               tty_kref_put(tty);
-               return -EBUSY;
-       }
-
-       schedule_work_on(WORK_CPU_UNBOUND, &speakup_paste_work.work);
-       return 0;
-}
-
-void speakup_cancel_paste(void)
-{
-       struct tty_struct *tty;
-
-       cancel_work_sync(&speakup_paste_work.work);
-       tty = xchg(&speakup_paste_work.tty, NULL);
-       if (tty)
-               tty_kref_put(tty);
-}
diff --git a/drivers/staging/speakup/serialio.c b/drivers/staging/speakup/serialio.c
deleted file mode 100644 (file)
index 177a298..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-
-#include "spk_types.h"
-#include "speakup.h"
-#include "spk_priv.h"
-#include "serialio.h"
-
-#include <linux/serial_core.h>
-/* WARNING:  Do not change this to <linux/serial.h> without testing that
- * SERIAL_PORT_DFNS does get defined to the appropriate value.
- */
-#include <asm/serial.h>
-
-#ifndef SERIAL_PORT_DFNS
-#define SERIAL_PORT_DFNS
-#endif
-
-static void start_serial_interrupt(int irq);
-
-static const struct old_serial_port rs_table[] = {
-       SERIAL_PORT_DFNS
-};
-
-static const struct old_serial_port *serstate;
-static int timeouts;
-
-static int spk_serial_out(struct spk_synth *in_synth, const char ch);
-static void spk_serial_send_xchar(char ch);
-static void spk_serial_tiocmset(unsigned int set, unsigned int clear);
-static unsigned char spk_serial_in(void);
-static unsigned char spk_serial_in_nowait(void);
-static void spk_serial_flush_buffer(void);
-
-struct spk_io_ops spk_serial_io_ops = {
-       .synth_out = spk_serial_out,
-       .send_xchar = spk_serial_send_xchar,
-       .tiocmset = spk_serial_tiocmset,
-       .synth_in = spk_serial_in,
-       .synth_in_nowait = spk_serial_in_nowait,
-       .flush_buffer = spk_serial_flush_buffer,
-};
-EXPORT_SYMBOL_GPL(spk_serial_io_ops);
-
-const struct old_serial_port *spk_serial_init(int index)
-{
-       int baud = 9600, quot = 0;
-       unsigned int cval = 0;
-       int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
-       const struct old_serial_port *ser;
-       int err;
-
-       if (index >= ARRAY_SIZE(rs_table)) {
-               pr_info("no port info for ttyS%d\n", index);
-               return NULL;
-       }
-       ser = rs_table + index;
-
-       /*      Divisor, bytesize and parity */
-       quot = ser->baud_base / baud;
-       cval = cflag & (CSIZE | CSTOPB);
-#if defined(__powerpc__) || defined(__alpha__)
-       cval >>= 8;
-#else /* !__powerpc__ && !__alpha__ */
-       cval >>= 4;
-#endif /* !__powerpc__ && !__alpha__ */
-       if (cflag & PARENB)
-               cval |= UART_LCR_PARITY;
-       if (!(cflag & PARODD))
-               cval |= UART_LCR_EPAR;
-       if (synth_request_region(ser->port, 8)) {
-               /* try to take it back. */
-               pr_info("Ports not available, trying to steal them\n");
-               __release_region(&ioport_resource, ser->port, 8);
-               err = synth_request_region(ser->port, 8);
-               if (err) {
-                       pr_warn("Unable to allocate port at %x, errno %i",
-                               ser->port, err);
-                       return NULL;
-               }
-       }
-
-       /*      Disable UART interrupts, set DTR and RTS high
-        *      and set speed.
-        */
-       outb(cval | UART_LCR_DLAB, ser->port + UART_LCR);       /* set DLAB */
-       outb(quot & 0xff, ser->port + UART_DLL);        /* LS of divisor */
-       outb(quot >> 8, ser->port + UART_DLM);          /* MS of divisor */
-       outb(cval, ser->port + UART_LCR);               /* reset DLAB */
-
-       /* Turn off Interrupts */
-       outb(0, ser->port + UART_IER);
-       outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
-
-       /* If we read 0xff from the LSR, there is no UART here. */
-       if (inb(ser->port + UART_LSR) == 0xff) {
-               synth_release_region(ser->port, 8);
-               serstate = NULL;
-               return NULL;
-       }
-
-       mdelay(1);
-       speakup_info.port_tts = ser->port;
-       serstate = ser;
-
-       start_serial_interrupt(ser->irq);
-
-       return ser;
-}
-
-static irqreturn_t synth_readbuf_handler(int irq, void *dev_id)
-{
-       unsigned long flags;
-       int c;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       while (inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR) {
-               c = inb_p(speakup_info.port_tts + UART_RX);
-               synth->read_buff_add((u_char)c);
-       }
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return IRQ_HANDLED;
-}
-
-static void start_serial_interrupt(int irq)
-{
-       int rv;
-
-       if (!synth->read_buff_add)
-               return;
-
-       rv = request_irq(irq, synth_readbuf_handler, IRQF_SHARED,
-                        "serial", (void *)synth_readbuf_handler);
-
-       if (rv)
-               pr_err("Unable to request Speakup serial I R Q\n");
-       /* Set MCR */
-       outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2,
-            speakup_info.port_tts + UART_MCR);
-       /* Turn on Interrupts */
-       outb(UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI,
-            speakup_info.port_tts + UART_IER);
-       inb(speakup_info.port_tts + UART_LSR);
-       inb(speakup_info.port_tts + UART_RX);
-       inb(speakup_info.port_tts + UART_IIR);
-       inb(speakup_info.port_tts + UART_MSR);
-       outb(1, speakup_info.port_tts + UART_FCR);      /* Turn FIFO On */
-}
-
-static void spk_serial_send_xchar(char ch)
-{
-       int timeout = SPK_XMITR_TIMEOUT;
-
-       while (spk_serial_tx_busy()) {
-               if (!--timeout)
-                       break;
-               udelay(1);
-       }
-       outb(ch, speakup_info.port_tts);
-}
-
-static void spk_serial_tiocmset(unsigned int set, unsigned int clear)
-{
-       int old = inb(speakup_info.port_tts + UART_MCR);
-
-       outb((old & ~clear) | set, speakup_info.port_tts + UART_MCR);
-}
-
-int spk_serial_synth_probe(struct spk_synth *synth)
-{
-       const struct old_serial_port *ser;
-       int failed = 0;
-
-       if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) {
-               ser = spk_serial_init(synth->ser);
-               if (!ser) {
-                       failed = -1;
-               } else {
-                       outb_p(0, ser->port);
-                       mdelay(1);
-                       outb_p('\r', ser->port);
-               }
-       } else {
-               failed = -1;
-               pr_warn("ttyS%i is an invalid port\n", synth->ser);
-       }
-       if (failed) {
-               pr_info("%s: not found\n", synth->long_name);
-               return -ENODEV;
-       }
-       pr_info("%s: ttyS%i, Driver Version %s\n",
-               synth->long_name, synth->ser, synth->version);
-       synth->alive = 1;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(spk_serial_synth_probe);
-
-void spk_stop_serial_interrupt(void)
-{
-       if (speakup_info.port_tts == 0)
-               return;
-
-       if (!synth->read_buff_add)
-               return;
-
-       /* Turn off interrupts */
-       outb(0, speakup_info.port_tts + UART_IER);
-       /* Free IRQ */
-       free_irq(serstate->irq, (void *)synth_readbuf_handler);
-}
-EXPORT_SYMBOL_GPL(spk_stop_serial_interrupt);
-
-int spk_wait_for_xmitr(struct spk_synth *in_synth)
-{
-       int tmout = SPK_XMITR_TIMEOUT;
-
-       if ((in_synth->alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) {
-               pr_warn("%s: too many timeouts, deactivating speakup\n",
-                       in_synth->long_name);
-               in_synth->alive = 0;
-               /* No synth any more, so nobody will restart TTYs, and we thus
-                * need to do it ourselves.  Now that there is no synth we can
-                * let application flood anyway
-                */
-               speakup_start_ttys();
-               timeouts = 0;
-               return 0;
-       }
-       while (spk_serial_tx_busy()) {
-               if (--tmout == 0) {
-                       pr_warn("%s: timed out (tx busy)\n",
-                               in_synth->long_name);
-                       timeouts++;
-                       return 0;
-               }
-               udelay(1);
-       }
-       tmout = SPK_CTS_TIMEOUT;
-       while (!((inb_p(speakup_info.port_tts + UART_MSR)) & UART_MSR_CTS)) {
-               /* CTS */
-               if (--tmout == 0) {
-                       timeouts++;
-                       return 0;
-               }
-               udelay(1);
-       }
-       timeouts = 0;
-       return 1;
-}
-
-static unsigned char spk_serial_in(void)
-{
-       int tmout = SPK_SERIAL_TIMEOUT;
-
-       while (!(inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR)) {
-               if (--tmout == 0) {
-                       pr_warn("time out while waiting for input.\n");
-                       return 0xff;
-               }
-               udelay(1);
-       }
-       return inb_p(speakup_info.port_tts + UART_RX);
-}
-
-static unsigned char spk_serial_in_nowait(void)
-{
-       unsigned char lsr;
-
-       lsr = inb_p(speakup_info.port_tts + UART_LSR);
-       if (!(lsr & UART_LSR_DR))
-               return 0;
-       return inb_p(speakup_info.port_tts + UART_RX);
-}
-
-static void spk_serial_flush_buffer(void)
-{
-       /* TODO: flush the UART 16550 buffer */
-}
-
-static int spk_serial_out(struct spk_synth *in_synth, const char ch)
-{
-       if (in_synth->alive && spk_wait_for_xmitr(in_synth)) {
-               outb_p(ch, speakup_info.port_tts);
-               return 1;
-       }
-       return 0;
-}
-
-const char *spk_serial_synth_immediate(struct spk_synth *synth,
-                                      const char *buff)
-{
-       u_char ch;
-
-       while ((ch = *buff)) {
-               if (ch == '\n')
-                       ch = synth->procspeech;
-               if (spk_wait_for_xmitr(synth))
-                       outb(ch, speakup_info.port_tts);
-               else
-                       return buff;
-               buff++;
-       }
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(spk_serial_synth_immediate);
-
-void spk_serial_release(void)
-{
-       spk_stop_serial_interrupt();
-       if (speakup_info.port_tts == 0)
-               return;
-       synth_release_region(speakup_info.port_tts, 8);
-       speakup_info.port_tts = 0;
-}
-EXPORT_SYMBOL_GPL(spk_serial_release);
diff --git a/drivers/staging/speakup/serialio.h b/drivers/staging/speakup/serialio.h
deleted file mode 100644 (file)
index 6f8f86f..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _SPEAKUP_SERIAL_H
-#define _SPEAKUP_SERIAL_H
-
-#include <linux/serial.h>      /* for rs_table, serial constants */
-#include <linux/serial_reg.h>  /* for more serial constants */
-#include <linux/serial_core.h>
-
-#include "spk_priv.h"
-
-/*
- * this is cut&paste from 8250.h. Get rid of the structure, the definitions
- * and this whole broken driver.
- */
-struct old_serial_port {
-       unsigned int uart; /* unused */
-       unsigned int baud_base;
-       unsigned int port;
-       unsigned int irq;
-       upf_t flags; /* unused */
-};
-
-/* countdown values for serial timeouts in us */
-#define SPK_SERIAL_TIMEOUT SPK_SYNTH_TIMEOUT
-/* countdown values transmitter/dsr timeouts in us */
-#define SPK_XMITR_TIMEOUT 100000
-/* countdown values cts timeouts in us */
-#define SPK_CTS_TIMEOUT 100000
-/* check ttyS0 ... ttyS3 */
-#define SPK_LO_TTY 0
-#define SPK_HI_TTY 3
-/* # of timeouts permitted before disable */
-#define NUM_DISABLE_TIMEOUTS 3
-/* buffer timeout in ms */
-#define SPK_TIMEOUT 100
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-#define spk_serial_tx_busy() \
-       ((inb(speakup_info.port_tts + UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
-
-#endif
diff --git a/drivers/staging/speakup/speakup.h b/drivers/staging/speakup/speakup.h
deleted file mode 100644 (file)
index 74fe49c..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _SPEAKUP_H
-#define _SPEAKUP_H
-
-#include "spk_types.h"
-#include "i18n.h"
-
-#define SPEAKUP_VERSION "3.1.6"
-#define KEY_MAP_VER 119
-#define SHIFT_TBL_SIZE 64
-#define MAX_DESC_LEN 72
-
-#define TOGGLE_0 .u.n = {NULL, 0, 0, 1, 0, 0, NULL }
-#define TOGGLE_1 .u.n = {NULL, 1, 0, 1, 0, 0, NULL }
-#define MAXVARLEN 15
-
-#define SYNTH_OK 0x0001
-#define B_ALPHA 0x0002
-#define ALPHA 0x0003
-#define B_CAP 0x0004
-#define A_CAP 0x0007
-#define B_NUM 0x0008
-#define NUM 0x0009
-#define ALPHANUM (B_ALPHA | B_NUM)
-#define SOME 0x0010
-#define MOST 0x0020
-#define PUNC 0x0040
-#define A_PUNC 0x0041
-#define B_WDLM 0x0080
-#define WDLM 0x0081
-#define B_EXNUM 0x0100
-#define CH_RPT 0x0200
-#define B_CTL 0x0400
-#define A_CTL (B_CTL + SYNTH_OK)
-#define B_SYM 0x0800
-#define B_CAPSYM (B_CAP | B_SYM)
-
-/* FIXME: u16 */
-#define IS_WDLM(x) (spk_chartab[((u_char)x)] & B_WDLM)
-#define IS_CHAR(x, type) (spk_chartab[((u_char)x)] & type)
-#define IS_TYPE(x, type) ((spk_chartab[((u_char)x)] & type) == type)
-
-int speakup_thread(void *data);
-void spk_reset_default_chars(void);
-void spk_reset_default_chartab(void);
-void synth_start(void);
-void synth_insert_next_index(int sent_num);
-void spk_reset_index_count(int sc);
-void spk_get_index_count(int *linecount, int *sentcount);
-int spk_set_key_info(const u_char *key_info, u_char *k_buffer);
-char *spk_strlwr(char *s);
-char *spk_s2uchar(char *start, char *dest);
-int speakup_kobj_init(void);
-void speakup_kobj_exit(void);
-int spk_chartab_get_value(char *keyword);
-void speakup_register_var(struct var_t *var);
-void speakup_unregister_var(enum var_id_t var_id);
-struct st_var_header *spk_get_var_header(enum var_id_t var_id);
-struct st_var_header *spk_var_header_by_name(const char *name);
-struct punc_var_t *spk_get_punc_var(enum var_id_t var_id);
-int spk_set_num_var(int val, struct st_var_header *var, int how);
-int spk_set_string_var(const char *page, struct st_var_header *var, int len);
-int spk_set_mask_bits(const char *input, const int which, const int how);
-extern special_func spk_special_handler;
-int spk_handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key);
-int synth_init(char *name);
-void synth_release(void);
-
-void spk_do_flush(void);
-void speakup_start_ttys(void);
-void synth_buffer_add(u16 ch);
-void synth_buffer_clear(void);
-void speakup_clear_selection(void);
-int speakup_set_selection(struct tty_struct *tty);
-void speakup_cancel_selection(void);
-int speakup_paste_selection(struct tty_struct *tty);
-void speakup_cancel_paste(void);
-void speakup_register_devsynth(void);
-void speakup_unregister_devsynth(void);
-void synth_write(const char *buf, size_t count);
-int synth_supports_indexing(void);
-
-extern struct vc_data *spk_sel_cons;
-extern unsigned short spk_xs, spk_ys, spk_xe, spk_ye; /* our region points */
-
-extern wait_queue_head_t speakup_event;
-extern struct kobject *speakup_kobj;
-extern struct task_struct *speakup_task;
-extern const u_char spk_key_defaults[];
-
-/* Protect speakup synthesizer list */
-extern struct mutex spk_mutex;
-extern struct st_spk_t *speakup_console[];
-extern struct spk_synth *synth;
-extern char spk_pitch_buff[];
-extern u_char *spk_our_keys[];
-extern short spk_punc_masks[];
-extern char spk_str_caps_start[], spk_str_caps_stop[], spk_str_pause[];
-extern bool spk_paused;
-extern const struct st_bits_data spk_punc_info[];
-extern u_char spk_key_buf[600];
-extern char *spk_characters[];
-extern char *spk_default_chars[];
-extern u_short spk_chartab[];
-extern int spk_no_intr, spk_say_ctrl, spk_say_word_ctl, spk_punc_level;
-extern int spk_reading_punc, spk_attrib_bleep, spk_bleeps;
-extern int spk_bleep_time, spk_bell_pos;
-extern int spk_spell_delay, spk_key_echo;
-extern short spk_punc_mask;
-extern short spk_pitch_shift, synth_flags;
-extern bool spk_quiet_boot;
-extern char *synth_name;
-extern struct bleep spk_unprocessed_sound;
-
-/* Prototypes from fakekey.c. */
-int speakup_add_virtual_keyboard(void);
-void speakup_remove_virtual_keyboard(void);
-void speakup_fake_down_arrow(void);
-bool speakup_fake_key_pressed(void);
-
-#endif
diff --git a/drivers/staging/speakup/speakup_acnt.h b/drivers/staging/speakup/speakup_acnt.h
deleted file mode 100644 (file)
index cffa938..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* speakup_acntpc.h - header file for speakups Accent-PC driver. */
-
-#define SYNTH_IO_EXTENT        0x02
-
-#define SYNTH_CLEAR    0x18            /* stops speech */
-
-       /* Port Status Flags */
-#define SYNTH_READABLE 0x01    /* mask for bit which is nonzero if a
-                                * byte can be read from the data port
-                                */
-#define SYNTH_WRITABLE 0x02    /* mask for RDY bit, which when set to
-                                * 1, indicates the data port is ready
-                                *  to accept a byte of data.
-                                */
-#define SYNTH_QUIET    'S' /* synth is not speaking */
-#define SYNTH_FULL     'F' /* synth is full. */
-#define SYNTH_ALMOST_EMPTY 'M' /* synth has less than 2 seconds of text left */
-#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
deleted file mode 100644 (file)
index c94328a..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * this code is specificly written as a driver for the speakup screenreview
- * package and is not a general device driver.
- * This driver is for the Aicom Acent PC internal synthesizer.
- */
-
-#include <linux/jiffies.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/kthread.h>
-
-#include "spk_priv.h"
-#include "serialio.h"
-#include "speakup.h"
-#include "speakup_acnt.h" /* local header file for Accent values */
-
-#define DRV_VERSION "2.10"
-#define PROCSPEECH '\r'
-
-static int synth_probe(struct spk_synth *synth);
-static void accent_release(void);
-static const char *synth_immediate(struct spk_synth *synth, const char *buf);
-static void do_catch_up(struct spk_synth *synth);
-static void synth_flush(struct spk_synth *synth);
-
-static int synth_port_control;
-static int port_forced;
-static unsigned int synth_portlist[] = { 0x2a8, 0 };
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\033P8" } },
-       { CAPS_STOP, .u.s = {"\033P5" } },
-       { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" } },
-       { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL } },
-       { VOL, .u.n = {"\033A%d", 5, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/acntpc.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute tone_attribute =
-       __ATTR(tone, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &rate_attribute.attr,
-       &tone_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_acntpc = {
-       .name = "acntpc",
-       .version = DRV_VERSION,
-       .long_name = "Accent PC",
-       .init = "\033=X \033Oi\033T2\033=M\033N1\n",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 1000,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_serial_io_ops,
-       .probe = synth_probe,
-       .release = accent_release,
-       .synth_immediate = synth_immediate,
-       .catch_up = do_catch_up,
-       .flush = synth_flush,
-       .is_alive = spk_synth_is_alive_nop,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = NULL,
-       .indexing = {
-               .command = NULL,
-               .lowindex = 0,
-               .highindex = 0,
-               .currindex = 0,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "acntpc",
-       },
-};
-
-static inline bool synth_writable(void)
-{
-       return inb_p(synth_port_control) & SYNTH_WRITABLE;
-}
-
-static inline bool synth_full(void)
-{
-       return inb_p(speakup_info.port_tts + UART_RX) == 'F';
-}
-
-static const char *synth_immediate(struct spk_synth *synth, const char *buf)
-{
-       u_char ch;
-
-       while ((ch = *buf)) {
-               int timeout = SPK_XMITR_TIMEOUT;
-
-               if (ch == '\n')
-                       ch = PROCSPEECH;
-               if (synth_full())
-                       return buf;
-               while (synth_writable()) {
-                       if (!--timeout)
-                               return buf;
-                       udelay(1);
-               }
-               outb_p(ch, speakup_info.port_tts);
-               buf++;
-       }
-       return NULL;
-}
-
-static void do_catch_up(struct spk_synth *synth)
-{
-       u_char ch;
-       unsigned long flags;
-       unsigned long jiff_max;
-       int timeout;
-       int delay_time_val;
-       int jiffy_delta_val;
-       int full_time_val;
-       struct var_t *delay_time;
-       struct var_t *full_time;
-       struct var_t *jiffy_delta;
-
-       jiffy_delta = spk_get_var(JIFFY);
-       delay_time = spk_get_var(DELAY);
-       full_time = spk_get_var(FULL);
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       jiffy_delta_val = jiffy_delta->u.n.value;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-
-       jiff_max = jiffies + jiffy_delta_val;
-       while (!kthread_should_stop()) {
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               if (speakup_info.flushing) {
-                       speakup_info.flushing = 0;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       synth->flush(synth);
-                       continue;
-               }
-               synth_buffer_skip_nonlatin1();
-               if (synth_buffer_empty()) {
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       break;
-               }
-               set_current_state(TASK_INTERRUPTIBLE);
-               full_time_val = full_time->u.n.value;
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (synth_full()) {
-                       schedule_timeout(msecs_to_jiffies(full_time_val));
-                       continue;
-               }
-               set_current_state(TASK_RUNNING);
-               timeout = SPK_XMITR_TIMEOUT;
-               while (synth_writable()) {
-                       if (!--timeout)
-                               break;
-                       udelay(1);
-               }
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               ch = synth_buffer_getc();
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (ch == '\n')
-                       ch = PROCSPEECH;
-               outb_p(ch, speakup_info.port_tts);
-               if (time_after_eq(jiffies, jiff_max) && ch == SPACE) {
-                       timeout = SPK_XMITR_TIMEOUT;
-                       while (synth_writable()) {
-                               if (!--timeout)
-                                       break;
-                               udelay(1);
-                       }
-                       outb_p(PROCSPEECH, speakup_info.port_tts);
-                       spin_lock_irqsave(&speakup_info.spinlock, flags);
-                       jiffy_delta_val = jiffy_delta->u.n.value;
-                       delay_time_val = delay_time->u.n.value;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       schedule_timeout(msecs_to_jiffies(delay_time_val));
-                       jiff_max = jiffies + jiffy_delta_val;
-               }
-       }
-       timeout = SPK_XMITR_TIMEOUT;
-       while (synth_writable()) {
-               if (!--timeout)
-                       break;
-               udelay(1);
-       }
-       outb_p(PROCSPEECH, speakup_info.port_tts);
-}
-
-static void synth_flush(struct spk_synth *synth)
-{
-       outb_p(SYNTH_CLEAR, speakup_info.port_tts);
-}
-
-static int synth_probe(struct spk_synth *synth)
-{
-       unsigned int port_val = 0;
-       int i = 0;
-
-       pr_info("Probing for %s.\n", synth->long_name);
-       if (port_forced) {
-               speakup_info.port_tts = port_forced;
-               pr_info("probe forced to %x by kernel command line\n",
-                       speakup_info.port_tts);
-               if (synth_request_region(speakup_info.port_tts - 1,
-                                        SYNTH_IO_EXTENT)) {
-                       pr_warn("sorry, port already reserved\n");
-                       return -EBUSY;
-               }
-               port_val = inw(speakup_info.port_tts - 1);
-               synth_port_control = speakup_info.port_tts - 1;
-       } else {
-               for (i = 0; synth_portlist[i]; i++) {
-                       if (synth_request_region(synth_portlist[i],
-                                                SYNTH_IO_EXTENT)) {
-                               pr_warn
-                                   ("request_region: failed with 0x%x, %d\n",
-                                    synth_portlist[i], SYNTH_IO_EXTENT);
-                               continue;
-                       }
-                       port_val = inw(synth_portlist[i]) & 0xfffc;
-                       if (port_val == 0x53fc) {
-                               /* 'S' and out&input bits */
-                               synth_port_control = synth_portlist[i];
-                               speakup_info.port_tts = synth_port_control + 1;
-                               break;
-                       }
-               }
-       }
-       port_val &= 0xfffc;
-       if (port_val != 0x53fc) {
-               /* 'S' and out&input bits */
-               pr_info("%s: not found\n", synth->long_name);
-               synth_release_region(synth_port_control, SYNTH_IO_EXTENT);
-               synth_port_control = 0;
-               return -ENODEV;
-       }
-       pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name,
-               synth_port_control, synth_port_control + SYNTH_IO_EXTENT - 1,
-               synth->version);
-       synth->alive = 1;
-       return 0;
-}
-
-static void accent_release(void)
-{
-       spk_stop_serial_interrupt();
-       if (speakup_info.port_tts)
-               synth_release_region(speakup_info.port_tts - 1,
-                                    SYNTH_IO_EXTENT);
-       speakup_info.port_tts = 0;
-}
-
-module_param_hw_named(port, port_forced, int, ioport, 0444);
-module_param_named(start, synth_acntpc.startup, short, 0444);
-
-MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_acntpc);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for Accent PC synthesizer");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_acntsa.c b/drivers/staging/speakup/speakup_acntsa.c
deleted file mode 100644 (file)
index 3a863dc..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * this code is specificly written as a driver for the speakup screenreview
- * package and is not a general device driver.
- */
-
-#include "spk_priv.h"
-#include "speakup.h"
-#include "speakup_acnt.h" /* local header file for Accent values */
-
-#define DRV_VERSION "2.11"
-#define PROCSPEECH '\r'
-
-static int synth_probe(struct spk_synth *synth);
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\033P8" } },
-       { CAPS_STOP, .u.s = {"\033P5" } },
-       { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" } },
-       { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL } },
-       { VOL, .u.n = {"\033A%d", 9, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/acntsa.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute tone_attribute =
-       __ATTR(tone, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &rate_attribute.attr,
-       &tone_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_acntsa = {
-       .name = "acntsa",
-       .version = DRV_VERSION,
-       .long_name = "Accent-SA",
-       .init = "\033T2\033=M\033Oi\033N1\n",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 400,
-       .trigger = 50,
-       .jiffies = 30,
-       .full = 40000,
-       .dev_name = SYNTH_DEFAULT_DEV,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_ttyio_ops,
-       .probe = synth_probe,
-       .release = spk_ttyio_release,
-       .synth_immediate = spk_ttyio_synth_immediate,
-       .catch_up = spk_do_catch_up,
-       .flush = spk_synth_flush,
-       .is_alive = spk_synth_is_alive_restart,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = NULL,
-       .indexing = {
-               .command = NULL,
-               .lowindex = 0,
-               .highindex = 0,
-               .currindex = 0,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "acntsa",
-       },
-};
-
-static int synth_probe(struct spk_synth *synth)
-{
-       int failed;
-
-       failed = spk_ttyio_synth_probe(synth);
-       if (failed == 0) {
-               synth->synth_immediate(synth, "\033=R\r");
-               mdelay(100);
-       }
-       synth->alive = !failed;
-       return failed;
-}
-
-module_param_named(ser, synth_acntsa.ser, int, 0444);
-module_param_named(dev, synth_acntsa.dev_name, charp, 0444);
-module_param_named(start, synth_acntsa.startup, short, 0444);
-
-MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
-MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_acntsa);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for Accent SA synthesizer");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_apollo.c b/drivers/staging/speakup/speakup_apollo.c
deleted file mode 100644 (file)
index 0877b40..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * this code is specificly written as a driver for the speakup screenreview
- * package and is not a general device driver.
- */
-#include <linux/jiffies.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/kthread.h>
-#include <linux/serial_reg.h>  /* for UART_MCR* constants */
-
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define DRV_VERSION "2.21"
-#define SYNTH_CLEAR 0x18
-#define PROCSPEECH '\r'
-
-static void do_catch_up(struct spk_synth *synth);
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"cap, " } },
-       { CAPS_STOP, .u.s = {"" } },
-       { RATE, .u.n = {"@W%d", 6, 1, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"@F%x", 10, 0, 15, 0, 0, NULL } },
-       { VOL, .u.n = {"@A%x", 10, 0, 15, 0, 0, NULL } },
-       { VOICE, .u.n = {"@V%d", 1, 1, 6, 0, 0, NULL } },
-       { LANG, .u.n = {"@=%d,", 1, 1, 4, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/apollo.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute lang_attribute =
-       __ATTR(lang, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute voice_attribute =
-       __ATTR(voice, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &lang_attribute.attr,
-       &pitch_attribute.attr,
-       &rate_attribute.attr,
-       &voice_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_apollo = {
-       .name = "apollo",
-       .version = DRV_VERSION,
-       .long_name = "Apollo",
-       .init = "@R3@D0@K1\r",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 40000,
-       .dev_name = SYNTH_DEFAULT_DEV,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_ttyio_ops,
-       .probe = spk_ttyio_synth_probe,
-       .release = spk_ttyio_release,
-       .synth_immediate = spk_ttyio_synth_immediate,
-       .catch_up = do_catch_up,
-       .flush = spk_synth_flush,
-       .is_alive = spk_synth_is_alive_restart,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = NULL,
-       .indexing = {
-               .command = NULL,
-               .lowindex = 0,
-               .highindex = 0,
-               .currindex = 0,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "apollo",
-       },
-};
-
-static void do_catch_up(struct spk_synth *synth)
-{
-       u_char ch;
-       unsigned long flags;
-       unsigned long jiff_max;
-       struct var_t *jiffy_delta;
-       struct var_t *delay_time;
-       struct var_t *full_time;
-       int full_time_val = 0;
-       int delay_time_val = 0;
-       int jiffy_delta_val = 0;
-
-       jiffy_delta = spk_get_var(JIFFY);
-       delay_time = spk_get_var(DELAY);
-       full_time = spk_get_var(FULL);
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       jiffy_delta_val = jiffy_delta->u.n.value;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       jiff_max = jiffies + jiffy_delta_val;
-
-       while (!kthread_should_stop()) {
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               jiffy_delta_val = jiffy_delta->u.n.value;
-               full_time_val = full_time->u.n.value;
-               delay_time_val = delay_time->u.n.value;
-               if (speakup_info.flushing) {
-                       speakup_info.flushing = 0;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       synth->flush(synth);
-                       continue;
-               }
-               synth_buffer_skip_nonlatin1();
-               if (synth_buffer_empty()) {
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       break;
-               }
-               ch = synth_buffer_peek();
-               set_current_state(TASK_INTERRUPTIBLE);
-               full_time_val = full_time->u.n.value;
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (!synth->io_ops->synth_out(synth, ch)) {
-                       synth->io_ops->tiocmset(0, UART_MCR_RTS);
-                       synth->io_ops->tiocmset(UART_MCR_RTS, 0);
-                       schedule_timeout(msecs_to_jiffies(full_time_val));
-                       continue;
-               }
-               if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
-                       spin_lock_irqsave(&speakup_info.spinlock, flags);
-                       jiffy_delta_val = jiffy_delta->u.n.value;
-                       full_time_val = full_time->u.n.value;
-                       delay_time_val = delay_time->u.n.value;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       if (synth->io_ops->synth_out(synth, synth->procspeech))
-                               schedule_timeout(msecs_to_jiffies
-                                                (delay_time_val));
-                       else
-                               schedule_timeout(msecs_to_jiffies
-                                                (full_time_val));
-                       jiff_max = jiffies + jiffy_delta_val;
-               }
-               set_current_state(TASK_RUNNING);
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               synth_buffer_getc();
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       }
-       synth->io_ops->synth_out(synth, PROCSPEECH);
-}
-
-module_param_named(ser, synth_apollo.ser, int, 0444);
-module_param_named(dev, synth_apollo.dev_name, charp, 0444);
-module_param_named(start, synth_apollo.startup, short, 0444);
-
-MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
-MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_apollo);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for Apollo II synthesizer");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_audptr.c b/drivers/staging/speakup/speakup_audptr.c
deleted file mode 100644 (file)
index e6a6a96..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * specificly written as a driver for the speakup screenreview
- * s not a general device driver.
- */
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define DRV_VERSION "2.11"
-#define SYNTH_CLEAR 0x18 /* flush synth buffer */
-#define PROCSPEECH '\r' /* start synth processing speech char */
-
-static int synth_probe(struct spk_synth *synth);
-static void synth_flush(struct spk_synth *synth);
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x05[f99]" } },
-       { CAPS_STOP, .u.s = {"\x05[f80]" } },
-       { RATE, .u.n = {"\x05[r%d]", 10, 0, 20, 100, -10, NULL } },
-       { PITCH, .u.n = {"\x05[f%d]", 80, 39, 4500, 0, 0, NULL } },
-       { VOL, .u.n = {"\x05[g%d]", 21, 0, 40, 0, 0, NULL } },
-       { TONE, .u.n = {"\x05[s%d]", 9, 0, 63, 0, 0, NULL } },
-       { PUNCT, .u.n = {"\x05[A%c]", 0, 0, 3, 0, 0, "nmsa" } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/audptr.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute punct_attribute =
-       __ATTR(punct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute tone_attribute =
-       __ATTR(tone, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &punct_attribute.attr,
-       &rate_attribute.attr,
-       &tone_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_audptr = {
-       .name = "audptr",
-       .version = DRV_VERSION,
-       .long_name = "Audapter",
-       .init = "\x05[D1]\x05[Ol]",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 400,
-       .trigger = 50,
-       .jiffies = 30,
-       .full = 18000,
-       .dev_name = SYNTH_DEFAULT_DEV,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_ttyio_ops,
-       .probe = synth_probe,
-       .release = spk_ttyio_release,
-       .synth_immediate = spk_ttyio_synth_immediate,
-       .catch_up = spk_do_catch_up,
-       .flush = synth_flush,
-       .is_alive = spk_synth_is_alive_restart,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = NULL,
-       .indexing = {
-               .command = NULL,
-               .lowindex = 0,
-               .highindex = 0,
-               .currindex = 0,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "audptr",
-       },
-};
-
-static void synth_flush(struct spk_synth *synth)
-{
-       synth->io_ops->flush_buffer();
-       synth->io_ops->send_xchar(SYNTH_CLEAR);
-       synth->io_ops->synth_out(synth, PROCSPEECH);
-}
-
-static void synth_version(struct spk_synth *synth)
-{
-       unsigned char test = 0;
-       char synth_id[40] = "";
-
-       synth->synth_immediate(synth, "\x05[Q]");
-       synth_id[test] = synth->io_ops->synth_in();
-       if (synth_id[test] == 'A') {
-               do {
-                       /* read version string from synth */
-                       synth_id[++test] = synth->io_ops->synth_in();
-               } while (synth_id[test] != '\n' && test < 32);
-               synth_id[++test] = 0x00;
-       }
-       if (synth_id[0] == 'A')
-               pr_info("%s version: %s", synth->long_name, synth_id);
-}
-
-static int synth_probe(struct spk_synth *synth)
-{
-       int failed;
-
-       failed = spk_ttyio_synth_probe(synth);
-       if (failed == 0)
-               synth_version(synth);
-       synth->alive = !failed;
-       return 0;
-}
-
-module_param_named(ser, synth_audptr.ser, int, 0444);
-module_param_named(dev, synth_audptr.dev_name, charp, 0444);
-module_param_named(start, synth_audptr.startup, short, 0444);
-
-MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
-MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_audptr);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for Audapter synthesizer");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_bns.c b/drivers/staging/speakup/speakup_bns.c
deleted file mode 100644 (file)
index 76dfa3f..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * this code is specificly written as a driver for the speakup screenreview
- * package and is not a general device driver.
- */
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define DRV_VERSION "2.11"
-#define SYNTH_CLEAR 0x18
-#define PROCSPEECH '\r'
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x05\x31\x32P" } },
-       { CAPS_STOP, .u.s = {"\x05\x38P" } },
-       { RATE, .u.n = {"\x05%dE", 8, 1, 16, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x05%dP", 8, 0, 16, 0, 0, NULL } },
-       { VOL, .u.n = {"\x05%dV", 8, 0, 16, 0, 0, NULL } },
-       { TONE, .u.n = {"\x05%dT", 8, 0, 16, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/bns.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute tone_attribute =
-       __ATTR(tone, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &rate_attribute.attr,
-       &tone_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_bns = {
-       .name = "bns",
-       .version = DRV_VERSION,
-       .long_name = "Braille 'N Speak",
-       .init = "\x05Z\x05\x43",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 40000,
-       .dev_name = SYNTH_DEFAULT_DEV,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_ttyio_ops,
-       .probe = spk_ttyio_synth_probe,
-       .release = spk_ttyio_release,
-       .synth_immediate = spk_ttyio_synth_immediate,
-       .catch_up = spk_do_catch_up,
-       .flush = spk_synth_flush,
-       .is_alive = spk_synth_is_alive_restart,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = NULL,
-       .indexing = {
-               .command = NULL,
-               .lowindex = 0,
-               .highindex = 0,
-               .currindex = 0,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "bns",
-       },
-};
-
-module_param_named(ser, synth_bns.ser, int, 0444);
-module_param_named(dev, synth_bns.dev_name, charp, 0444);
-module_param_named(start, synth_bns.startup, short, 0444);
-
-MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
-MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_bns);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for Braille 'n Speak synthesizers");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_decext.c b/drivers/staging/speakup/speakup_decext.c
deleted file mode 100644 (file)
index 7408eb2..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * specificly written as a driver for the speakup screenreview
- * s not a general device driver.
- */
-#include <linux/jiffies.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/kthread.h>
-
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define DRV_VERSION "2.14"
-#define SYNTH_CLEAR 0x03
-#define PROCSPEECH 0x0b
-
-static volatile unsigned char last_char;
-
-static void read_buff_add(u_char ch)
-{
-       last_char = ch;
-}
-
-static inline bool synth_full(void)
-{
-       return last_char == 0x13;
-}
-
-static void do_catch_up(struct spk_synth *synth);
-static void synth_flush(struct spk_synth *synth);
-
-static int in_escape;
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"[:dv ap 222]" } },
-       { CAPS_STOP, .u.s = {"[:dv ap 100]" } },
-       { RATE, .u.n = {"[:ra %d]", 7, 0, 9, 150, 25, NULL } },
-       { PITCH, .u.n = {"[:dv ap %d]", 100, 0, 100, 0, 0, NULL } },
-       { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
-       { VOL, .u.n = {"[:dv gv %d]", 13, 0, 16, 0, 5, NULL } },
-       { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" } },
-       { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/decext.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute inflection_attribute =
-       __ATTR(inflection, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute punct_attribute =
-       __ATTR(punct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute voice_attribute =
-       __ATTR(voice, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &inflection_attribute.attr,
-       &punct_attribute.attr,
-       &rate_attribute.attr,
-       &voice_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_decext = {
-       .name = "decext",
-       .version = DRV_VERSION,
-       .long_name = "Dectalk External",
-       .init = "[:pe -380]",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 40000,
-       .flags = SF_DEC,
-       .dev_name = SYNTH_DEFAULT_DEV,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_ttyio_ops,
-       .probe = spk_ttyio_synth_probe,
-       .release = spk_ttyio_release,
-       .synth_immediate = spk_ttyio_synth_immediate,
-       .catch_up = do_catch_up,
-       .flush = synth_flush,
-       .is_alive = spk_synth_is_alive_restart,
-       .synth_adjust = NULL,
-       .read_buff_add = read_buff_add,
-       .get_index = NULL,
-       .indexing = {
-               .command = NULL,
-               .lowindex = 0,
-               .highindex = 0,
-               .currindex = 0,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "decext",
-       },
-};
-
-static void do_catch_up(struct spk_synth *synth)
-{
-       u_char ch;
-       static u_char last = '\0';
-       unsigned long flags;
-       unsigned long jiff_max;
-       struct var_t *jiffy_delta;
-       struct var_t *delay_time;
-       int jiffy_delta_val = 0;
-       int delay_time_val = 0;
-
-       jiffy_delta = spk_get_var(JIFFY);
-       delay_time = spk_get_var(DELAY);
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       jiffy_delta_val = jiffy_delta->u.n.value;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       jiff_max = jiffies + jiffy_delta_val;
-
-       while (!kthread_should_stop()) {
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               if (speakup_info.flushing) {
-                       speakup_info.flushing = 0;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       synth->flush(synth);
-                       continue;
-               }
-               synth_buffer_skip_nonlatin1();
-               if (synth_buffer_empty()) {
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       break;
-               }
-               ch = synth_buffer_peek();
-               set_current_state(TASK_INTERRUPTIBLE);
-               delay_time_val = delay_time->u.n.value;
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (ch == '\n')
-                       ch = 0x0D;
-               if (synth_full() || !synth->io_ops->synth_out(synth, ch)) {
-                       schedule_timeout(msecs_to_jiffies(delay_time_val));
-                       continue;
-               }
-               set_current_state(TASK_RUNNING);
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               synth_buffer_getc();
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (ch == '[') {
-                       in_escape = 1;
-               } else if (ch == ']') {
-                       in_escape = 0;
-               } else if (ch <= SPACE) {
-                       if (!in_escape && strchr(",.!?;:", last))
-                               synth->io_ops->synth_out(synth, PROCSPEECH);
-                       if (time_after_eq(jiffies, jiff_max)) {
-                               if (!in_escape)
-                                       synth->io_ops->synth_out(synth,
-                                                                PROCSPEECH);
-                               spin_lock_irqsave(&speakup_info.spinlock,
-                                                 flags);
-                               jiffy_delta_val = jiffy_delta->u.n.value;
-                               delay_time_val = delay_time->u.n.value;
-                               spin_unlock_irqrestore(&speakup_info.spinlock,
-                                                      flags);
-                               schedule_timeout(msecs_to_jiffies
-                                                (delay_time_val));
-                               jiff_max = jiffies + jiffy_delta_val;
-                       }
-               }
-               last = ch;
-       }
-       if (!in_escape)
-               synth->io_ops->synth_out(synth, PROCSPEECH);
-}
-
-static void synth_flush(struct spk_synth *synth)
-{
-       in_escape = 0;
-       synth->io_ops->flush_buffer();
-       synth->synth_immediate(synth, "\033P;10z\033\\");
-}
-
-module_param_named(ser, synth_decext.ser, int, 0444);
-module_param_named(dev, synth_decext.dev_name, charp, 0444);
-module_param_named(start, synth_decext.startup, short, 0444);
-
-MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
-MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_decext);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for DECtalk External synthesizers");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_decpc.c b/drivers/staging/speakup/speakup_decpc.c
deleted file mode 100644 (file)
index 96f24c8..0000000
+++ /dev/null
@@ -1,495 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * This is the DECtalk PC speakup driver
- *
- * Some constants from DEC's DOS driver:
- *      Copyright (c) by Digital Equipment Corp.
- *
- * 386BSD DECtalk PC driver:
- *      Copyright (c) 1996 Brian Buhrow <buhrow@lothlorien.nfbcal.org>
- *
- * Linux DECtalk PC driver:
- *      Copyright (c) 1997 Nicolas Pitre <nico@cam.org>
- *
- * speakup DECtalk PC Internal driver:
- *      Copyright (c) 2003 David Borowski <david575@golden.net>
- *
- * All rights reserved.
- */
-#include <linux/jiffies.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/kthread.h>
-
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define        MODULE_init             0x0dec  /* module in boot code */
-#define        MODULE_self_test        0x8800  /* module in self-test */
-#define        MODULE_reset            0xffff  /* reinit the whole module */
-
-#define        MODE_mask               0xf000  /* mode bits in high nibble */
-#define        MODE_null               0x0000
-#define        MODE_test               0x2000  /* in testing mode */
-#define        MODE_status             0x8000
-#define        STAT_int                0x0001  /* running in interrupt mode */
-#define        STAT_tr_char            0x0002  /* character data to transmit */
-#define        STAT_rr_char            0x0004  /* ready to receive char data */
-#define        STAT_cmd_ready          0x0008  /* ready to accept commands */
-#define        STAT_dma_ready          0x0010  /* dma command ready */
-#define        STAT_digitized          0x0020  /* spc in digitized mode */
-#define        STAT_new_index          0x0040  /* new last index ready */
-#define        STAT_new_status         0x0080  /* new status posted */
-#define        STAT_dma_state          0x0100  /* dma state toggle */
-#define        STAT_index_valid        0x0200  /* indexs are valid */
-#define        STAT_flushing           0x0400  /* flush in progress */
-#define        STAT_self_test          0x0800  /* module in self test */
-#define        MODE_ready              0xc000  /* module ready for next phase */
-#define        READY_boot              0x0000
-#define        READY_kernel            0x0001
-#define        MODE_error              0xf000
-
-#define        CMD_mask                0xf000  /* mask for command nibble */
-#define        CMD_null                0x0000  /* post status */
-#define        CMD_control             0x1000  /* hard control command */
-#define        CTRL_mask               0x0F00  /* mask off control nibble */
-#define        CTRL_data               0x00FF  /* mask to get data byte */
-#define        CTRL_null               0x0000  /* null control */
-#define        CTRL_vol_up             0x0100  /* increase volume */
-#define        CTRL_vol_down           0x0200  /* decrease volume */
-#define        CTRL_vol_set            0x0300  /* set volume */
-#define        CTRL_pause              0x0400  /* pause spc */
-#define        CTRL_resume             0x0500  /* resume spc clock */
-#define        CTRL_resume_spc         0x0001  /* resume spc soft pause */
-#define        CTRL_flush              0x0600  /* flush all buffers */
-#define        CTRL_int_enable         0x0700  /* enable status change ints */
-#define        CTRL_buff_free          0x0800  /* buffer remain count */
-#define        CTRL_buff_used          0x0900  /* buffer in use */
-#define        CTRL_speech             0x0a00  /* immediate speech change */
-#define        CTRL_SP_voice           0x0001  /* voice change */
-#define        CTRL_SP_rate            0x0002  /* rate change */
-#define        CTRL_SP_comma           0x0003  /* comma pause change */
-#define        CTRL_SP_period          0x0004  /* period pause change */
-#define        CTRL_SP_rate_delta      0x0005  /* delta rate change */
-#define        CTRL_SP_get_param       0x0006  /* return the desired parameter */
-#define        CTRL_last_index         0x0b00  /* get last index spoken */
-#define        CTRL_io_priority        0x0c00  /* change i/o priority */
-#define        CTRL_free_mem           0x0d00  /* get free paragraphs on module */
-#define        CTRL_get_lang           0x0e00  /* return bitmask of loaded languages */
-#define        CMD_test                0x2000  /* self-test request */
-#define        TEST_mask               0x0F00  /* isolate test field */
-#define        TEST_null               0x0000  /* no test requested */
-#define        TEST_isa_int            0x0100  /* assert isa irq */
-#define        TEST_echo               0x0200  /* make data in == data out */
-#define        TEST_seg                0x0300  /* set peek/poke segment */
-#define        TEST_off                0x0400  /* set peek/poke offset */
-#define        TEST_peek               0x0500  /* data out == *peek */
-#define        TEST_poke               0x0600  /* *peek == data in */
-#define        TEST_sub_code           0x00FF  /* user defined test sub codes */
-#define        CMD_id                  0x3000  /* return software id */
-#define        ID_null                 0x0000  /* null id */
-#define        ID_kernel               0x0100  /* kernel code executing */
-#define        ID_boot                 0x0200  /* boot code executing */
-#define        CMD_dma                 0x4000  /* force a dma start */
-#define        CMD_reset               0x5000  /* reset module status */
-#define        CMD_sync                0x6000  /* kernel sync command */
-#define        CMD_char_in             0x7000  /* single character send */
-#define        CMD_char_out            0x8000  /* single character get */
-#define        CHAR_count_1            0x0100  /* one char in cmd_low */
-#define        CHAR_count_2            0x0200  /* the second in data_low */
-#define        CHAR_count_3            0x0300  /* the third in data_high */
-#define        CMD_spc_mode            0x9000  /* change spc mode */
-#define        CMD_spc_to_text         0x0100  /* set to text mode */
-#define        CMD_spc_to_digit        0x0200  /* set to digital mode */
-#define        CMD_spc_rate            0x0400  /* change spc data rate */
-#define        CMD_error               0xf000  /* severe error */
-
-enum { PRIMARY_DIC     = 0, USER_DIC, COMMAND_DIC, ABBREV_DIC };
-
-#define        DMA_single_in           0x01
-#define        DMA_single_out          0x02
-#define        DMA_buff_in             0x03
-#define        DMA_buff_out            0x04
-#define        DMA_control             0x05
-#define        DT_MEM_ALLOC            0x03
-#define        DT_SET_DIC              0x04
-#define        DT_START_TASK           0x05
-#define        DT_LOAD_MEM             0x06
-#define        DT_READ_MEM             0x07
-#define        DT_DIGITAL_IN           0x08
-#define        DMA_sync                0x06
-#define        DMA_sync_char           0x07
-
-#define DRV_VERSION "2.12"
-#define PROCSPEECH 0x0b
-#define SYNTH_IO_EXTENT 8
-
-static int synth_probe(struct spk_synth *synth);
-static void dtpc_release(void);
-static const char *synth_immediate(struct spk_synth *synth, const char *buf);
-static void do_catch_up(struct spk_synth *synth);
-static void synth_flush(struct spk_synth *synth);
-
-static int synth_portlist[] = { 0x340, 0x350, 0x240, 0x250, 0 };
-static int in_escape, is_flushing;
-static int dt_stat, dma_state;
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"[:dv ap 200]" } },
-       { CAPS_STOP, .u.s = {"[:dv ap 100]" } },
-       { RATE, .u.n = {"[:ra %d]", 9, 0, 18, 150, 25, NULL } },
-       { PITCH, .u.n = {"[:dv ap %d]", 80, 0, 100, 20, 0, NULL } },
-       { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
-       { VOL, .u.n = {"[:vo se %d]", 5, 0, 9, 5, 10, NULL } },
-       { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" } },
-       { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/decpc.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute inflection_attribute =
-       __ATTR(inflection, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute punct_attribute =
-       __ATTR(punct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute voice_attribute =
-       __ATTR(voice, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &inflection_attribute.attr,
-       &punct_attribute.attr,
-       &rate_attribute.attr,
-       &voice_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_dec_pc = {
-       .name = "decpc",
-       .version = DRV_VERSION,
-       .long_name = "Dectalk PC",
-       .init = "[:pe -380]",
-       .procspeech = PROCSPEECH,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 1000,
-       .flags = SF_DEC,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_serial_io_ops,
-       .probe = synth_probe,
-       .release = dtpc_release,
-       .synth_immediate = synth_immediate,
-       .catch_up = do_catch_up,
-       .flush = synth_flush,
-       .is_alive = spk_synth_is_alive_nop,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = NULL,
-       .indexing = {
-               .command = NULL,
-               .lowindex = 0,
-               .highindex = 0,
-               .currindex = 0,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "decpc",
-       },
-};
-
-static int dt_getstatus(void)
-{
-       dt_stat = inb_p(speakup_info.port_tts) |
-                (inb_p(speakup_info.port_tts + 1) << 8);
-       return dt_stat;
-}
-
-static void dt_sendcmd(u_int cmd)
-{
-       outb_p(cmd & 0xFF, speakup_info.port_tts);
-       outb_p((cmd >> 8) & 0xFF, speakup_info.port_tts + 1);
-}
-
-static int dt_waitbit(int bit)
-{
-       int timeout = 100;
-
-       while (--timeout > 0) {
-               if ((dt_getstatus() & bit) == bit)
-                       return 1;
-               udelay(50);
-       }
-       return 0;
-}
-
-static int dt_wait_dma(void)
-{
-       int timeout = 100, state = dma_state;
-
-       if (!dt_waitbit(STAT_dma_ready))
-               return 0;
-       while (--timeout > 0) {
-               if ((dt_getstatus() & STAT_dma_state) == state)
-                       return 1;
-               udelay(50);
-       }
-       dma_state = dt_getstatus() & STAT_dma_state;
-       return 1;
-}
-
-static int dt_ctrl(u_int cmd)
-{
-       int timeout = 10;
-
-       if (!dt_waitbit(STAT_cmd_ready))
-               return -1;
-       outb_p(0, speakup_info.port_tts + 2);
-       outb_p(0, speakup_info.port_tts + 3);
-       dt_getstatus();
-       dt_sendcmd(CMD_control | cmd);
-       outb_p(0, speakup_info.port_tts + 6);
-       while (dt_getstatus() & STAT_cmd_ready) {
-               udelay(20);
-               if (--timeout == 0)
-                       break;
-       }
-       dt_sendcmd(CMD_null);
-       return 0;
-}
-
-static void synth_flush(struct spk_synth *synth)
-{
-       int timeout = 10;
-
-       if (is_flushing)
-               return;
-       is_flushing = 4;
-       in_escape = 0;
-       while (dt_ctrl(CTRL_flush)) {
-               if (--timeout == 0)
-                       break;
-               udelay(50);
-       }
-       for (timeout = 0; timeout < 10; timeout++) {
-               if (dt_waitbit(STAT_dma_ready))
-                       break;
-               udelay(50);
-       }
-       outb_p(DMA_sync, speakup_info.port_tts + 4);
-       outb_p(0, speakup_info.port_tts + 4);
-       udelay(100);
-       for (timeout = 0; timeout < 10; timeout++) {
-               if (!(dt_getstatus() & STAT_flushing))
-                       break;
-               udelay(50);
-       }
-       dma_state = dt_getstatus() & STAT_dma_state;
-       dma_state ^= STAT_dma_state;
-       is_flushing = 0;
-}
-
-static int dt_sendchar(char ch)
-{
-       if (!dt_wait_dma())
-               return -1;
-       if (!(dt_stat & STAT_rr_char))
-               return -2;
-       outb_p(DMA_single_in, speakup_info.port_tts + 4);
-       outb_p(ch, speakup_info.port_tts + 4);
-       dma_state ^= STAT_dma_state;
-       return 0;
-}
-
-static int testkernel(void)
-{
-       int status = 0;
-
-       if (dt_getstatus() == 0xffff) {
-               status = -1;
-               goto oops;
-       }
-       dt_sendcmd(CMD_sync);
-       if (!dt_waitbit(STAT_cmd_ready))
-               status = -2;
-       else if (dt_stat & 0x8000)
-               return 0;
-       else if (dt_stat == 0x0dec)
-               pr_warn("dec_pc at 0x%x, software not loaded\n",
-                       speakup_info.port_tts);
-       status = -3;
-oops:  synth_release_region(speakup_info.port_tts, SYNTH_IO_EXTENT);
-       speakup_info.port_tts = 0;
-       return status;
-}
-
-static void do_catch_up(struct spk_synth *synth)
-{
-       u_char ch;
-       static u_char last;
-       unsigned long flags;
-       unsigned long jiff_max;
-       struct var_t *jiffy_delta;
-       struct var_t *delay_time;
-       int jiffy_delta_val;
-       int delay_time_val;
-
-       jiffy_delta = spk_get_var(JIFFY);
-       delay_time = spk_get_var(DELAY);
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       jiffy_delta_val = jiffy_delta->u.n.value;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       jiff_max = jiffies + jiffy_delta_val;
-
-       while (!kthread_should_stop()) {
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               if (speakup_info.flushing) {
-                       speakup_info.flushing = 0;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       synth->flush(synth);
-                       continue;
-               }
-               synth_buffer_skip_nonlatin1();
-               if (synth_buffer_empty()) {
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       break;
-               }
-               ch = synth_buffer_peek();
-               set_current_state(TASK_INTERRUPTIBLE);
-               delay_time_val = delay_time->u.n.value;
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (ch == '\n')
-                       ch = 0x0D;
-               if (dt_sendchar(ch)) {
-                       schedule_timeout(msecs_to_jiffies(delay_time_val));
-                       continue;
-               }
-               set_current_state(TASK_RUNNING);
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               synth_buffer_getc();
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (ch == '[') {
-                       in_escape = 1;
-               } else if (ch == ']') {
-                       in_escape = 0;
-               } else if (ch <= SPACE) {
-                       if (!in_escape && strchr(",.!?;:", last))
-                               dt_sendchar(PROCSPEECH);
-                       if (time_after_eq(jiffies, jiff_max)) {
-                               if (!in_escape)
-                                       dt_sendchar(PROCSPEECH);
-                               spin_lock_irqsave(&speakup_info.spinlock,
-                                                 flags);
-                               jiffy_delta_val = jiffy_delta->u.n.value;
-                               delay_time_val = delay_time->u.n.value;
-                               spin_unlock_irqrestore(&speakup_info.spinlock,
-                                                      flags);
-                               schedule_timeout(msecs_to_jiffies
-                                                (delay_time_val));
-                               jiff_max = jiffies + jiffy_delta_val;
-                       }
-               }
-               last = ch;
-               ch = 0;
-       }
-       if (!in_escape)
-               dt_sendchar(PROCSPEECH);
-}
-
-static const char *synth_immediate(struct spk_synth *synth, const char *buf)
-{
-       u_char ch;
-
-       while ((ch = *buf)) {
-               if (ch == '\n')
-                       ch = PROCSPEECH;
-               if (dt_sendchar(ch))
-                       return buf;
-               buf++;
-       }
-       return NULL;
-}
-
-static int synth_probe(struct spk_synth *synth)
-{
-       int i = 0, failed = 0;
-
-       pr_info("Probing for %s.\n", synth->long_name);
-       for (i = 0; synth_portlist[i]; i++) {
-               if (synth_request_region(synth_portlist[i], SYNTH_IO_EXTENT)) {
-                       pr_warn("request_region: failed with 0x%x, %d\n",
-                               synth_portlist[i], SYNTH_IO_EXTENT);
-                       continue;
-               }
-               speakup_info.port_tts = synth_portlist[i];
-               failed = testkernel();
-               if (failed == 0)
-                       break;
-       }
-       if (failed) {
-               pr_info("%s: not found\n", synth->long_name);
-               return -ENODEV;
-       }
-       pr_info("%s: %03x-%03x, Driver Version %s,\n", synth->long_name,
-               speakup_info.port_tts, speakup_info.port_tts + 7,
-               synth->version);
-       synth->alive = 1;
-       return 0;
-}
-
-static void dtpc_release(void)
-{
-       spk_stop_serial_interrupt();
-       if (speakup_info.port_tts)
-               synth_release_region(speakup_info.port_tts, SYNTH_IO_EXTENT);
-       speakup_info.port_tts = 0;
-}
-
-module_param_named(start, synth_dec_pc.startup, short, 0444);
-
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_dec_pc);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for DECtalk PC synthesizers");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/staging/speakup/speakup_dectlk.c b/drivers/staging/speakup/speakup_dectlk.c
deleted file mode 100644 (file)
index 780214b..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * specificly written as a driver for the speakup screenreview
- * s not a general device driver.
- */
-#include <linux/unistd.h>
-#include <linux/proc_fs.h>
-#include <linux/jiffies.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/kthread.h>
-#include "speakup.h"
-#include "spk_priv.h"
-
-#define DRV_VERSION "2.20"
-#define SYNTH_CLEAR 0x03
-#define PROCSPEECH 0x0b
-static int xoff;
-
-static inline int synth_full(void)
-{
-       return xoff;
-}
-
-static void do_catch_up(struct spk_synth *synth);
-static void synth_flush(struct spk_synth *synth);
-static void read_buff_add(u_char c);
-static unsigned char get_index(struct spk_synth *synth);
-
-static int in_escape;
-static int is_flushing;
-
-static spinlock_t flush_lock;
-static DECLARE_WAIT_QUEUE_HEAD(flush);
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"[:dv ap 160] " } },
-       { CAPS_STOP, .u.s = {"[:dv ap 100 ] " } },
-       { RATE, .u.n = {"[:ra %d] ", 180, 75, 650, 0, 0, NULL } },
-       { INFLECTION, .u.n = {"[:dv pr %d] ", 100, 0, 10000, 0, 0, NULL } },
-       { VOL, .u.n = {"[:dv g5 %d] ", 86, 60, 86, 0, 0, NULL } },
-       { PUNCT, .u.n = {"[:pu %c] ", 0, 0, 2, 0, 0, "nsa" } },
-       { VOICE, .u.n = {"[:n%c] ", 0, 0, 9, 0, 0, "phfdburwkv" } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/dectlk.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute inflection_attribute =
-       __ATTR(inflection, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute punct_attribute =
-       __ATTR(punct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute voice_attribute =
-       __ATTR(voice, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &inflection_attribute.attr,
-       &punct_attribute.attr,
-       &rate_attribute.attr,
-       &voice_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static int ap_defaults[] = {122, 89, 155, 110, 208, 240, 200, 106, 306};
-static int g5_defaults[] = {86, 81, 86, 84, 81, 80, 83, 83, 73};
-
-static struct spk_synth synth_dectlk = {
-       .name = "dectlk",
-       .version = DRV_VERSION,
-       .long_name = "Dectalk Express",
-       .init = "[:error sp :name paul :rate 180 :tsr off] ",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 40000,
-       .dev_name = SYNTH_DEFAULT_DEV,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .default_pitch = ap_defaults,
-       .default_vol = g5_defaults,
-       .io_ops = &spk_ttyio_ops,
-       .probe = spk_ttyio_synth_probe,
-       .release = spk_ttyio_release,
-       .synth_immediate = spk_ttyio_synth_immediate,
-       .catch_up = do_catch_up,
-       .flush = synth_flush,
-       .is_alive = spk_synth_is_alive_restart,
-       .synth_adjust = NULL,
-       .read_buff_add = read_buff_add,
-       .get_index = get_index,
-       .indexing = {
-               .command = "[:in re %d ] ",
-               .lowindex = 1,
-               .highindex = 8,
-               .currindex = 1,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "dectlk",
-       },
-};
-
-static int is_indnum(u_char *ch)
-{
-       if ((*ch >= '0') && (*ch <= '9')) {
-               *ch = *ch - '0';
-               return 1;
-       }
-       return 0;
-}
-
-static u_char lastind;
-
-static unsigned char get_index(struct spk_synth *synth)
-{
-       u_char rv;
-
-       rv = lastind;
-       lastind = 0;
-       return rv;
-}
-
-static void read_buff_add(u_char c)
-{
-       static int ind = -1;
-
-       if (c == 0x01) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&flush_lock, flags);
-               is_flushing = 0;
-               wake_up_interruptible(&flush);
-               spin_unlock_irqrestore(&flush_lock, flags);
-       } else if (c == 0x13) {
-               xoff = 1;
-       } else if (c == 0x11) {
-               xoff = 0;
-       } else if (is_indnum(&c)) {
-               if (ind == -1)
-                       ind = c;
-               else
-                       ind = ind * 10 + c;
-       } else if ((c > 31) && (c < 127)) {
-               if (ind != -1)
-                       lastind = (u_char)ind;
-               ind = -1;
-       }
-}
-
-static void do_catch_up(struct spk_synth *synth)
-{
-       int synth_full_val = 0;
-       static u_char ch;
-       static u_char last = '\0';
-       unsigned long flags;
-       unsigned long jiff_max;
-       unsigned long timeout = msecs_to_jiffies(4000);
-       DEFINE_WAIT(wait);
-       struct var_t *jiffy_delta;
-       struct var_t *delay_time;
-       int jiffy_delta_val;
-       int delay_time_val;
-
-       jiffy_delta = spk_get_var(JIFFY);
-       delay_time = spk_get_var(DELAY);
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       jiffy_delta_val = jiffy_delta->u.n.value;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       jiff_max = jiffies + jiffy_delta_val;
-
-       while (!kthread_should_stop()) {
-               /* if no ctl-a in 4, send data anyway */
-               spin_lock_irqsave(&flush_lock, flags);
-               while (is_flushing && timeout) {
-                       prepare_to_wait(&flush, &wait, TASK_INTERRUPTIBLE);
-                       spin_unlock_irqrestore(&flush_lock, flags);
-                       timeout = schedule_timeout(timeout);
-                       spin_lock_irqsave(&flush_lock, flags);
-               }
-               finish_wait(&flush, &wait);
-               is_flushing = 0;
-               spin_unlock_irqrestore(&flush_lock, flags);
-
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               if (speakup_info.flushing) {
-                       speakup_info.flushing = 0;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       synth->flush(synth);
-                       continue;
-               }
-               synth_buffer_skip_nonlatin1();
-               if (synth_buffer_empty()) {
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       break;
-               }
-               ch = synth_buffer_peek();
-               set_current_state(TASK_INTERRUPTIBLE);
-               delay_time_val = delay_time->u.n.value;
-               synth_full_val = synth_full();
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (ch == '\n')
-                       ch = 0x0D;
-               if (synth_full_val || !synth->io_ops->synth_out(synth, ch)) {
-                       schedule_timeout(msecs_to_jiffies(delay_time_val));
-                       continue;
-               }
-               set_current_state(TASK_RUNNING);
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               synth_buffer_getc();
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (ch == '[') {
-                       in_escape = 1;
-               } else if (ch == ']') {
-                       in_escape = 0;
-               } else if (ch <= SPACE) {
-                       if (!in_escape && strchr(",.!?;:", last))
-                               synth->io_ops->synth_out(synth, PROCSPEECH);
-                       if (time_after_eq(jiffies, jiff_max)) {
-                               if (!in_escape)
-                                       synth->io_ops->synth_out(synth,
-                                                                PROCSPEECH);
-                               spin_lock_irqsave(&speakup_info.spinlock,
-                                                 flags);
-                               jiffy_delta_val = jiffy_delta->u.n.value;
-                               delay_time_val = delay_time->u.n.value;
-                               spin_unlock_irqrestore(&speakup_info.spinlock,
-                                                      flags);
-                               schedule_timeout(msecs_to_jiffies
-                                                (delay_time_val));
-                               jiff_max = jiffies + jiffy_delta_val;
-                       }
-               }
-               last = ch;
-       }
-       if (!in_escape)
-               synth->io_ops->synth_out(synth, PROCSPEECH);
-}
-
-static void synth_flush(struct spk_synth *synth)
-{
-       if (in_escape)
-               /* if in command output ']' so we don't get an error */
-               synth->io_ops->synth_out(synth, ']');
-       in_escape = 0;
-       is_flushing = 1;
-       synth->io_ops->flush_buffer();
-       synth->io_ops->synth_out(synth, SYNTH_CLEAR);
-}
-
-module_param_named(ser, synth_dectlk.ser, int, 0444);
-module_param_named(dev, synth_dectlk.dev_name, charp, 0444);
-module_param_named(start, synth_dectlk.startup, short, 0444);
-
-MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
-MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_dectlk);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for DECtalk Express synthesizers");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_dtlk.c b/drivers/staging/speakup/speakup_dtlk.c
deleted file mode 100644 (file)
index dbebed0..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * specificly written as a driver for the speakup screenreview
- * package it's not a general device driver.
- * This driver is for the RC Systems DoubleTalk PC internal synthesizer.
- */
-#include <linux/jiffies.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/kthread.h>
-
-#include "spk_priv.h"
-#include "serialio.h"
-#include "speakup_dtlk.h" /* local header file for DoubleTalk values */
-#include "speakup.h"
-
-#define DRV_VERSION "2.10"
-#define PROCSPEECH 0x00
-
-static int synth_probe(struct spk_synth *synth);
-static void dtlk_release(void);
-static const char *synth_immediate(struct spk_synth *synth, const char *buf);
-static void do_catch_up(struct spk_synth *synth);
-static void synth_flush(struct spk_synth *synth);
-
-static int synth_lpc;
-static int port_forced;
-static unsigned int synth_portlist[] = {
-                0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0
-};
-
-static u_char synth_status;
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x01+35p" } },
-       { CAPS_STOP, .u.s = {"\x01-35p" } },
-       { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL } },
-       { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
-       { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL } },
-       { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
-       { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/dtlk.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute freq_attribute =
-       __ATTR(freq, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute punct_attribute =
-       __ATTR(punct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute tone_attribute =
-       __ATTR(tone, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute voice_attribute =
-       __ATTR(voice, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &freq_attribute.attr,
-       &pitch_attribute.attr,
-       &punct_attribute.attr,
-       &rate_attribute.attr,
-       &tone_attribute.attr,
-       &voice_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_dtlk = {
-       .name = "dtlk",
-       .version = DRV_VERSION,
-       .long_name = "DoubleTalk PC",
-       .init = "\x01@\x01\x31y",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 30,
-       .jiffies = 50,
-       .full = 1000,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_serial_io_ops,
-       .probe = synth_probe,
-       .release = dtlk_release,
-       .synth_immediate = synth_immediate,
-       .catch_up = do_catch_up,
-       .flush = synth_flush,
-       .is_alive = spk_synth_is_alive_nop,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = spk_synth_get_index,
-       .indexing = {
-               .command = "\x01%di",
-               .lowindex = 1,
-               .highindex = 5,
-               .currindex = 1,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "dtlk",
-       },
-};
-
-static inline bool synth_readable(void)
-{
-       synth_status = inb_p(speakup_info.port_tts + UART_RX);
-       return (synth_status & TTS_READABLE) != 0;
-}
-
-static inline bool synth_writable(void)
-{
-       synth_status = inb_p(speakup_info.port_tts + UART_RX);
-       return (synth_status & TTS_WRITABLE) != 0;
-}
-
-static inline bool synth_full(void)
-{
-       synth_status = inb_p(speakup_info.port_tts + UART_RX);
-       return (synth_status & TTS_ALMOST_FULL) != 0;
-}
-
-static void spk_out(const char ch)
-{
-       int timeout = SPK_XMITR_TIMEOUT;
-
-       while (!synth_writable()) {
-               if (!--timeout)
-                       break;
-               udelay(1);
-       }
-       outb_p(ch, speakup_info.port_tts);
-       timeout = SPK_XMITR_TIMEOUT;
-       while (synth_writable()) {
-               if (!--timeout)
-                       break;
-               udelay(1);
-       }
-}
-
-static void do_catch_up(struct spk_synth *synth)
-{
-       u_char ch;
-       unsigned long flags;
-       unsigned long jiff_max;
-       struct var_t *jiffy_delta;
-       struct var_t *delay_time;
-       int jiffy_delta_val;
-       int delay_time_val;
-
-       jiffy_delta = spk_get_var(JIFFY);
-       delay_time = spk_get_var(DELAY);
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       jiffy_delta_val = jiffy_delta->u.n.value;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       jiff_max = jiffies + jiffy_delta_val;
-       while (!kthread_should_stop()) {
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               if (speakup_info.flushing) {
-                       speakup_info.flushing = 0;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       synth->flush(synth);
-                       continue;
-               }
-               synth_buffer_skip_nonlatin1();
-               if (synth_buffer_empty()) {
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       break;
-               }
-               set_current_state(TASK_INTERRUPTIBLE);
-               delay_time_val = delay_time->u.n.value;
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (synth_full()) {
-                       schedule_timeout(msecs_to_jiffies(delay_time_val));
-                       continue;
-               }
-               set_current_state(TASK_RUNNING);
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               ch = synth_buffer_getc();
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (ch == '\n')
-                       ch = PROCSPEECH;
-               spk_out(ch);
-               if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
-                       spk_out(PROCSPEECH);
-                       spin_lock_irqsave(&speakup_info.spinlock, flags);
-                       delay_time_val = delay_time->u.n.value;
-                       jiffy_delta_val = jiffy_delta->u.n.value;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       schedule_timeout(msecs_to_jiffies(delay_time_val));
-                       jiff_max = jiffies + jiffy_delta_val;
-               }
-       }
-       spk_out(PROCSPEECH);
-}
-
-static const char *synth_immediate(struct spk_synth *synth, const char *buf)
-{
-       u_char ch;
-
-       while ((ch = (u_char)*buf)) {
-               if (synth_full())
-                       return buf;
-               if (ch == '\n')
-                       ch = PROCSPEECH;
-               spk_out(ch);
-               buf++;
-       }
-       return NULL;
-}
-
-static void synth_flush(struct spk_synth *synth)
-{
-       outb_p(SYNTH_CLEAR, speakup_info.port_tts);
-       while (synth_writable())
-               cpu_relax();
-}
-
-static char synth_read_tts(void)
-{
-       u_char ch;
-
-       while (!synth_readable())
-               cpu_relax();
-       ch = synth_status & 0x7f;
-       outb_p(ch, speakup_info.port_tts);
-       while (synth_readable())
-               cpu_relax();
-       return (char)ch;
-}
-
-/* interrogate the DoubleTalk PC and return its settings */
-static struct synth_settings *synth_interrogate(struct spk_synth *synth)
-{
-       u_char *t;
-       static char buf[sizeof(struct synth_settings) + 1];
-       int total, i;
-       static struct synth_settings status;
-
-       synth_immediate(synth, "\x18\x01?");
-       for (total = 0, i = 0; i < 50; i++) {
-               buf[total] = synth_read_tts();
-               if (total > 2 && buf[total] == 0x7f)
-                       break;
-               if (total < sizeof(struct synth_settings))
-                       total++;
-       }
-       t = buf;
-       /* serial number is little endian */
-       status.serial_number = t[0] + t[1] * 256;
-       t += 2;
-       for (i = 0; *t != '\r'; t++) {
-               status.rom_version[i] = *t;
-               if (i < sizeof(status.rom_version) - 1)
-                       i++;
-       }
-       status.rom_version[i] = 0;
-       t++;
-       status.mode = *t++;
-       status.punc_level = *t++;
-       status.formant_freq = *t++;
-       status.pitch = *t++;
-       status.speed = *t++;
-       status.volume = *t++;
-       status.tone = *t++;
-       status.expression = *t++;
-       status.ext_dict_loaded = *t++;
-       status.ext_dict_status = *t++;
-       status.free_ram = *t++;
-       status.articulation = *t++;
-       status.reverb = *t++;
-       status.eob = *t++;
-       return &status;
-}
-
-static int synth_probe(struct spk_synth *synth)
-{
-       unsigned int port_val = 0;
-       int i = 0;
-       struct synth_settings *sp;
-
-       pr_info("Probing for DoubleTalk.\n");
-       if (port_forced) {
-               speakup_info.port_tts = port_forced;
-               pr_info("probe forced to %x by kernel command line\n",
-                       speakup_info.port_tts);
-               if ((port_forced & 0xf) != 0xf)
-                       pr_info("warning: port base should probably end with f\n");
-               if (synth_request_region(speakup_info.port_tts - 1,
-                                        SYNTH_IO_EXTENT)) {
-                       pr_warn("sorry, port already reserved\n");
-                       return -EBUSY;
-               }
-               port_val = inw(speakup_info.port_tts - 1);
-               synth_lpc = speakup_info.port_tts - 1;
-       } else {
-               for (i = 0; synth_portlist[i]; i++) {
-                       if (synth_request_region(synth_portlist[i],
-                                                SYNTH_IO_EXTENT))
-                               continue;
-                       port_val = inw(synth_portlist[i]) & 0xfbff;
-                       if (port_val == 0x107f) {
-                               synth_lpc = synth_portlist[i];
-                               speakup_info.port_tts = synth_lpc + 1;
-                               break;
-                       }
-                       synth_release_region(synth_portlist[i],
-                                            SYNTH_IO_EXTENT);
-               }
-       }
-       port_val &= 0xfbff;
-       if (port_val != 0x107f) {
-               pr_info("DoubleTalk PC: not found\n");
-               if (synth_lpc)
-                       synth_release_region(synth_lpc, SYNTH_IO_EXTENT);
-               return -ENODEV;
-       }
-       while (inw_p(synth_lpc) != 0x147f)
-               cpu_relax(); /* wait until it's ready */
-       sp = synth_interrogate(synth);
-       pr_info("%s: %03x-%03x, ROM ver %s, s/n %u, driver: %s\n",
-               synth->long_name, synth_lpc, synth_lpc + SYNTH_IO_EXTENT - 1,
-               sp->rom_version, sp->serial_number, synth->version);
-       synth->alive = 1;
-       return 0;
-}
-
-static void dtlk_release(void)
-{
-       spk_stop_serial_interrupt();
-       if (speakup_info.port_tts)
-               synth_release_region(speakup_info.port_tts - 1,
-                                    SYNTH_IO_EXTENT);
-       speakup_info.port_tts = 0;
-}
-
-module_param_hw_named(port, port_forced, int, ioport, 0444);
-module_param_named(start, synth_dtlk.startup, short, 0444);
-
-MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_dtlk);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for DoubleTalk PC synthesizers");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_dtlk.h b/drivers/staging/speakup/speakup_dtlk.h
deleted file mode 100644 (file)
index 9c378b5..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* speakup_dtlk.h - header file for speakups DoubleTalk driver. */
-
-#define SYNTH_IO_EXTENT        0x02
-#define SYNTH_CLEAR    0x18            /* stops speech */
-       /* TTS Port Status Flags */
-#define TTS_READABLE   0x80    /* mask for bit which is nonzero if a
-                                * byte can be read from the TTS port
-                                */
-#define TTS_SPEAKING   0x40    /* mask for SYNC bit, which is nonzero
-                                * while DoubleTalk is producing
-                                * output with TTS, PCM or CVSD
-                                * synthesizers or tone generators
-                                * (that is, all but LPC)
-                                */
-#define TTS_SPEAKING2  0x20    /* mask for SYNC2 bit,
-                                * which falls to zero up to 0.4 sec
-                                * before speech stops
-                                */
-#define TTS_WRITABLE   0x10    /* mask for RDY bit, which when set to
-                                * 1, indicates the TTS port is ready
-                                * to accept a byte of data.  The RDY
-                                * bit goes zero 2-3 usec after
-                                * writing, and goes 1 again 180-190
-                                * usec later.
-                                */
-#define TTS_ALMOST_FULL        0x08    /* mask for AF bit: When set to 1,
-                                * indicates that less than 300 bytes
-                                * are available in the TTS input
-                                * buffer. AF is always 0 in the PCM,
-                                * TGN and CVSD modes.
-                                */
-#define TTS_ALMOST_EMPTY 0x04  /* mask for AE bit: When set to 1,
-                                * indicates that less than 300 bytes
-                                * are remaining in DoubleTalk's input
-                                * (TTS or PCM) buffer. AE is always 1
-                                * in the TGN and CVSD modes.
-                                */
-
-                               /* data returned by Interrogate command */
-struct synth_settings {
-       u_short serial_number;  /* 0-7Fh:0-7Fh */
-       u_char rom_version[24]; /* null terminated string */
-       u_char mode;            /* 0=Character; 1=Phoneme; 2=Text */
-       u_char punc_level;      /* nB; 0-7 */
-       u_char formant_freq;    /* nF; 0-9 */
-       u_char pitch;           /* nP; 0-99 */
-       u_char speed;           /* nS; 0-9 */
-       u_char volume;          /* nV; 0-9 */
-       u_char tone;            /* nX; 0-2 */
-       u_char expression;      /* nE; 0-9 */
-       u_char ext_dict_loaded; /* 1=exception dictionary loaded */
-       u_char ext_dict_status; /* 1=exception dictionary enabled */
-       u_char free_ram;        /* # pages (truncated) remaining for
-                                * text buffer
-                                */
-       u_char articulation;    /* nA; 0-9 */
-       u_char reverb;          /* nR; 0-9 */
-       u_char eob;             /* 7Fh value indicating end of
-                                * parameter block
-                                */
-       u_char has_indexing;    /* nonzero if indexing is implemented */
-};
diff --git a/drivers/staging/speakup/speakup_dummy.c b/drivers/staging/speakup/speakup_dummy.c
deleted file mode 100644 (file)
index e393438..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- * eventually modified by Samuel Thibault <samuel.thibault@ens-lyon.org>
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- * Copyright (C) 2007 Samuel Thibault.
- *
- * specificly written as a driver for the speakup screenreview
- * s not a general device driver.
- */
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define PROCSPEECH '\n'
-#define DRV_VERSION "2.11"
-#define SYNTH_CLEAR '!'
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"CAPS_START\n" } },
-       { CAPS_STOP, .u.s = {"CAPS_STOP\n" } },
-       { PAUSE, .u.s = {"PAUSE\n"} },
-       { RATE, .u.n = {"RATE %d\n", 8, 1, 16, 0, 0, NULL } },
-       { PITCH, .u.n = {"PITCH %d\n", 8, 0, 16, 0, 0, NULL } },
-       { INFLECTION, .u.n = {"INFLECTION %d\n", 8, 0, 16, 0, 0, NULL } },
-       { VOL, .u.n = {"VOL %d\n", 8, 0, 16, 0, 0, NULL } },
-       { TONE, .u.n = {"TONE %d\n", 8, 0, 16, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/dummy.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute inflection_attribute =
-       __ATTR(inflection, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute tone_attribute =
-       __ATTR(tone, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &inflection_attribute.attr,
-       &rate_attribute.attr,
-       &tone_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_dummy = {
-       .name = "dummy",
-       .version = DRV_VERSION,
-       .long_name = "Dummy",
-       .init = "Speakup\n",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 40000,
-       .dev_name = SYNTH_DEFAULT_DEV,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_ttyio_ops,
-       .probe = spk_ttyio_synth_probe,
-       .release = spk_ttyio_release,
-       .synth_immediate = spk_ttyio_synth_immediate,
-       .catch_up = spk_do_catch_up_unicode,
-       .flush = spk_synth_flush,
-       .is_alive = spk_synth_is_alive_restart,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = NULL,
-       .indexing = {
-               .command = NULL,
-               .lowindex = 0,
-               .highindex = 0,
-               .currindex = 0,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "dummy",
-       },
-};
-
-module_param_named(ser, synth_dummy.ser, int, 0444);
-module_param_named(dev, synth_dummy.dev_name, charp, 0444);
-module_param_named(start, synth_dummy.startup, short, 0444);
-
-MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
-MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_dummy);
-
-MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
-MODULE_DESCRIPTION("Speakup support for text console");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_keypc.c b/drivers/staging/speakup/speakup_keypc.c
deleted file mode 100644 (file)
index 414827e..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * written by David Borowski
- *
- * Copyright (C) 2003 David Borowski.
- *
- * specificly written as a driver for the speakup screenreview
- * package it's not a general device driver.
- * This driver is for the Keynote Gold internal synthesizer.
- */
-#include <linux/jiffies.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/kthread.h>
-#include <linux/serial_reg.h>
-
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define DRV_VERSION "2.10"
-#define SYNTH_IO_EXTENT        0x04
-#define SWAIT udelay(70)
-#define PROCSPEECH 0x1f
-#define SYNTH_CLEAR 0x03
-
-static int synth_probe(struct spk_synth *synth);
-static void keynote_release(void);
-static const char *synth_immediate(struct spk_synth *synth, const char *buf);
-static void do_catch_up(struct spk_synth *synth);
-static void synth_flush(struct spk_synth *synth);
-
-static int synth_port;
-static int port_forced;
-static unsigned int synth_portlist[] = { 0x2a8, 0 };
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"[f130]" } },
-       { CAPS_STOP, .u.s = {"[f90]" } },
-       { RATE, .u.n = {"\04%c ", 8, 0, 10, 81, -8, NULL } },
-       { PITCH, .u.n = {"[f%d]", 5, 0, 9, 40, 10, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/keypc.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &rate_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_keypc = {
-       .name = "keypc",
-       .version = DRV_VERSION,
-       .long_name = "Keynote PC",
-       .init = "[t][n7,1][n8,0]",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 1000,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_serial_io_ops,
-       .probe = synth_probe,
-       .release = keynote_release,
-       .synth_immediate = synth_immediate,
-       .catch_up = do_catch_up,
-       .flush = synth_flush,
-       .is_alive = spk_synth_is_alive_nop,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = NULL,
-       .indexing = {
-               .command = NULL,
-               .lowindex = 0,
-               .highindex = 0,
-               .currindex = 0,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "keypc",
-       },
-};
-
-static inline bool synth_writable(void)
-{
-       return (inb_p(synth_port + UART_RX) & 0x10) != 0;
-}
-
-static inline bool synth_full(void)
-{
-       return (inb_p(synth_port + UART_RX) & 0x80) == 0;
-}
-
-static char *oops(void)
-{
-       int s1, s2, s3, s4;
-
-       s1 = inb_p(synth_port);
-       s2 = inb_p(synth_port + 1);
-       s3 = inb_p(synth_port + 2);
-       s4 = inb_p(synth_port + 3);
-       pr_warn("synth timeout %d %d %d %d\n", s1, s2, s3, s4);
-       return NULL;
-}
-
-static const char *synth_immediate(struct spk_synth *synth, const char *buf)
-{
-       u_char ch;
-       int timeout;
-
-       while ((ch = *buf)) {
-               if (ch == '\n')
-                       ch = PROCSPEECH;
-               if (synth_full())
-                       return buf;
-               timeout = 1000;
-               while (synth_writable())
-                       if (--timeout <= 0)
-                               return oops();
-               outb_p(ch, synth_port);
-               udelay(70);
-               buf++;
-       }
-       return NULL;
-}
-
-static void do_catch_up(struct spk_synth *synth)
-{
-       u_char ch;
-       int timeout;
-       unsigned long flags;
-       unsigned long jiff_max;
-       struct var_t *jiffy_delta;
-       struct var_t *delay_time;
-       struct var_t *full_time;
-       int delay_time_val;
-       int full_time_val;
-       int jiffy_delta_val;
-
-       jiffy_delta = spk_get_var(JIFFY);
-       delay_time = spk_get_var(DELAY);
-       full_time = spk_get_var(FULL);
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       jiffy_delta_val = jiffy_delta->u.n.value;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-
-       jiff_max = jiffies + jiffy_delta_val;
-       while (!kthread_should_stop()) {
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               if (speakup_info.flushing) {
-                       speakup_info.flushing = 0;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       synth->flush(synth);
-                       continue;
-               }
-               synth_buffer_skip_nonlatin1();
-               if (synth_buffer_empty()) {
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       break;
-               }
-               set_current_state(TASK_INTERRUPTIBLE);
-               full_time_val = full_time->u.n.value;
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (synth_full()) {
-                       schedule_timeout(msecs_to_jiffies(full_time_val));
-                       continue;
-               }
-               set_current_state(TASK_RUNNING);
-               timeout = 1000;
-               while (synth_writable())
-                       if (--timeout <= 0)
-                               break;
-               if (timeout <= 0) {
-                       oops();
-                       break;
-               }
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               ch = synth_buffer_getc();
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (ch == '\n')
-                       ch = PROCSPEECH;
-               outb_p(ch, synth_port);
-               SWAIT;
-               if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
-                       timeout = 1000;
-                       while (synth_writable())
-                               if (--timeout <= 0)
-                                       break;
-                       if (timeout <= 0) {
-                               oops();
-                               break;
-                       }
-                       outb_p(PROCSPEECH, synth_port);
-                       spin_lock_irqsave(&speakup_info.spinlock, flags);
-                       jiffy_delta_val = jiffy_delta->u.n.value;
-                       delay_time_val = delay_time->u.n.value;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       schedule_timeout(msecs_to_jiffies(delay_time_val));
-                       jiff_max = jiffies + jiffy_delta_val;
-               }
-       }
-       timeout = 1000;
-       while (synth_writable())
-               if (--timeout <= 0)
-                       break;
-       if (timeout <= 0)
-               oops();
-       else
-               outb_p(PROCSPEECH, synth_port);
-}
-
-static void synth_flush(struct spk_synth *synth)
-{
-       outb_p(SYNTH_CLEAR, synth_port);
-}
-
-static int synth_probe(struct spk_synth *synth)
-{
-       unsigned int port_val = 0;
-       int i = 0;
-
-       pr_info("Probing for %s.\n", synth->long_name);
-       if (port_forced) {
-               synth_port = port_forced;
-               pr_info("probe forced to %x by kernel command line\n",
-                       synth_port);
-               if (synth_request_region(synth_port - 1, SYNTH_IO_EXTENT)) {
-                       pr_warn("sorry, port already reserved\n");
-                       return -EBUSY;
-               }
-               port_val = inb(synth_port);
-       } else {
-               for (i = 0; synth_portlist[i]; i++) {
-                       if (synth_request_region(synth_portlist[i],
-                                                SYNTH_IO_EXTENT)) {
-                               pr_warn
-                                   ("request_region: failed with 0x%x, %d\n",
-                                    synth_portlist[i], SYNTH_IO_EXTENT);
-                               continue;
-                       }
-                       port_val = inb(synth_portlist[i]);
-                       if (port_val == 0x80) {
-                               synth_port = synth_portlist[i];
-                               break;
-                       }
-               }
-       }
-       if (port_val != 0x80) {
-               pr_info("%s: not found\n", synth->long_name);
-               synth_release_region(synth_port, SYNTH_IO_EXTENT);
-               synth_port = 0;
-               return -ENODEV;
-       }
-       pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name,
-               synth_port, synth_port + SYNTH_IO_EXTENT - 1,
-               synth->version);
-       synth->alive = 1;
-       return 0;
-}
-
-static void keynote_release(void)
-{
-       spk_stop_serial_interrupt();
-       if (synth_port)
-               synth_release_region(synth_port, SYNTH_IO_EXTENT);
-       synth_port = 0;
-}
-
-module_param_hw_named(port, port_forced, int, ioport, 0444);
-module_param_named(start, synth_keypc.startup, short, 0444);
-
-MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_keypc);
-
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for Keynote Gold PC synthesizers");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_ltlk.c b/drivers/staging/speakup/speakup_ltlk.c
deleted file mode 100644 (file)
index 3c59519..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * specificly written as a driver for the speakup screenreview
- * s not a general device driver.
- */
-#include "speakup.h"
-#include "spk_priv.h"
-#include "speakup_dtlk.h" /* local header file for LiteTalk values */
-
-#define DRV_VERSION "2.11"
-#define PROCSPEECH 0x0d
-
-static int synth_probe(struct spk_synth *synth);
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x01+35p" } },
-       { CAPS_STOP, .u.s = {"\x01-35p" } },
-       { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL } },
-       { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
-       { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL } },
-       { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
-       { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/*
- * These attributes will appear in /sys/accessibility/speakup/ltlk.
- */
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute freq_attribute =
-       __ATTR(freq, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute punct_attribute =
-       __ATTR(punct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute tone_attribute =
-       __ATTR(tone, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute voice_attribute =
-       __ATTR(voice, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &freq_attribute.attr,
-       &pitch_attribute.attr,
-       &punct_attribute.attr,
-       &rate_attribute.attr,
-       &tone_attribute.attr,
-       &voice_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_ltlk = {
-       .name = "ltlk",
-       .version = DRV_VERSION,
-       .long_name = "LiteTalk",
-       .init = "\01@\x01\x31y\n\0",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 40000,
-       .dev_name = SYNTH_DEFAULT_DEV,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_ttyio_ops,
-       .probe = synth_probe,
-       .release = spk_ttyio_release,
-       .synth_immediate = spk_ttyio_synth_immediate,
-       .catch_up = spk_do_catch_up,
-       .flush = spk_synth_flush,
-       .is_alive = spk_synth_is_alive_restart,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = spk_synth_get_index,
-       .indexing = {
-               .command = "\x01%di",
-               .lowindex = 1,
-               .highindex = 5,
-               .currindex = 1,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "ltlk",
-       },
-};
-
-/* interrogate the LiteTalk and print its settings */
-static void synth_interrogate(struct spk_synth *synth)
-{
-       unsigned char *t, i;
-       unsigned char buf[50], rom_v[20];
-
-       synth->synth_immediate(synth, "\x18\x01?");
-       for (i = 0; i < 50; i++) {
-               buf[i] = synth->io_ops->synth_in();
-               if (i > 2 && buf[i] == 0x7f)
-                       break;
-       }
-       t = buf + 2;
-       for (i = 0; *t != '\r'; t++) {
-               rom_v[i] = *t;
-               if (++i >= 19)
-                       break;
-       }
-       rom_v[i] = 0;
-       pr_info("%s: ROM version: %s\n", synth->long_name, rom_v);
-}
-
-static int synth_probe(struct spk_synth *synth)
-{
-       int failed = 0;
-
-       failed = spk_ttyio_synth_probe(synth);
-       if (failed == 0)
-               synth_interrogate(synth);
-       synth->alive = !failed;
-       return failed;
-}
-
-module_param_named(ser, synth_ltlk.ser, int, 0444);
-module_param_named(dev, synth_ltlk.dev_name, charp, 0444);
-module_param_named(start, synth_ltlk.startup, short, 0444);
-
-MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
-MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_ltlk);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for DoubleTalk LT/LiteTalk synthesizers");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_soft.c b/drivers/staging/speakup/speakup_soft.c
deleted file mode 100644 (file)
index 9a70295..0000000
+++ /dev/null
@@ -1,430 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/* speakup_soft.c - speakup driver to register and make available
- * a user space device for software synthesizers.  written by: Kirk
- * Reiser <kirk@braille.uwo.ca>
- *
- * Copyright (C) 2003  Kirk Reiser.
- *
- * this code is specificly written as a driver for the speakup screenreview
- * package and is not a general device driver.
- */
-
-#include <linux/unistd.h>
-#include <linux/miscdevice.h>  /* for misc_register, and MISC_DYNAMIC_MINOR */
-#include <linux/poll.h>                /* for poll_wait() */
-
-/* schedule(), signal_pending(), TASK_INTERRUPTIBLE */
-#include <linux/sched/signal.h>
-
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define DRV_VERSION "2.6"
-#define PROCSPEECH 0x0d
-#define CLEAR_SYNTH 0x18
-
-static int softsynth_probe(struct spk_synth *synth);
-static void softsynth_release(void);
-static int softsynth_is_alive(struct spk_synth *synth);
-static unsigned char get_index(struct spk_synth *synth);
-
-static struct miscdevice synth_device, synthu_device;
-static int init_pos;
-static int misc_registered;
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x01+3p" } },
-       { CAPS_STOP, .u.s = {"\x01-3p" } },
-       { PAUSE, .u.n = {"\x01P" } },
-       { RATE, .u.n = {"\x01%ds", 2, 0, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x01%dp", 5, 0, 9, 0, 0, NULL } },
-       { INFLECTION, .u.n = {"\x01%dr", 5, 0, 9, 0, 0, NULL } },
-       { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } },
-       { PUNCT, .u.n = {"\x01%db", 0, 0, 2, 0, 0, NULL } },
-       { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL } },
-       { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/* These attributes will appear in /sys/accessibility/speakup/soft. */
-
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute freq_attribute =
-       __ATTR(freq, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute inflection_attribute =
-       __ATTR(inflection, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute punct_attribute =
-       __ATTR(punct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute tone_attribute =
-       __ATTR(tone, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute voice_attribute =
-       __ATTR(voice, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-/*
- * We should uncomment the following definition, when we agree on a
- * method of passing a language designation to the software synthesizer.
- * static struct kobj_attribute lang_attribute =
- *     __ATTR(lang, 0644, spk_var_show, spk_var_store);
- */
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &freq_attribute.attr,
-/*     &lang_attribute.attr, */
-       &pitch_attribute.attr,
-       &inflection_attribute.attr,
-       &punct_attribute.attr,
-       &rate_attribute.attr,
-       &tone_attribute.attr,
-       &voice_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_soft = {
-       .name = "soft",
-       .version = DRV_VERSION,
-       .long_name = "software synth",
-       .init = "\01@\x01\x31y\n",
-       .procspeech = PROCSPEECH,
-       .delay = 0,
-       .trigger = 0,
-       .jiffies = 0,
-       .full = 0,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = NULL,
-       .probe = softsynth_probe,
-       .release = softsynth_release,
-       .synth_immediate = NULL,
-       .catch_up = NULL,
-       .flush = NULL,
-       .is_alive = softsynth_is_alive,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = get_index,
-       .indexing = {
-               .command = "\x01%di",
-               .lowindex = 1,
-               .highindex = 5,
-               .currindex = 1,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "soft",
-       },
-};
-
-static char *get_initstring(void)
-{
-       static char buf[40];
-       char *cp;
-       struct var_t *var;
-
-       memset(buf, 0, sizeof(buf));
-       cp = buf;
-       var = synth_soft.vars;
-       while (var->var_id != MAXVARS) {
-               if (var->var_id != CAPS_START && var->var_id != CAPS_STOP &&
-                   var->var_id != PAUSE && var->var_id != DIRECT)
-                       cp = cp + sprintf(cp, var->u.n.synth_fmt,
-                                         var->u.n.value);
-               var++;
-       }
-       cp = cp + sprintf(cp, "\n");
-       return buf;
-}
-
-static int softsynth_open(struct inode *inode, struct file *fp)
-{
-       unsigned long flags;
-       /*if ((fp->f_flags & O_ACCMODE) != O_RDONLY) */
-       /*      return -EPERM; */
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       if (synth_soft.alive) {
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               return -EBUSY;
-       }
-       synth_soft.alive = 1;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return 0;
-}
-
-static int softsynth_close(struct inode *inode, struct file *fp)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       synth_soft.alive = 0;
-       init_pos = 0;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       /* Make sure we let applications go before leaving */
-       speakup_start_ttys();
-       return 0;
-}
-
-static ssize_t softsynthx_read(struct file *fp, char __user *buf, size_t count,
-                              loff_t *pos, int unicode)
-{
-       int chars_sent = 0;
-       char __user *cp;
-       char *init;
-       size_t bytes_per_ch = unicode ? 3 : 1;
-       u16 ch;
-       int empty;
-       unsigned long flags;
-       DEFINE_WAIT(wait);
-
-       if (count < bytes_per_ch)
-               return -EINVAL;
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       synth_soft.alive = 1;
-       while (1) {
-               prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE);
-               if (synth_current() == &synth_soft) {
-                       if (!unicode)
-                               synth_buffer_skip_nonlatin1();
-                       if (!synth_buffer_empty() || speakup_info.flushing)
-                               break;
-               }
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (fp->f_flags & O_NONBLOCK) {
-                       finish_wait(&speakup_event, &wait);
-                       return -EAGAIN;
-               }
-               if (signal_pending(current)) {
-                       finish_wait(&speakup_event, &wait);
-                       return -ERESTARTSYS;
-               }
-               schedule();
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-       }
-       finish_wait(&speakup_event, &wait);
-
-       cp = buf;
-       init = get_initstring();
-
-       /* Keep 3 bytes available for a 16bit UTF-8-encoded character */
-       while (chars_sent <= count - bytes_per_ch) {
-               if (synth_current() != &synth_soft)
-                       break;
-               if (speakup_info.flushing) {
-                       speakup_info.flushing = 0;
-                       ch = '\x18';
-               } else if (init[init_pos]) {
-                       ch = init[init_pos++];
-               } else {
-                       if (!unicode)
-                               synth_buffer_skip_nonlatin1();
-                       if (synth_buffer_empty())
-                               break;
-                       ch = synth_buffer_getc();
-               }
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-
-               if ((!unicode && ch < 0x100) || (unicode && ch < 0x80)) {
-                       u_char c = ch;
-
-                       if (copy_to_user(cp, &c, 1))
-                               return -EFAULT;
-
-                       chars_sent++;
-                       cp++;
-               } else if (unicode && ch < 0x800) {
-                       u_char s[2] = {
-                               0xc0 | (ch >> 6),
-                               0x80 | (ch & 0x3f)
-                       };
-
-                       if (copy_to_user(cp, s, sizeof(s)))
-                               return -EFAULT;
-
-                       chars_sent += sizeof(s);
-                       cp += sizeof(s);
-               } else if (unicode) {
-                       u_char s[3] = {
-                               0xe0 | (ch >> 12),
-                               0x80 | ((ch >> 6) & 0x3f),
-                               0x80 | (ch & 0x3f)
-                       };
-
-                       if (copy_to_user(cp, s, sizeof(s)))
-                               return -EFAULT;
-
-                       chars_sent += sizeof(s);
-                       cp += sizeof(s);
-               }
-
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-       }
-       *pos += chars_sent;
-       empty = synth_buffer_empty();
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       if (empty) {
-               speakup_start_ttys();
-               *pos = 0;
-       }
-       return chars_sent;
-}
-
-static ssize_t softsynth_read(struct file *fp, char __user *buf, size_t count,
-                             loff_t *pos)
-{
-       return softsynthx_read(fp, buf, count, pos, 0);
-}
-
-static ssize_t softsynthu_read(struct file *fp, char __user *buf, size_t count,
-                              loff_t *pos)
-{
-       return softsynthx_read(fp, buf, count, pos, 1);
-}
-
-static int last_index;
-
-static ssize_t softsynth_write(struct file *fp, const char __user *buf,
-                              size_t count, loff_t *pos)
-{
-       unsigned long supplied_index = 0;
-       int converted;
-
-       converted = kstrtoul_from_user(buf, count, 0, &supplied_index);
-
-       if (converted < 0)
-               return converted;
-
-       last_index = supplied_index;
-       return count;
-}
-
-static __poll_t softsynth_poll(struct file *fp, struct poll_table_struct *wait)
-{
-       unsigned long flags;
-       __poll_t ret = 0;
-
-       poll_wait(fp, &speakup_event, wait);
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       if (synth_current() == &synth_soft &&
-           (!synth_buffer_empty() || speakup_info.flushing))
-               ret = EPOLLIN | EPOLLRDNORM;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       return ret;
-}
-
-static unsigned char get_index(struct spk_synth *synth)
-{
-       int rv;
-
-       rv = last_index;
-       last_index = 0;
-       return rv;
-}
-
-static const struct file_operations softsynth_fops = {
-       .owner = THIS_MODULE,
-       .poll = softsynth_poll,
-       .read = softsynth_read,
-       .write = softsynth_write,
-       .open = softsynth_open,
-       .release = softsynth_close,
-};
-
-static const struct file_operations softsynthu_fops = {
-       .owner = THIS_MODULE,
-       .poll = softsynth_poll,
-       .read = softsynthu_read,
-       .write = softsynth_write,
-       .open = softsynth_open,
-       .release = softsynth_close,
-};
-
-static int softsynth_probe(struct spk_synth *synth)
-{
-       if (misc_registered != 0)
-               return 0;
-       memset(&synth_device, 0, sizeof(synth_device));
-       synth_device.minor = MISC_DYNAMIC_MINOR;
-       synth_device.name = "softsynth";
-       synth_device.fops = &softsynth_fops;
-       if (misc_register(&synth_device)) {
-               pr_warn("Couldn't initialize miscdevice /dev/softsynth.\n");
-               return -ENODEV;
-       }
-
-       memset(&synthu_device, 0, sizeof(synthu_device));
-       synthu_device.minor = MISC_DYNAMIC_MINOR;
-       synthu_device.name = "softsynthu";
-       synthu_device.fops = &softsynthu_fops;
-       if (misc_register(&synthu_device)) {
-               pr_warn("Couldn't initialize miscdevice /dev/softsynthu.\n");
-               return -ENODEV;
-       }
-
-       misc_registered = 1;
-       pr_info("initialized device: /dev/softsynth, node (MAJOR 10, MINOR %d)\n",
-               synth_device.minor);
-       pr_info("initialized device: /dev/softsynthu, node (MAJOR 10, MINOR %d)\n",
-               synthu_device.minor);
-       return 0;
-}
-
-static void softsynth_release(void)
-{
-       misc_deregister(&synth_device);
-       misc_deregister(&synthu_device);
-       misc_registered = 0;
-       pr_info("unregistered /dev/softsynth\n");
-       pr_info("unregistered /dev/softsynthu\n");
-}
-
-static int softsynth_is_alive(struct spk_synth *synth)
-{
-       if (synth_soft.alive)
-               return 1;
-       return 0;
-}
-
-module_param_named(start, synth_soft.startup, short, 0444);
-
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_soft);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_DESCRIPTION("Speakup userspace software synthesizer support");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/staging/speakup/speakup_spkout.c b/drivers/staging/speakup/speakup_spkout.c
deleted file mode 100644 (file)
index 6e933bf..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * specificly written as a driver for the speakup screenreview
- * s not a general device driver.
- */
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define DRV_VERSION "2.11"
-#define SYNTH_CLEAR 0x18
-#define PROCSPEECH '\r'
-
-static void synth_flush(struct spk_synth *synth);
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x05P+" } },
-       { CAPS_STOP, .u.s = {"\x05P-" } },
-       { RATE, .u.n = {"\x05R%d", 7, 0, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x05P%d", 3, 0, 9, 0, 0, NULL } },
-       { VOL, .u.n = {"\x05V%d", 9, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\x05T%c", 8, 0, 25, 65, 0, NULL } },
-       { PUNCT, .u.n = {"\x05M%c", 0, 0, 3, 0, 0, "nsma" } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/* These attributes will appear in /sys/accessibility/speakup/spkout. */
-
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute punct_attribute =
-       __ATTR(punct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute tone_attribute =
-       __ATTR(tone, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &punct_attribute.attr,
-       &rate_attribute.attr,
-       &tone_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_spkout = {
-       .name = "spkout",
-       .version = DRV_VERSION,
-       .long_name = "Speakout",
-       .init = "\005W1\005I2\005C3",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 40000,
-       .dev_name = SYNTH_DEFAULT_DEV,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_ttyio_ops,
-       .probe = spk_ttyio_synth_probe,
-       .release = spk_ttyio_release,
-       .synth_immediate = spk_ttyio_synth_immediate,
-       .catch_up = spk_do_catch_up,
-       .flush = synth_flush,
-       .is_alive = spk_synth_is_alive_restart,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = spk_synth_get_index,
-       .indexing = {
-               .command = "\x05[%c",
-               .lowindex = 1,
-               .highindex = 5,
-               .currindex = 1,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "spkout",
-       },
-};
-
-static void synth_flush(struct spk_synth *synth)
-{
-       synth->io_ops->flush_buffer();
-       synth->io_ops->send_xchar(SYNTH_CLEAR);
-}
-
-module_param_named(ser, synth_spkout.ser, int, 0444);
-module_param_named(dev, synth_spkout.dev_name, charp, 0444);
-module_param_named(start, synth_spkout.startup, short, 0444);
-
-MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
-MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_spkout);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for Speak Out synthesizers");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakup_txprt.c b/drivers/staging/speakup/speakup_txprt.c
deleted file mode 100644 (file)
index a7326f2..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
- * this version considerably modified by David Borowski, david575@rogers.com
- *
- * Copyright (C) 1998-99  Kirk Reiser.
- * Copyright (C) 2003 David Borowski.
- *
- * specificly written as a driver for the speakup screenreview
- * s not a general device driver.
- */
-#include "spk_priv.h"
-#include "speakup.h"
-
-#define DRV_VERSION "2.11"
-#define SYNTH_CLEAR 0x18
-#define PROCSPEECH '\r' /* process speech char */
-
-static struct var_t vars[] = {
-       { CAPS_START, .u.s = {"\x05P8" } },
-       { CAPS_STOP, .u.s = {"\x05P5" } },
-       { RATE, .u.n = {"\x05R%d", 5, 0, 9, 0, 0, NULL } },
-       { PITCH, .u.n = {"\x05P%d", 5, 0, 9, 0, 0, NULL } },
-       { VOL, .u.n = {"\x05V%d", 5, 0, 9, 0, 0, NULL } },
-       { TONE, .u.n = {"\x05T%c", 12, 0, 25, 61, 0, NULL } },
-       { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL } },
-       V_LAST_VAR
-        };
-
-/* These attributes will appear in /sys/accessibility/speakup/txprt. */
-
-static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute rate_attribute =
-       __ATTR(rate, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute tone_attribute =
-       __ATTR(tone, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute vol_attribute =
-       __ATTR(vol, 0644, spk_var_show, spk_var_store);
-
-static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute direct_attribute =
-       __ATTR(direct, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
-static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
-
-/*
- * Create a group of attributes so that we can create and destroy them all
- * at once.
- */
-static struct attribute *synth_attrs[] = {
-       &caps_start_attribute.attr,
-       &caps_stop_attribute.attr,
-       &pitch_attribute.attr,
-       &rate_attribute.attr,
-       &tone_attribute.attr,
-       &vol_attribute.attr,
-       &delay_time_attribute.attr,
-       &direct_attribute.attr,
-       &full_time_attribute.attr,
-       &jiffy_delta_attribute.attr,
-       &trigger_time_attribute.attr,
-       NULL,   /* need to NULL terminate the list of attributes */
-};
-
-static struct spk_synth synth_txprt = {
-       .name = "txprt",
-       .version = DRV_VERSION,
-       .long_name = "Transport",
-       .init = "\x05N1",
-       .procspeech = PROCSPEECH,
-       .clear = SYNTH_CLEAR,
-       .delay = 500,
-       .trigger = 50,
-       .jiffies = 50,
-       .full = 40000,
-       .dev_name = SYNTH_DEFAULT_DEV,
-       .startup = SYNTH_START,
-       .checkval = SYNTH_CHECK,
-       .vars = vars,
-       .io_ops = &spk_ttyio_ops,
-       .probe = spk_ttyio_synth_probe,
-       .release = spk_ttyio_release,
-       .synth_immediate = spk_ttyio_synth_immediate,
-       .catch_up = spk_do_catch_up,
-       .flush = spk_synth_flush,
-       .is_alive = spk_synth_is_alive_restart,
-       .synth_adjust = NULL,
-       .read_buff_add = NULL,
-       .get_index = NULL,
-       .indexing = {
-               .command = NULL,
-               .lowindex = 0,
-               .highindex = 0,
-               .currindex = 0,
-       },
-       .attributes = {
-               .attrs = synth_attrs,
-               .name = "txprt",
-       },
-};
-
-module_param_named(ser, synth_txprt.ser, int, 0444);
-module_param_named(dev, synth_txprt.dev_name, charp, 0444);
-module_param_named(start, synth_txprt.startup, short, 0444);
-
-MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
-MODULE_PARM_DESC(dev, "Set the device e.g. ttyUSB0, for the synthesizer.");
-MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
-
-module_spk_synth(synth_txprt);
-
-MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
-MODULE_AUTHOR("David Borowski");
-MODULE_DESCRIPTION("Speakup support for Transport synthesizers");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
diff --git a/drivers/staging/speakup/speakupmap.h b/drivers/staging/speakup/speakupmap.h
deleted file mode 100644 (file)
index c60d733..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-       119, 62, 6,
-       0, 16, 20, 17, 32, 48, 0,
-       2, 0, 78, 0, 0, 0, 0,
-       3, 0, 79, 0, 0, 0, 0,
-       4, 0, 76, 0, 0, 0, 0,
-       5, 0, 77, 0, 0, 0, 0,
-       6, 0, 74, 0, 0, 0, 0,
-       7, 0, 75, 0, 0, 0, 0,
-       9, 0, 5, 46, 0, 0, 0,
-       10, 0, 4, 0, 0, 0, 0,
-       11, 0, 0, 1, 0, 0, 0,
-       12, 0, 27, 0, 33, 0, 0,
-       19, 0, 47, 0, 0, 0, 0,
-       21, 0, 29, 17, 0, 0, 0,
-       22, 0, 15, 0, 0, 0, 0,
-       23, 0, 14, 0, 0, 0, 28,
-       24, 0, 16, 0, 0, 0, 0,
-       25, 0, 30, 18, 0, 0, 0,
-       28, 0, 3, 26, 0, 0, 0,
-       35, 0, 31, 0, 0, 0, 0,
-       36, 0, 12, 0, 0, 0, 0,
-       37, 0, 11, 0, 0, 0, 22,
-       38, 0, 13, 0, 0, 0, 0,
-       39, 0, 32, 7, 0, 0, 0,
-       40, 0, 23, 0, 0, 0, 0,
-       44, 0, 44, 0, 0, 0, 0,
-       49, 0, 24, 0, 0, 0, 0,
-       50, 0, 9, 19, 6, 0, 0,
-       51, 0, 8, 0, 0, 0, 36,
-       52, 0, 10, 20, 0, 0, 0,
-       53, 0, 25, 0, 0, 0, 0,
-       55, 46, 1, 0, 0, 0, 0,
-       58, 128, 128, 0, 0, 0, 0,
-       59, 0, 45, 0, 0, 0, 0,
-       60, 0, 40, 0, 0, 0, 0,
-       61, 0, 41, 0, 0, 0, 0,
-       62, 0, 42, 0, 0, 0, 0,
-       63, 0, 34, 0, 0, 0, 0,
-       64, 0, 35, 0, 0, 0, 0,
-       65, 0, 37, 0, 0, 0, 0,
-       66, 0, 38, 0, 0, 0, 0,
-       67, 0, 66, 0, 39, 0, 0,
-       68, 0, 67, 0, 0, 0, 0,
-       71, 15, 19, 0, 0, 0, 0,
-       72, 14, 29, 0, 0, 28, 0,
-       73, 16, 17, 0, 0, 0, 0,
-       74, 27, 33, 0, 0, 0, 0,
-       75, 12, 31, 0, 0, 0, 0,
-       76, 11, 21, 0, 0, 22, 0,
-       77, 13, 32, 0, 0, 0, 0,
-       78, 23, 43, 0, 0, 0, 0,
-       79, 9, 20, 0, 0, 0, 0,
-       80, 8, 30, 0, 0, 36, 0,
-       81, 10, 18, 0, 0, 0, 0,
-       82, 128, 128, 0, 0, 0, 0,
-       83, 24, 25, 0, 0, 0, 0,
-       87, 0, 68, 0, 0, 0, 0,
-       88, 0, 69, 0, 0, 0, 0,
-       96, 3, 26, 0, 0, 0, 0,
-       98, 4, 5, 0, 0, 0, 0,
-       99, 2, 0, 0, 0, 0, 0,
-       104, 0, 6, 0, 0, 0, 0,
-       109, 0, 7, 0, 0, 0, 0,
-       125, 128, 128, 0, 0, 0, 0,
-       0, 119
diff --git a/drivers/staging/speakup/speakupmap.map b/drivers/staging/speakup/speakupmap.map
deleted file mode 100644 (file)
index f10d44c..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-spk key_f9 = punc_level_dec
-spk key_f10 = punc_level_inc
-spk key_f11 = reading_punc_dec
-spk key_f12 = reading_punc_inc
-spk key_1 = vol_dec
-spk key_2 = vol_inc
-spk key_3 = pitch_dec
-spk key_4 = pitch_inc
-spk key_5 = rate_dec
-spk key_6 = rate_inc
-key_kpasterisk = toggle_cursoring
-ctrl spk key_8 = toggle_cursoring
-spk key_kpasterisk = speakup_goto
-spk key_f1 = speakup_help
-spk key_f2 = set_win
-spk key_f3 = clear_win
-spk key_f4 = enable_win
-spk key_f5 = edit_some
-spk key_f6 = edit_most
-spk key_f7 = edit_delim
-spk key_f8 = edit_repeat
-shift spk key_f9 = edit_exnum
- key_kp7 = say_prev_line
-spk key_kp7 = left_edge
- key_kp8 = say_line
-double key_kp8 = say_line_indent
-spk key_kp8 = say_from_top
- key_kp9 = say_next_line
-spk key_kp9 = top_edge
- key_kpminus = speakup_parked
-spk key_kpminus = say_char_num
- key_kp4 = say_prev_word
-spk key_kp4 = say_from_left
- key_kp5 = say_word
-double key_kp5 = spell_word
-spk key_kp5 = spell_phonetic
- key_kp6 = say_next_word
-spk key_kp6 = say_to_right
- key_kpplus = say_screen
-spk key_kpplus = say_win
- key_kp1 = say_prev_char
-spk key_kp1 = right_edge
- key_kp2 = say_char
-spk key_kp2 = say_to_bottom
-double key_kp2 = say_phonetic_char
- key_kp3 = say_next_char
-spk key_kp3 = bottom_edge
- key_kp0 = spk_key
- key_kpdot = say_position
-spk key_kpdot = say_attributes
-key_kpenter = speakup_quiet
-spk key_kpenter = speakup_off
-key_sysrq = speech_kill
- key_kpslash = speakup_cut
-spk key_kpslash = speakup_paste
-spk key_pageup = say_first_char
-spk key_pagedown = say_last_char
-key_capslock = spk_key
- spk key_z = spk_lock
-key_leftmeta = spk_key
-ctrl spk key_0 = speakup_goto
-spk key_u = say_prev_line
-spk key_i = say_line
-double spk key_i = say_line_indent
-spk key_o = say_next_line
-spk key_minus = speakup_parked
-shift spk key_minus = say_char_num
-spk key_j = say_prev_word
-spk key_k = say_word
-double spk key_k = spell_word
-spk key_l = say_next_word
-spk key_m = say_prev_char
-spk key_comma = say_char
-double spk key_comma = say_phonetic_char
-spk key_dot = say_next_char
-spk key_n = say_position
- ctrl spk key_m = left_edge
- ctrl spk key_y = top_edge
- ctrl spk key_dot = right_edge
-ctrl spk key_p = bottom_edge
-spk key_apostrophe = say_screen
-spk key_h = say_from_left
-spk key_y = say_from_top
-spk key_semicolon = say_to_right
-spk key_p = say_to_bottom
-spk key_slash = say_attributes
- spk key_enter = speakup_quiet
- ctrl spk key_enter = speakup_off
- spk key_9 = speakup_cut
-spk key_8 = speakup_paste
-shift spk key_m = say_first_char
- ctrl spk key_semicolon = say_last_char
-spk key_r = read_all_doc
diff --git a/drivers/staging/speakup/spk_priv.h b/drivers/staging/speakup/spk_priv.h
deleted file mode 100644 (file)
index c75b408..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/* spk_priv.h
- * review functions for the speakup screen review package.
- * originally written by: Kirk Reiser and Andy Berdan.
- *
- * extensively modified by David Borowski.
- *
- * Copyright (C) 1998  Kirk Reiser.
- * Copyright (C) 2003  David Borowski.
- */
-#ifndef _SPEAKUP_PRIVATE_H
-#define _SPEAKUP_PRIVATE_H
-
-#include <linux/printk.h>
-
-#include "spk_types.h"
-#include "spk_priv_keyinfo.h"
-
-#define V_LAST_VAR { MAXVARS }
-#define SPACE 0x20
-#define SYNTH_CHECK 20030716 /* today's date ought to do for check value */
-/* synth flags, for odd synths */
-#define SF_DEC 1 /* to fiddle puncs in alpha strings so it doesn't spell */
-#ifdef MODULE
-#define SYNTH_START 1
-#else
-#define SYNTH_START 0
-#endif
-
-#define KT_SPKUP 15
-#define SPK_SYNTH_TIMEOUT 100000 /* in micro-seconds */
-#define SYNTH_DEFAULT_DEV "ttyS0"
-#define SYNTH_DEFAULT_SER 0
-
-const struct old_serial_port *spk_serial_init(int index);
-void spk_stop_serial_interrupt(void);
-int spk_wait_for_xmitr(struct spk_synth *in_synth);
-void spk_serial_release(void);
-void spk_ttyio_release(void);
-void spk_ttyio_register_ldisc(void);
-void spk_ttyio_unregister_ldisc(void);
-
-void synth_buffer_skip_nonlatin1(void);
-u16 synth_buffer_getc(void);
-u16 synth_buffer_peek(void);
-int synth_buffer_empty(void);
-struct var_t *spk_get_var(enum var_id_t var_id);
-ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
-                    char *buf);
-ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
-                     const char *buf, size_t count);
-
-int spk_serial_synth_probe(struct spk_synth *synth);
-int spk_ttyio_synth_probe(struct spk_synth *synth);
-const char *spk_serial_synth_immediate(struct spk_synth *synth,
-                                      const char *buff);
-const char *spk_ttyio_synth_immediate(struct spk_synth *synth,
-                                     const char *buff);
-void spk_do_catch_up(struct spk_synth *synth);
-void spk_do_catch_up_unicode(struct spk_synth *synth);
-void spk_synth_flush(struct spk_synth *synth);
-unsigned char spk_synth_get_index(struct spk_synth *synth);
-int spk_synth_is_alive_nop(struct spk_synth *synth);
-int spk_synth_is_alive_restart(struct spk_synth *synth);
-__printf(1, 2)
-void synth_printf(const char *buf, ...);
-void synth_putwc(u16 wc);
-void synth_putwc_s(u16 wc);
-void synth_putws(const u16 *buf);
-void synth_putws_s(const u16 *buf);
-int synth_request_region(unsigned long start, unsigned long n);
-int synth_release_region(unsigned long start, unsigned long n);
-int synth_add(struct spk_synth *in_synth);
-void synth_remove(struct spk_synth *in_synth);
-struct spk_synth *synth_current(void);
-
-extern struct speakup_info_t speakup_info;
-
-extern struct var_t synth_time_vars[];
-
-extern struct spk_io_ops spk_serial_io_ops;
-extern struct spk_io_ops spk_ttyio_ops;
-
-#endif
diff --git a/drivers/staging/speakup/spk_priv_keyinfo.h b/drivers/staging/speakup/spk_priv_keyinfo.h
deleted file mode 100644 (file)
index 1f789bd..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/* spk_priv.h
- * review functions for the speakup screen review package.
- * originally written by: Kirk Reiser and Andy Berdan.
- *
- * extensively modified by David Borowski.
- *
- * Copyright (C) 1998  Kirk Reiser.
- * Copyright (C) 2003  David Borowski.
- */
-
-#ifndef _SPEAKUP_KEYINFO_H
-#define _SPEAKUP_KEYINFO_H
-
-#define FIRST_SYNTH_VAR RATE
-/* 0 is reserved for no remap */
-#define SPEAKUP_GOTO           0x01
-#define SPEECH_KILL            0x02
-#define SPEAKUP_QUIET          0x03
-#define SPEAKUP_CUT            0x04
-#define SPEAKUP_PASTE          0x05
-#define SAY_FIRST_CHAR         0x06
-#define SAY_LAST_CHAR          0x07
-#define SAY_CHAR               0x08
-#define SAY_PREV_CHAR          0x09
-#define SAY_NEXT_CHAR          0x0a
-#define SAY_WORD               0x0b
-#define SAY_PREV_WORD          0x0c
-#define SAY_NEXT_WORD          0x0d
-#define SAY_LINE               0x0e
-#define SAY_PREV_LINE          0x0f
-#define SAY_NEXT_LINE          0x10
-#define TOP_EDGE               0x11
-#define BOTTOM_EDGE            0x12
-#define LEFT_EDGE              0x13
-#define RIGHT_EDGE             0x14
-#define SPELL_PHONETIC         0x15
-#define SPELL_WORD             0x16
-#define SAY_SCREEN             0x17
-#define SAY_POSITION           0x18
-#define SAY_ATTRIBUTES         0x19
-#define SPEAKUP_OFF            0x1a
-#define SPEAKUP_PARKED         0x1b
-#define SAY_LINE_INDENT        0x1c
-#define SAY_FROM_TOP           0x1d
-#define SAY_TO_BOTTOM          0x1e
-#define SAY_FROM_LEFT          0x1f
-#define SAY_TO_RIGHT           0x20
-#define SAY_CHAR_NUM           0x21
-#define EDIT_SOME              0x22
-#define EDIT_MOST              0x23
-#define SAY_PHONETIC_CHAR      0x24
-#define EDIT_DELIM             0x25
-#define EDIT_REPEAT            0x26
-#define EDIT_EXNUM             0x27
-#define SET_WIN                0x28
-#define CLEAR_WIN              0x29
-#define ENABLE_WIN             0x2a
-#define SAY_WIN                0x2b
-#define SPK_LOCK               0x2c
-#define SPEAKUP_HELP           0x2d
-#define TOGGLE_CURSORING       0x2e
-#define READ_ALL_DOC           0x2f
-
-/* one greater than the last func handler */
-#define SPKUP_MAX_FUNC         0x30
-
-#define SPK_KEY                0x80
-#define FIRST_EDIT_BITS        0x22
-#define FIRST_SET_VAR SPELL_DELAY
-
-/* increase if adding more than 0x3f functions */
-#define VAR_START              0x40
-
-/* keys for setting variables, must be ordered same as the enum for var_ids */
-/* with dec being even and inc being 1 greater */
-#define SPELL_DELAY_DEC (VAR_START + 0)
-#define SPELL_DELAY_INC (SPELL_DELAY_DEC + 1)
-#define PUNC_LEVEL_DEC (SPELL_DELAY_DEC + 2)
-#define PUNC_LEVEL_INC (PUNC_LEVEL_DEC + 1)
-#define READING_PUNC_DEC (PUNC_LEVEL_DEC + 2)
-#define READING_PUNC_INC (READING_PUNC_DEC + 1)
-#define ATTRIB_BLEEP_DEC (READING_PUNC_DEC + 2)
-#define ATTRIB_BLEEP_INC (ATTRIB_BLEEP_DEC + 1)
-#define BLEEPS_DEC (ATTRIB_BLEEP_DEC + 2)
-#define BLEEPS_INC (BLEEPS_DEC + 1)
-#define RATE_DEC (BLEEPS_DEC + 2)
-#define RATE_INC (RATE_DEC + 1)
-#define PITCH_DEC (RATE_DEC + 2)
-#define PITCH_INC (PITCH_DEC + 1)
-#define VOL_DEC (PITCH_DEC + 2)
-#define VOL_INC (VOL_DEC + 1)
-#define TONE_DEC (VOL_DEC + 2)
-#define TONE_INC (TONE_DEC + 1)
-#define PUNCT_DEC (TONE_DEC + 2)
-#define PUNCT_INC (PUNCT_DEC + 1)
-#define VOICE_DEC (PUNCT_DEC + 2)
-#define VOICE_INC (VOICE_DEC + 1)
-
-#endif
diff --git a/drivers/staging/speakup/spk_ttyio.c b/drivers/staging/speakup/spk_ttyio.c
deleted file mode 100644 (file)
index 9b95f77..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/types.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/slab.h>
-
-#include "speakup.h"
-#include "spk_types.h"
-#include "spk_priv.h"
-
-struct spk_ldisc_data {
-       char buf;
-       struct completion completion;
-       bool buf_free;
-};
-
-static struct spk_synth *spk_ttyio_synth;
-static struct tty_struct *speakup_tty;
-/* mutex to protect against speakup_tty disappearing from underneath us while
- * we are using it. this can happen when the device physically unplugged,
- * while in use. it also serialises access to speakup_tty.
- */
-static DEFINE_MUTEX(speakup_tty_mutex);
-
-static int ser_to_dev(int ser, dev_t *dev_no)
-{
-       if (ser < 0 || ser > (255 - 64)) {
-               pr_err("speakup: Invalid ser param. Must be between 0 and 191 inclusive.\n");
-               return -EINVAL;
-       }
-
-       *dev_no = MKDEV(4, (64 + ser));
-       return 0;
-}
-
-static int get_dev_to_use(struct spk_synth *synth, dev_t *dev_no)
-{
-       /* use ser only when dev is not specified */
-       if (strcmp(synth->dev_name, SYNTH_DEFAULT_DEV) ||
-           synth->ser == SYNTH_DEFAULT_SER)
-               return tty_dev_name_to_number(synth->dev_name, dev_no);
-
-       return ser_to_dev(synth->ser, dev_no);
-}
-
-static int spk_ttyio_ldisc_open(struct tty_struct *tty)
-{
-       struct spk_ldisc_data *ldisc_data;
-
-       if (!tty->ops->write)
-               return -EOPNOTSUPP;
-       speakup_tty = tty;
-
-       ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL);
-       if (!ldisc_data)
-               return -ENOMEM;
-
-       init_completion(&ldisc_data->completion);
-       ldisc_data->buf_free = true;
-       speakup_tty->disc_data = ldisc_data;
-
-       return 0;
-}
-
-static void spk_ttyio_ldisc_close(struct tty_struct *tty)
-{
-       mutex_lock(&speakup_tty_mutex);
-       kfree(speakup_tty->disc_data);
-       speakup_tty = NULL;
-       mutex_unlock(&speakup_tty_mutex);
-}
-
-static int spk_ttyio_receive_buf2(struct tty_struct *tty,
-                                 const unsigned char *cp, char *fp, int count)
-{
-       struct spk_ldisc_data *ldisc_data = tty->disc_data;
-
-       if (spk_ttyio_synth->read_buff_add) {
-               int i;
-
-               for (i = 0; i < count; i++)
-                       spk_ttyio_synth->read_buff_add(cp[i]);
-
-               return count;
-       }
-
-       if (!ldisc_data->buf_free)
-               /* ttyio_in will tty_schedule_flip */
-               return 0;
-
-       /* Make sure the consumer has read buf before we have seen
-        * buf_free == true and overwrite buf
-        */
-       mb();
-
-       ldisc_data->buf = cp[0];
-       ldisc_data->buf_free = false;
-       complete(&ldisc_data->completion);
-
-       return 1;
-}
-
-static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
-       .owner          = THIS_MODULE,
-       .magic          = TTY_LDISC_MAGIC,
-       .name           = "speakup_ldisc",
-       .open           = spk_ttyio_ldisc_open,
-       .close          = spk_ttyio_ldisc_close,
-       .receive_buf2   = spk_ttyio_receive_buf2,
-};
-
-static int spk_ttyio_out(struct spk_synth *in_synth, const char ch);
-static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch);
-static void spk_ttyio_send_xchar(char ch);
-static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear);
-static unsigned char spk_ttyio_in(void);
-static unsigned char spk_ttyio_in_nowait(void);
-static void spk_ttyio_flush_buffer(void);
-
-struct spk_io_ops spk_ttyio_ops = {
-       .synth_out = spk_ttyio_out,
-       .synth_out_unicode = spk_ttyio_out_unicode,
-       .send_xchar = spk_ttyio_send_xchar,
-       .tiocmset = spk_ttyio_tiocmset,
-       .synth_in = spk_ttyio_in,
-       .synth_in_nowait = spk_ttyio_in_nowait,
-       .flush_buffer = spk_ttyio_flush_buffer,
-};
-EXPORT_SYMBOL_GPL(spk_ttyio_ops);
-
-static inline void get_termios(struct tty_struct *tty,
-                              struct ktermios *out_termios)
-{
-       down_read(&tty->termios_rwsem);
-       *out_termios = tty->termios;
-       up_read(&tty->termios_rwsem);
-}
-
-static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
-{
-       int ret = 0;
-       struct tty_struct *tty;
-       struct ktermios tmp_termios;
-       dev_t dev;
-
-       ret = get_dev_to_use(synth, &dev);
-       if (ret)
-               return ret;
-
-       tty = tty_kopen(dev);
-       if (IS_ERR(tty))
-               return PTR_ERR(tty);
-
-       if (tty->ops->open)
-               ret = tty->ops->open(tty, NULL);
-       else
-               ret = -ENODEV;
-
-       if (ret) {
-               tty_unlock(tty);
-               return ret;
-       }
-
-       clear_bit(TTY_HUPPED, &tty->flags);
-       /* ensure hardware flow control is enabled */
-       get_termios(tty, &tmp_termios);
-       if (!(tmp_termios.c_cflag & CRTSCTS)) {
-               tmp_termios.c_cflag |= CRTSCTS;
-               tty_set_termios(tty, &tmp_termios);
-               /*
-                * check c_cflag to see if it's updated as tty_set_termios
-                * may not return error even when no tty bits are
-                * changed by the request.
-                */
-               get_termios(tty, &tmp_termios);
-               if (!(tmp_termios.c_cflag & CRTSCTS))
-                       pr_warn("speakup: Failed to set hardware flow control\n");
-       }
-
-       tty_unlock(tty);
-
-       ret = tty_set_ldisc(tty, N_SPEAKUP);
-       if (ret)
-               pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
-
-       return ret;
-}
-
-void spk_ttyio_register_ldisc(void)
-{
-       if (tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops))
-               pr_warn("speakup: Error registering line discipline. Most synths won't work.\n");
-}
-
-void spk_ttyio_unregister_ldisc(void)
-{
-       if (tty_unregister_ldisc(N_SPEAKUP))
-               pr_warn("speakup: Couldn't unregister ldisc\n");
-}
-
-static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
-{
-       mutex_lock(&speakup_tty_mutex);
-       if (in_synth->alive && speakup_tty && speakup_tty->ops->write) {
-               int ret = speakup_tty->ops->write(speakup_tty, &ch, 1);
-
-               mutex_unlock(&speakup_tty_mutex);
-               if (ret == 0)
-                       /* No room */
-                       return 0;
-               if (ret < 0) {
-                       pr_warn("%s: I/O error, deactivating speakup\n",
-                               in_synth->long_name);
-                       /* No synth any more, so nobody will restart TTYs,
-                        * and we thus need to do it ourselves.  Now that there
-                        * is no synth we can let application flood anyway
-                        */
-                       in_synth->alive = 0;
-                       speakup_start_ttys();
-                       return 0;
-               }
-               return 1;
-       }
-
-       mutex_unlock(&speakup_tty_mutex);
-       return 0;
-}
-
-static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch)
-{
-       int ret;
-
-       if (ch < 0x80) {
-               ret = spk_ttyio_out(in_synth, ch);
-       } else if (ch < 0x800) {
-               ret  = spk_ttyio_out(in_synth, 0xc0 | (ch >> 6));
-               ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
-       } else {
-               ret  = spk_ttyio_out(in_synth, 0xe0 | (ch >> 12));
-               ret &= spk_ttyio_out(in_synth, 0x80 | ((ch >> 6) & 0x3f));
-               ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f));
-       }
-       return ret;
-}
-
-static int check_tty(struct tty_struct *tty)
-{
-       if (!tty) {
-               pr_warn("%s: I/O error, deactivating speakup\n",
-                       spk_ttyio_synth->long_name);
-               /* No synth any more, so nobody will restart TTYs, and we thus
-                * need to do it ourselves.  Now that there is no synth we can
-                * let application flood anyway
-                */
-               spk_ttyio_synth->alive = 0;
-               speakup_start_ttys();
-               return 1;
-       }
-
-       return 0;
-}
-
-static void spk_ttyio_send_xchar(char ch)
-{
-       mutex_lock(&speakup_tty_mutex);
-       if (check_tty(speakup_tty)) {
-               mutex_unlock(&speakup_tty_mutex);
-               return;
-       }
-
-       if (speakup_tty->ops->send_xchar)
-               speakup_tty->ops->send_xchar(speakup_tty, ch);
-       mutex_unlock(&speakup_tty_mutex);
-}
-
-static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear)
-{
-       mutex_lock(&speakup_tty_mutex);
-       if (check_tty(speakup_tty)) {
-               mutex_unlock(&speakup_tty_mutex);
-               return;
-       }
-
-       if (speakup_tty->ops->tiocmset)
-               speakup_tty->ops->tiocmset(speakup_tty, set, clear);
-       mutex_unlock(&speakup_tty_mutex);
-}
-
-static unsigned char ttyio_in(int timeout)
-{
-       struct spk_ldisc_data *ldisc_data = speakup_tty->disc_data;
-       char rv;
-
-       if (wait_for_completion_timeout(&ldisc_data->completion,
-                                       usecs_to_jiffies(timeout)) == 0) {
-               if (timeout)
-                       pr_warn("spk_ttyio: timeout (%d)  while waiting for input\n",
-                               timeout);
-               return 0xff;
-       }
-
-       rv = ldisc_data->buf;
-       /* Make sure we have read buf before we set buf_free to let
-        * the producer overwrite it
-        */
-       mb();
-       ldisc_data->buf_free = true;
-       /* Let TTY push more characters */
-       tty_schedule_flip(speakup_tty->port);
-
-       return rv;
-}
-
-static unsigned char spk_ttyio_in(void)
-{
-       return ttyio_in(SPK_SYNTH_TIMEOUT);
-}
-
-static unsigned char spk_ttyio_in_nowait(void)
-{
-       u8 rv = ttyio_in(0);
-
-       return (rv == 0xff) ? 0 : rv;
-}
-
-static void spk_ttyio_flush_buffer(void)
-{
-       mutex_lock(&speakup_tty_mutex);
-       if (check_tty(speakup_tty)) {
-               mutex_unlock(&speakup_tty_mutex);
-               return;
-       }
-
-       if (speakup_tty->ops->flush_buffer)
-               speakup_tty->ops->flush_buffer(speakup_tty);
-
-       mutex_unlock(&speakup_tty_mutex);
-}
-
-int spk_ttyio_synth_probe(struct spk_synth *synth)
-{
-       int rv = spk_ttyio_initialise_ldisc(synth);
-
-       if (rv)
-               return rv;
-
-       synth->alive = 1;
-       spk_ttyio_synth = synth;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(spk_ttyio_synth_probe);
-
-void spk_ttyio_release(void)
-{
-       if (!speakup_tty)
-               return;
-
-       tty_lock(speakup_tty);
-
-       if (speakup_tty->ops->close)
-               speakup_tty->ops->close(speakup_tty, NULL);
-
-       tty_ldisc_flush(speakup_tty);
-       tty_unlock(speakup_tty);
-       tty_kclose(speakup_tty);
-}
-EXPORT_SYMBOL_GPL(spk_ttyio_release);
-
-const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff)
-{
-       u_char ch;
-
-       while ((ch = *buff)) {
-               if (ch == '\n')
-                       ch = synth->procspeech;
-               if (tty_write_room(speakup_tty) < 1 ||
-                   !synth->io_ops->synth_out(synth, ch))
-                       return buff;
-               buff++;
-       }
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(spk_ttyio_synth_immediate);
diff --git a/drivers/staging/speakup/spk_types.h b/drivers/staging/speakup/spk_types.h
deleted file mode 100644 (file)
index d3272c6..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef SPEAKUP_TYPES_H
-#define SPEAKUP_TYPES_H
-
-/* This file includes all of the typedefs and structs used in speakup. */
-
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/wait.h>                /* for wait_queue */
-#include <linux/init.h>                /* for __init */
-#include <linux/module.h>
-#include <linux/vt_kern.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/io.h>          /* for inb_p, outb_p, inb, outb, etc... */
-#include <linux/device.h>
-
-enum var_type_t {
-       VAR_NUM = 0,
-       VAR_TIME,
-       VAR_STRING,
-       VAR_PROC
-};
-
-enum {
-       E_DEFAULT = 0,
-       E_SET,
-       E_INC,
-       E_DEC,
-       E_NEW_DEFAULT,
-};
-
-enum var_id_t {
-       VERSION = 0, SYNTH, SILENT, SYNTH_DIRECT,
-       KEYMAP, CHARS,
-       PUNC_SOME, PUNC_MOST, PUNC_ALL,
-       DELIM, REPEATS, EXNUMBER,
-       DELAY, TRIGGER, JIFFY, FULL, /* all timers must be together */
-       BLEEP_TIME, CURSOR_TIME, BELL_POS,
-       SAY_CONTROL, SAY_WORD_CTL, NO_INTERRUPT, KEY_ECHO,
-       SPELL_DELAY, PUNC_LEVEL, READING_PUNC,
-       ATTRIB_BLEEP, BLEEPS,
-       RATE, PITCH, INFLECTION, VOL, TONE, PUNCT, VOICE, FREQUENCY, LANG,
-       DIRECT, PAUSE,
-       CAPS_START, CAPS_STOP, CHARTAB,
-       MAXVARS
-};
-
-typedef int (*special_func)(struct vc_data *vc, u_char type, u_char ch,
-               u_short key);
-
-#define COLOR_BUFFER_SIZE 160
-
-struct spk_highlight_color_track {
-       /* Count of each background color */
-       unsigned int bgcount[8];
-       /* Buffer for characters drawn with each background color */
-       u16 highbuf[8][COLOR_BUFFER_SIZE];
-       /* Current index into highbuf */
-       unsigned int highsize[8];
-       /* Reading Position for each color */
-       u_long rpos[8], rx[8], ry[8];
-       /* Real Cursor Y Position */
-       ulong cy;
-};
-
-struct st_spk_t {
-       u_long reading_x, cursor_x;
-       u_long reading_y, cursor_y;
-       u_long reading_pos, cursor_pos;
-       u_long go_x, go_pos;
-       u_long w_top, w_bottom, w_left, w_right;
-       u_char w_start, w_enabled;
-       u_char reading_attr, old_attr;
-       char parked, shut_up;
-       struct spk_highlight_color_track ht;
-       int tty_stopped;
-};
-
-/* now some defines to make these easier to use. */
-#define spk_shut_up (speakup_console[vc->vc_num]->shut_up)
-#define spk_killed (speakup_console[vc->vc_num]->shut_up & 0x40)
-#define spk_x (speakup_console[vc->vc_num]->reading_x)
-#define spk_cx (speakup_console[vc->vc_num]->cursor_x)
-#define spk_y (speakup_console[vc->vc_num]->reading_y)
-#define spk_cy (speakup_console[vc->vc_num]->cursor_y)
-#define spk_pos (speakup_console[vc->vc_num]->reading_pos)
-#define spk_cp (speakup_console[vc->vc_num]->cursor_pos)
-#define goto_pos (speakup_console[vc->vc_num]->go_pos)
-#define goto_x (speakup_console[vc->vc_num]->go_x)
-#define win_top (speakup_console[vc->vc_num]->w_top)
-#define win_bottom (speakup_console[vc->vc_num]->w_bottom)
-#define win_left (speakup_console[vc->vc_num]->w_left)
-#define win_right (speakup_console[vc->vc_num]->w_right)
-#define win_start (speakup_console[vc->vc_num]->w_start)
-#define win_enabled (speakup_console[vc->vc_num]->w_enabled)
-#define spk_attr (speakup_console[vc->vc_num]->reading_attr)
-#define spk_old_attr (speakup_console[vc->vc_num]->old_attr)
-#define spk_parked (speakup_console[vc->vc_num]->parked)
-
-struct st_var_header {
-       char *name;
-       enum var_id_t var_id;
-       enum var_type_t var_type;
-       void *p_val; /* ptr to programs variable to store value */
-       void *data;  /* ptr to the vars data */
-};
-
-struct num_var_t {
-       char *synth_fmt;
-       int default_val;
-       int low;
-       int high;
-       short offset, multiplier; /* for fiddling rates etc. */
-       char *out_str;  /* if synth needs char representation of number */
-       int value;      /* current value */
-};
-
-struct punc_var_t {
-       enum var_id_t var_id;
-       short value;
-};
-
-struct string_var_t {
-       char *default_val;
-};
-
-struct var_t {
-       enum var_id_t var_id;
-       union {
-               struct num_var_t n;
-               struct string_var_t s;
-       } u;
-};
-
-struct st_bits_data { /* punc, repeats, word delim bits */
-       char *name;
-       char *value;
-       short mask;
-};
-
-struct synth_indexing {
-       char *command;
-       unsigned char lowindex;
-       unsigned char highindex;
-       unsigned char currindex;
-};
-
-struct spk_synth;
-
-struct spk_io_ops {
-       int (*synth_out)(struct spk_synth *synth, const char ch);
-       int (*synth_out_unicode)(struct spk_synth *synth, u16 ch);
-       void (*send_xchar)(char ch);
-       void (*tiocmset)(unsigned int set, unsigned int clear);
-       unsigned char (*synth_in)(void);
-       unsigned char (*synth_in_nowait)(void);
-       void (*flush_buffer)(void);
-};
-
-struct spk_synth {
-       struct list_head node;
-
-       const char *name;
-       const char *version;
-       const char *long_name;
-       const char *init;
-       char procspeech;
-       char clear;
-       int delay;
-       int trigger;
-       int jiffies;
-       int full;
-       int ser;
-       char *dev_name;
-       short flags;
-       short startup;
-       const int checkval; /* for validating a proper synth module */
-       struct var_t *vars;
-       int *default_pitch;
-       int *default_vol;
-       struct spk_io_ops *io_ops;
-       int (*probe)(struct spk_synth *synth);
-       void (*release)(void);
-       const char *(*synth_immediate)(struct spk_synth *synth,
-                                      const char *buff);
-       void (*catch_up)(struct spk_synth *synth);
-       void (*flush)(struct spk_synth *synth);
-       int (*is_alive)(struct spk_synth *synth);
-       int (*synth_adjust)(struct st_var_header *var);
-       void (*read_buff_add)(u_char c);
-       unsigned char (*get_index)(struct spk_synth *synth);
-       struct synth_indexing indexing;
-       int alive;
-       struct attribute_group attributes;
-};
-
-/*
- * module_spk_synth() - Helper macro for registering a speakup driver
- * @__spk_synth: spk_synth struct
- * Helper macro for speakup drivers which do not do anything special in module
- * init/exit. This eliminates a lot of boilerplate. Each module may only
- * use this macro once, and calling it replaces module_init() and module_exit()
- */
-#define module_spk_synth(__spk_synth) \
-       module_driver(__spk_synth, synth_add, synth_remove)
-
-struct speakup_info_t {
-       spinlock_t spinlock;
-       int port_tts;
-       int flushing;
-};
-
-struct bleep {
-       short freq;
-       unsigned long jiffies;
-       int active;
-};
-#endif
diff --git a/drivers/staging/speakup/spkguide.txt b/drivers/staging/speakup/spkguide.txt
deleted file mode 100644 (file)
index 3782f6a..0000000
+++ /dev/null
@@ -1,1575 +0,0 @@
-
-The Speakup User's Guide
-For Speakup 3.1.2 and Later
-By Gene Collins
-Updated by others
-Last modified on Mon Sep 27 14:26:31 2010
-Document version 1.3
-
-Copyright (c) 2005  Gene Collins
-Copyright (c) 2008  Samuel Thibault
-Copyright (c) 2009, 2010  the Speakup Team
-
-Permission is granted to copy, distribute and/or modify this document
-under the terms of the GNU Free Documentation License, Version 1.2 or
-any later version published by the Free Software Foundation; with no
-Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
-copy of the license is included in the section entitled "GNU Free
-Documentation License".
-
-Preface
-
-The purpose of this document is to familiarize users with the user
-interface to Speakup, a Linux Screen Reader.  If you need instructions
-for installing or obtaining Speakup, visit the web site at
-http://linux-speakup.org/.  Speakup is a set of patches to the standard
-Linux kernel source tree.  It can be built as a series of modules, or as
-a part of a monolithic kernel.  These details are beyond the scope of
-this manual, but the user may need to be aware of the module
-capabilities, depending on how your system administrator has installed
-Speakup.  If Speakup is built as a part of a monolithic kernel, and the
-user is using a hardware synthesizer, then Speakup will be able to
-provide speech access from the time the kernel is loaded, until the time
-the system is shutdown.  This means that if you have obtained Linux
-installation media for a distribution which includes Speakup as a part
-of its kernel, you will be able, as a blind person, to install Linux
-with speech access unaided by a sighted person.  Again, these details
-are beyond the scope of this manual, but the user should be aware of
-them.  See the web site mentioned above for further details.
-
-1.  Starting Speakup
-
-If your system administrator has installed Speakup to work with your
-specific synthesizer by default, then all you need to do to use Speakup
-is to boot your system, and Speakup should come up talking.  This
-assumes of course  that your synthesizer is a supported hardware
-synthesizer, and that it is either installed in or connected to your
-system, and is if necessary powered on.
-
-It is possible, however, that Speakup may have been compiled into the
-kernel with no default synthesizer.  It is even possible that your
-kernel has been compiled with support for some of the supported
-synthesizers and not others.  If you find that this is the case, and
-your synthesizer is supported but not available, complain to the person
-who compiled and installed your kernel.  Or better yet, go to the web
-site, and learn how to patch Speakup into your own kernel source, and
-build and install your own kernel.
-
-If your kernel has been compiled with Speakup, and has no default
-synthesizer set, or you would like to use a different synthesizer than
-the default one, then you may issue the following command at the boot
-prompt of your boot loader.
-
-linux speakup.synth=ltlk
-
-This command would tell Speakup to look for and use a LiteTalk or
-DoubleTalk LT at boot up.  You may replace the ltlk synthesizer keyword
-with the keyword for whatever synthesizer you wish to use.  The
-speakup.synth parameter will accept the following keywords, provided
-that support for the related synthesizers has been built into the
-kernel.
-
-acntsa -- Accent SA
-acntpc -- Accent PC
-apollo -- Apollo
-audptr -- Audapter
-bns -- Braille 'n Speak
-dectlk -- DecTalk Express (old and new, db9 serial only)
-decext -- DecTalk (old) External
-dtlk -- DoubleTalk PC
-keypc -- Keynote Gold PC
-ltlk -- DoubleTalk LT, LiteTalk, or external Tripletalk (db9 serial only)
-spkout -- Speak Out
-txprt -- Transport
-dummy -- Plain text terminal
-
-Note: Speakup does * NOT * support usb connections!  Speakup also does *
-NOT * support the internal Tripletalk!
-
-Speakup does support two other synthesizers, but because they work in
-conjunction with other software, they must be loaded as modules after
-their related software is loaded, and so are not available at boot up.
-These are as follows:
-
-decpc -- DecTalk PC (not available at boot up)
-soft -- One of several software synthesizers (not available at boot up)
-
-See the sections on loading modules and software synthesizers later in
-this manual for further details.  It should be noted here that the
-speakup.synth boot parameter will have no effect if Speakup has been
-compiled as modules.  In order for Speakup modules to be loaded during
-the boot process, such action must be configured by your system
-administrator.  This will mean that you will hear some, but not all,  of
-the bootup messages.
-
-2.  Basic operation
-
-Once you have booted the system, and if necessary, have supplied the
-proper bootup parameter for your synthesizer, Speakup will begin
-talking as soon as the kernel is loaded.  In fact, it will talk a lot!
-It will speak all the boot up messages that the kernel prints on the
-screen during the boot process.  This is because Speakup is not a
-separate screen reader, but is actually built into the operating
-system.  Since almost all console applications must print text on the
-screen using the kernel, and must get their keyboard input through the
-kernel, they are automatically handled properly by Speakup.  There are a
-few exceptions, but we'll come to those later.
-
-Note:  In this guide I will refer to the numeric keypad as the keypad.
-This is done because the speakupmap.map file referred to later in this
-manual uses the term keypad instead of numeric keypad.  Also I'm lazy
-and would rather only type one word.  So keypad it is.  Got it?  Good.
-
-Most of the Speakup review keys are located on the keypad at the far
-right of the keyboard.  The numlock key should be off, in order for these
-to work.  If you toggle the numlock on, the keypad will produce numbers,
-which is exactly what you want for spreadsheets and such.  For the
-purposes of this guide, you should have the numlock turned off, which is
-its default state at bootup.
-
-You probably won't want to listen to all the bootup messages every time
-you start your system, though it's a good idea to listen to them at
-least once, just so you'll know what kind of information is available to
-you during the boot process.  You can always review these messages after
-bootup with the command:
-
-dmesg | more
-
-In order to speed the boot process, and to silence the speaking of the
-bootup messages, just press the keypad enter key.  This key is located
-in the bottom right corner of the keypad.  Speakup will shut up and stay
-that way, until you press another key.
-
-You can check to see if the boot process has completed by pressing the 8
-key on the keypad, which reads the current line.  This also has the
-effect of starting Speakup talking again, so you can press keypad enter
-to silence it again if the boot process has not completed.
-
-When the boot process is complete, you will arrive at a "login" prompt.
-At this point, you'll need to type in your user id and password, as
-provided by your system administrator.  You will hear Speakup speak the
-letters of your user id as you type it, but not the password.  This is
-because the password is not displayed on the screen for security
-reasons.  This has nothing to do with Speakup, it's a Linux security
-feature.
-
-Once you've logged in, you can run any Linux command or program which is
-allowed by your user id.  Normal users will not be able to run programs
-which require root privileges.
-
-When you are running a program or command, Speakup will automatically
-speak new text as it arrives on the screen.  You can at any time silence
-the speech with keypad enter, or use any of the Speakup review keys.
-
-Here are some basic Speakup review keys, and a short description of what
-they do.
-
-keypad 1 -- read previous character
-keypad 2 -- read current character (pressing keypad 2 twice rapidly will speak
-       the current character phonetically)
-keypad 3 -- read next character
-keypad 4 -- read previous word
-keypad 5 -- read current word (press twice rapidly to spell the current word)
-keypad 6 -- read next word
-keypad 7 -- read previous line
-keypad 8 -- read current line (press twice rapidly to hear how much the
-       text on the current line is indented)
-keypad 9 -- read next line
-keypad period -- speak current cursor position and announce current
-       virtual console
-
-It's also worth noting that the insert key on the keypad is mapped
-as the speakup key.  Instead of pressing and releasing this key, as you
-do under DOS or Windows, you hold it like a shift key, and press other
-keys in combination with it.  For example, repeatedly holding keypad
-insert, from now on called speakup, and keypad enter will toggle the
-speaking of new text on the screen on and off.  This is not the same as
-just pressing keypad enter by itself, which just silences the speech
-until you hit another key.  When you hit speakup plus keypad enter,
-Speakup will say, "You turned me off.", or "Hey, that's better."  When
-Speakup is turned off, no new text on the screen will be spoken.  You
-can still use the reading controls to review the screen however.
-
-3.  Using the Speakup Help System
-
-In order to enter the Speakup help system, press and hold the speakup
-key (remember that this is the keypad insert key), and press the f1 key.
-You will hear the message:
-
-"Press space to leave help, cursor up or down to scroll, or a letter to
-go to commands in list."
-
-When you press the spacebar to leave the help system, you will hear:
-
-"Leaving help."
-
-While you are in the Speakup help system, you can scroll up or down
-through the list of available commands using the cursor keys.  The list
-of commands is arranged in alphabetical order.  If you wish to jump to
-commands in a specific part of the alphabet, you may press the letter of
-the alphabet you wish to jump to.
-
-You can also just explore by typing keyboard keys.  Pressing keys will
-cause Speakup to speak the command associated with that key.  For
-example, if you press the keypad 8 key, you will hear:
-
-"Keypad 8 is line, say current."
-
-You'll notice that some commands do not have keys assigned to them.
-This is because they are very infrequently used commands, and are also
-accessible through the sys system.  We'll discuss the sys system later
-in this manual.
-
-You'll also notice that some commands have two keys assigned to them.
-This is because Speakup has a built in set of alternative key bindings
-for laptop users.  The alternate speakup key is the caps lock key.  You
-can press and hold the caps lock key, while pressing an alternate
-speakup command key to activate the command.  On most laptops, the
-numeric keypad is defined as the keys in the j k l area of the keyboard.
-
-There is usually a function key which turns this keypad function on and
-off, and some other key which controls the numlock state.  Toggling the
-keypad functionality on and off can become a royal pain.  So, Speakup
-gives you a simple way to get at an alternative set of key mappings for
-your laptop.  These are also available by default on desktop systems,
-because Speakup does not know whether it is running on a desktop or
-laptop.  So you may choose which set of Speakup keys to use.  Some
-system administrators may have chosen to compile Speakup for a desktop
-system without this set of alternate key bindings, but these details are
-beyond the scope of this manual.  To use the caps lock for its normal
-purpose, hold the shift key while toggling the caps lock on and off.  We
-should note here, that holding the caps lock key and pressing the z key
-will toggle the alternate j k l keypad on and off.
-
-4.  Keys and Their Assigned Commands
-
-In this section, we'll go through a list of all the speakup keys and
-commands.  You can also get a list of commands and assigned keys from
-the help system.
-
-The following list was taken from the speakupmap.map file.  Key
-assignments are on the left of the equal sign, and the associated
-Speakup commands are on the right.  The designation "spk" means to press
-and hold the speakup key, a.k.a. keypad insert, a.k.a. caps lock, while
-pressing the other specified key.
-
-spk key_f9 = punc_level_dec
-spk key_f10 = punc_level_inc
-spk key_f11 = reading_punc_dec
-spk key_f12 = reading_punc_inc
-spk key_1 = vol_dec
-spk key_2 =  vol_inc
-spk key_3 = pitch_dec
-spk key_4 = pitch_inc
-spk key_5 = rate_dec
-spk key_6 = rate_inc
-key_kpasterisk = toggle_cursoring
-spk key_kpasterisk = speakup_goto
-spk key_f1 = speakup_help
-spk key_f2 = set_win
-spk key_f3 = clear_win
-spk key_f4 = enable_win
-spk key_f5 = edit_some
-spk key_f6 = edit_most
-spk key_f7 = edit_delim
-spk key_f8 = edit_repeat
-shift spk key_f9 = edit_exnum
- key_kp7 = say_prev_line
-spk key_kp7 = left_edge
- key_kp8 = say_line
-double  key_kp8 = say_line_indent
-spk key_kp8 = say_from_top
- key_kp9 = say_next_line
-spk  key_kp9 = top_edge
- key_kpminus = speakup_parked
-spk key_kpminus = say_char_num
- key_kp4 = say_prev_word
-spk key_kp4 = say_from_left
- key_kp5 = say_word
-double key_kp5 = spell_word
-spk key_kp5 = spell_phonetic
- key_kp6 = say_next_word
-spk key_kp6 = say_to_right
- key_kpplus = say_screen
-spk key_kpplus = say_win
- key_kp1 = say_prev_char
-spk key_kp1 = right_edge
- key_kp2 = say_char
-spk key_kp2 = say_to_bottom
-double key_kp2 = say_phonetic_char
- key_kp3 = say_next_char
-spk  key_kp3 = bottom_edge
- key_kp0 = spk_key
- key_kpdot = say_position
-spk key_kpdot = say_attributes
-key_kpenter = speakup_quiet
-spk key_kpenter = speakup_off
-key_sysrq = speech_kill
- key_kpslash = speakup_cut
-spk key_kpslash = speakup_paste
-spk key_pageup = say_first_char
-spk key_pagedown = say_last_char
-key_capslock = spk_key
- spk key_z = spk_lock
-key_leftmeta = spk_key
-ctrl spk key_0 = speakup_goto
-spk key_u = say_prev_line
-spk key_i = say_line
-double spk key_i = say_line_indent
-spk key_o = say_next_line
-spk key_minus = speakup_parked
-shift spk key_minus = say_char_num
-spk key_j = say_prev_word
-spk key_k = say_word
-double spk key_k = spell_word
-spk key_l = say_next_word
-spk key_m = say_prev_char
-spk key_comma = say_char
-double spk key_comma = say_phonetic_char
-spk key_dot = say_next_char
-spk key_n = say_position
- ctrl spk key_m = left_edge
- ctrl spk key_y = top_edge
- ctrl spk key_dot = right_edge
-ctrl spk key_p = bottom_edge
-spk key_apostrophe = say_screen
-spk key_h = say_from_left
-spk key_y = say_from_top
-spk key_semicolon = say_to_right
-spk key_p = say_to_bottom
-spk key_slash = say_attributes
- spk key_enter = speakup_quiet
- ctrl  spk key_enter = speakup_off
- spk key_9 = speakup_cut
-spk key_8 = speakup_paste
-shift spk key_m = say_first_char
- ctrl spk key_semicolon = say_last_char
-
-5.  The Speakup Sys System
-
-The Speakup screen reader also creates a speakup subdirectory as a part
-of the sys system.
-
-As a convenience, run as root
-
-ln -s /sys/accessibility/speakup /speakup
-
-to directly access speakup parameters from /speakup.
-You can see these entries by typing the command:
-
-ls -1 /speakup/*
-
-If you issue the above ls command, you will get back something like
-this:
-
-/speakup/attrib_bleep
-/speakup/bell_pos
-/speakup/bleep_time
-/speakup/bleeps
-/speakup/cursor_time
-/speakup/delimiters
-/speakup/ex_num
-/speakup/key_echo
-/speakup/keymap
-/speakup/no_interrupt
-/speakup/punc_all
-/speakup/punc_level
-/speakup/punc_most
-/speakup/punc_some
-/speakup/reading_punc
-/speakup/repeats
-/speakup/say_control
-/speakup/say_word_ctl
-/speakup/silent
-/speakup/spell_delay
-/speakup/synth
-/speakup/synth_direct
-/speakup/version
-
-/speakup/i18n:
-announcements
-characters
-chartab
-colors
-ctl_keys
-formatted
-function_names
-key_names
-states
-
-/speakup/soft:
-caps_start
-caps_stop
-delay_time
-direct
-freq
-full_time
-jiffy_delta
-pitch
-inflection
-punct
-rate
-tone
-trigger_time
-voice
-vol
-
-Notice the two subdirectories of /speakup: /speakup/i18n and
-/speakup/soft.
-The i18n subdirectory is described in a later section.
-The files under /speakup/soft represent settings that are specific to the
-driver for the software synthesizer.  If you use the LiteTalk, your
-synthesizer-specific settings would be found in /speakup/ltlk.  In other words,
-a subdirectory named /speakup/KWD is created to hold parameters specific
-to the device whose keyword is KWD.
-These parameters include volume, rate, pitch, and others.
-
-In addition to using the Speakup hot keys to change such things as
-volume, pitch, and rate, you can also echo values to the appropriate
-entry in the /speakup directory.  This is very useful, since it
-lets you control Speakup parameters from within a script.  How you
-would write such scripts is somewhat beyond the scope of this manual,
-but I will include a couple of simple examples here to give you a
-general idea of what such scripts can do.
-
-Suppose for example, that you wanted to control both the punctuation
-level and the reading punctuation level at the same time.  For
-simplicity, we'll call them punc0, punc1, punc2, and punc3.  The scripts
-might look something like this:
-
-#!/bin/bash
-# punc0
-# set punc and reading punc levels to 0
-echo 0 >/speakup/punc_level
-echo 0 >/speakup/reading_punc
-echo Punctuation level set to 0.
-
-#!/bin/bash
-# punc1
-# set punc and reading punc levels to 1
-echo 1 >/speakup/punc_level
-echo 1 >/speakup/reading_punc
-echo Punctuation level set to 1.
-
-#!/bin/bash
-# punc2
-# set punc and reading punc levels to 2
-echo 2 >/speakup/punc_level
-echo 2 >/speakup/reading_punc
-echo Punctuation level set to 2.
-
-#!/bin/bash
-# punc3
-# set punc and reading punc levels to 3
-echo 3 >/speakup/punc_level
-echo 3 >/speakup/reading_punc
-echo Punctuation level set to 3.
-
-If you were to store these four small scripts in a directory in your
-path, perhaps /usr/local/bin, and set the permissions to 755 with the
-chmod command, then you could change the default reading punc and
-punctuation levels at the same time by issuing just one command.  For
-example, if you were to execute the punc3 command at your shell prompt,
-then the reading punc and punc level would both get set to 3.
-
-I should note that the above scripts were written to work with bash, but
-regardless of which shell you use, you should be able to do something
-similar.
-
-The Speakup sys system also has another interesting use.  You can echo
-Speakup parameters into the sys system in a script during system
-startup, and speakup will return to your preferred parameters every time
-the system is rebooted.
-
-Most of the Speakup sys parameters can be manipulated by a regular user
-on the system.  However, there are a few parameters that are dangerous
-enough that they should only be manipulated by the root user on your
-system.  There are even some parameters that are read only, and cannot
-be written to at all.  For example, the version entry in the Speakup
-sys system is read only.  This is because there is no reason for a user
-to tamper with the version number which is reported by Speakup.  Doing
-an ls -l on /speakup/version will return this:
-
--r--r--r--    1 root     root            0 Mar 21 13:46 /speakup/version
-
-As you can see, the version entry in the Speakup sys system is read
-only, is owned by root, and belongs to the root group.  Doing a cat of
-/speakup/version will display the Speakup version number, like
-this:
-
-cat /speakup/version
-Speakup v-2.00 CVS: Thu Oct 21 10:38:21 EDT 2004
-synth dtlk version 1.1
-
-The display shows the Speakup version number, along with the version
-number of the driver for the current synthesizer.
-
-Looking at entries in the Speakup sys system can be useful in many
-ways.  For example, you might wish to know what level your volume is set
-at.  You could type:
-
-cat /speakup/KWD/vol
-# Replace KWD with the keyword for your synthesizer, E.G., ltlk for LiteTalk.
-5
-
-The number five which comes back is the level at which the synthesizer
-volume is set at.
-
-All the entries in the Speakup sys system are readable, some are
-writable by root only, and some are writable by everyone.  Unless you
-know what you are doing, you should probably leave the ones that are
-writable by root only alone.  Most of the names are self explanatory.
-Vol for controlling volume, pitch for pitch, inflection for pitch range, rate
-for controlling speaking rate, etc.  If you find one you aren't sure about, you
-can post a query on the Speakup list.
-
-6.  Changing Synthesizers
-
-It is possible to change to a different synthesizer while speakup is
-running.  In other words, it is not necessary to reboot the system
-in order to use a different synthesizer.  You can simply echo the
-synthesizer keyword to the /speakup/synth sys entry.
-Depending on your situation, you may wish to echo none to the synth
-sys entry, to disable speech while one synthesizer is disconnected and
-a second one is connected in its place.  Then echo the keyword for the
-new synthesizer into the synth sys entry in order to start speech
-with the newly connected synthesizer.  See the list of synthesizer
-keywords in section 1 to find the keyword which matches your synth.
-
-7.  Loading modules
-
-As mentioned earlier, Speakup can either be completely compiled into the
-kernel, with the exception of the help module, or it can be compiled as
-a series of modules.   When compiled as modules, Speakup will only be
-able to speak some of the bootup messages if your system administrator
-has configured the system to load the modules at boo time. The modules
-can  be loaded after the file systems have been checked and mounted, or
-from an initrd.  There is a third possibility.  Speakup can be compiled
-with some components built into the kernel, and others as modules.  As
-we'll see in the next section, this is particularly useful when you are
-working with software synthesizers.
-
-If Speakup is completely compiled as modules, then you must use the
-modprobe command to load Speakup.  You do this by loading the module for
-the synthesizer driver you wish to use.  The driver modules are all
-named speakup_<keyword>, where <keyword> is the keyword for the
-synthesizer you want.  So, in order to load the driver for the DecTalk
-Express, you would type the following command:
-
-modprobe speakup_dectlk
-
-Issuing this command would load the DecTalk Express driver and all other
-related Speakup modules necessary to get Speakup up and running.
-
-To completely unload Speakup, again presuming that it is entirely built
-as modules, you would give the command:
-
-modprobe -r speakup_dectlk
-
-The above command assumes you were running a DecTalk Express.  If you
-were using a different synth, then you would substitute its keyword in
-place of dectlk.
-
-If you have multiple drivers loaded, you need to unload all of them, in
-order to completely unload Speakup.
-For example, if you have loaded both the dectlk and ltlk drivers, use the
-command:
-modprobe -r speakup_dectlk speakup_ltlk
-
-You cannot unload the driver for software synthesizers when a user-space
-daemon is using /dev/softsynth.  First, kill the daemon.  Next, remove
-the driver with the command:
-modprobe -r speakup_soft
-
-Now, suppose we have a situation where the main Speakup component
-is built into the kernel, and some or all of the drivers are built as
-modules.  Since the main part of Speakup is compiled into the kernel, a
-partial Speakup sys system has been created which we can take advantage
-of by simply echoing the synthesizer keyword into the
-/speakup/synth sys entry.  This will cause the kernel to
-automatically load the appropriate driver module, and start Speakup
-talking.  To switch to another synth, just echo a new keyword to the
-synth sys entry.  For example, to load the DoubleTalk LT driver,
-you would type:
-
-echo ltlk >/speakup/synth
-
-You can use the modprobe -r command to unload driver modules, regardless
-of whether the main part of Speakup has been built into the kernel or
-not.
-
-8.  Using Software Synthesizers
-
-Using a software synthesizer requires that some other software be
-installed and running on your system.  For this reason, software
-synthesizers are not available for use at bootup, or during a system
-installation process.
-There are two freely-available solutions for software speech: Espeakup and
-Speech Dispatcher.
-These are described in subsections 8.1 and 8.2, respectively.
-
-During the rest of this section, we assume that speakup_soft is either
-built in to your kernel, or loaded as a module.
-
-If your system does not have udev installed , before you can use a
-software synthesizer, you must have created the /dev/softsynth device.
-If you have not already done so, issue the following commands as root:
-
-cd /dev
-mknod softsynth c 10 26
-
-While we are at it, we might just as well create the /dev/synth device,
-which can be used to let user space programs send information to your
-synthesizer.  To create /dev/synth, change to the /dev directory, and
-issue the following command as root:
-
-mknod synth c 10 25
-
-of both.
-
-8.1. Espeakup
-
-Espeakup is a connector between Speakup and the eSpeak software synthesizer.
-Espeakup may already be available as a package for your distribution
-of Linux.  If it is not packaged, you need to install it manually.
-You can find it in the contrib/ subdirectory of the Speakup sources.
-The filename is espeakup-$VERSION.tar.bz2, where $VERSION
-depends on the current release of Espeakup.  The Speakup 3.1.2 source
-ships with version 0.71 of Espeakup.
-The README file included with the Espeakup sources describes the process
-of manual installation.
-
-Assuming that Espeakup is installed, either by the user or by the distributor,
-follow these steps to use it.
-
-Tell Speakup to use the "soft driver:
-echo soft > /speakup/synth
-
-Finally, start the espeakup program.  There are two ways to do it.
-Both require root privileges.
-
-If Espeakup was installed as a package for your Linux distribution,
-you probably have a distribution-specific script that controls the operation
-of the daemon.  Look for a file named espeakup under /etc/init.d or
-/etc/rc.d.  Execute the following command with root privileges:
-/etc/init.d/espeakup start
-Replace init.d with rc.d, if your distribution uses scripts located under
-/etc/rc.d.
-Your distribution will also have a procedure for starting daemons at
-boot-time, so it is possible to have software speech as soon as user-space
-daemons are started by the bootup scripts.
-These procedures are not described in this document.
-
-If you built Espeakup manually, the "make install" step placed the binary
-under /usr/bin.
-Run the following command as root:
-/usr/bin/espeakup
-Espeakup should start speaking.
-
-8.2. Speech Dispatcher
-
-For this option, you must have a package called
-Speech Dispatcher running on your system, and it must be configured to
-work with one of its supported software synthesizers.
-
-Two open source synthesizers you might use are Flite and Festival.  You
-might also choose to purchase the Software DecTalk from Fonix Sales Inc.
-If you run a google search for Fonix, you'll find their web site.
-
-You can obtain a copy of Speech Dispatcher from free(b)soft at
-http://www.freebsoft.org/.  Follow the installation instructions that
-come with Speech Dispatcher in order to install and configure Speech
-Dispatcher.  You can check out the web site for your Linux distribution
-in order to get a copy of either Flite or Festival.  Your Linux
-distribution may also have a precompiled Speech Dispatcher package.
-
-Once you've installed, configured, and tested Speech Dispatcher with your
-chosen software synthesizer, you still need one more piece of software
-in order to make things work.  You need a package called speechd-up.
-You get it from the free(b)soft web site mentioned above.  After you've
-compiled and installed speechd-up, you are almost ready to begin using
-your software synthesizer.
-
-Now you can begin using your software synthesizer.  In order to do so,
-echo the soft keyword to the synth sys entry like this:
-
-echo soft >/speakup/synth
-
-Next run the speechd_up command like this:
-
-speechd_up &
-
-Your synth should now start talking, and you should be able to adjust
-the pitch, rate, etc.
-
-9.  Using The DecTalk PC Card
-
-The DecTalk PC card is an ISA card that is inserted into one of the ISA
-slots in your computer.  It requires that the DecTalk PC software be
-installed on your computer, and that the software be loaded onto the
-Dectalk PC card before it can be used.
-
-You can get the dec_pc.tgz file from the linux-speakup.org site.  The
-dec_pc.tgz file is in the ~ftp/pub/linux/speakup directory.
-
-After you have downloaded the dec_pc.tgz file, untar it in your home
-directory, and read the Readme file in the newly created dec_pc
-directory.
-
-The easiest way to get the software working is to copy the entire dec_pc
-directory into /user/local/lib.  To do this, su to root in your home
-directory, and issue the command:
-
-cp dec_pc /usr/local/lib
-
-You will need to copy the dtload command from the dec_pc directory to a
-directory in your path.  Either /usr/bin or /usr/local/bin is a good
-choice.
-
-You can now run the dtload command in order to load the DecTalk PC
-software onto the card.  After you have done this, echo the decpc
-keyword to the synth entry in the sys system like this:
-
-echo decpc >/speakup/synth
-
-Your DecTalk PC should start talking, and then you can adjust the pitch,
-rate, volume, voice, etc.  The voice entry in the Speakup sys system
-will accept a number from 0 through 7 for the DecTalk PC synthesizer,
-which will give you access to some of the DecTalk voices.
-
-10.  Using Cursor Tracking
-
-In Speakup version 2.0 and later, cursor tracking is turned on by
-default.  This means that when you are using an editor, Speakup will
-automatically speak characters as you move left and right with the
-cursor keys, and lines as you move up and down with the cursor keys.
-This is the traditional sort of cursor tracking.
-Recent versions of Speakup provide two additional ways to control the
-text that is spoken when the cursor is moved:
-"highlight tracking" and "read window."
-They are described later in this section.
-Sometimes, these modes get in your way, so you can disable cursor tracking
-altogether.
-
-You may select among the various forms of cursor tracking using the keypad
-asterisk key.
-Each time you press this key, a new mode is selected, and Speakup speaks
-the name of the new mode.  The names for the four possible states of cursor
-tracking are: "cursoring on", "highlight tracking", "read window",
-and "cursoring off."  The keypad asterisk key moves through the list of
-modes in a circular fashion.
-
-If highlight tracking is enabled, Speakup tracks highlighted text,
-rather than the cursor itself. When you move the cursor with the arrow keys,
-Speakup speaks the currently highlighted information.
-This is useful when moving through various menus and dialog boxes.
-If cursor tracking isn't helping you while navigating a menu,
-try highlight tracking.
-
-With the "read window" variety of cursor tracking, you can limit the text
-that Speakup speaks by specifying a window of interest on the screen.
-See section 15 for a description of the process of defining windows.
-When you move the cursor via the arrow keys, Speakup only speaks
-the contents of the window.  This is especially helpful when you are hearing
-superfluous speech.  Consider the following example.
-
-Suppose that you are at a shell prompt.  You use bash, and you want to
-explore your command history using the up and down arrow keys.  If you
-have enabled cursor tracking, you will hear two pieces of information.
-Speakup speaks both your shell prompt and the current entry from the
-command history.  You may not want to hear the prompt repeated
-each time you move, so you can silence it by specifying a window.  Find
-the last line of text on the screen.  Clear the current window by pressing
-the key combination speakup f3.  Use the review cursor to find the first
-character that follows your shell prompt.  Press speakup + f2 twice, to
-define a one-line window.  The boundaries of the window are the
-character following the shell prompt and the end of the line.  Now, cycle
-through the cursor tracking modes using keypad asterisk, until Speakup
-says "read window."  Move through your history using your arrow keys.
-You will notice that Speakup no longer speaks the redundant prompt.
-
-Some folks like to turn cursor tracking off while they are using the
-lynx web browser.  You definitely want to turn cursor tracking off when
-you are using the alsamixer application.  Otherwise, you won't be able
-to hear your mixer settings while you are using the arrow keys.
-
-11.  Cut and Paste
-
-One of Speakup's more useful features is the ability to cut and paste
-text on the screen.  This means that you can capture information from a
-program, and paste that captured text into a different place in the
-program, or into an entirely different program, which may even be
-running on a different console.
-
-For example, in this manual, we have made references to several web
-sites.  It would be nice if you could cut and paste these urls into your
-web browser.  Speakup does this quite nicely.  Suppose you wanted to
-past the following url into your browser:
-
-http://linux-speakup.org/
-
-Use the speakup review keys to position the reading cursor on the first
-character of the above url.  When the reading cursor is in position,
-press the keypad slash key once.  Speakup will say, "mark".  Next,
-position the reading cursor on the rightmost character of the above
-url. Press the keypad slash key once again to actually cut the text
-from the screen.  Speakup will say, "cut".  Although we call this
-cutting, Speakup does not actually delete the cut text from the screen.
-It makes a copy of the text in a special buffer for later pasting.
-
-Now that you have the url cut from the screen, you can paste it into
-your browser, or even paste the url on a command line as an argument to
-your browser.
-
-Suppose you want to start lynx and go to the Speakup site.
-
-You can switch to a different console with the alt left and right
-arrows, or you can switch to a specific console by typing alt and a
-function key.  These are not Speakup commands, just standard Linux
-console capabilities.
-
-Once you've changed to an appropriate console, and are at a shell prompt,
-type the word lynx, followed by a space.  Now press and hold the speakup
-key, while you type the keypad slash character.  The url will be pasted
-onto the command line, just as though you had typed it in.  Press the
-enter key to execute the command.
-
-The paste buffer will continue to hold the cut information, until a new
-mark and cut operation is carried out.  This means you can paste the cut
-information as many times as you like before doing another cut
-operation.
-
-You are not limited to cutting and pasting only one line on the screen.
-You can also cut and paste rectangular regions of the screen.  Just
-position the reading cursor at the top left corner of the text to be
-cut, mark it with the keypad slash key, then position the reading cursor
-at the bottom right corner of the region to be cut, and cut it with the
-keypad slash key.
-
-12.  Changing the Pronunciation of Characters
-
-Through the /speakup/i18n/characters sys entry, Speakup gives you the
-ability to change how Speakup pronounces a given character.  You could,
-for example, change how some punctuation characters are spoken.  You can
-even change how Speakup will pronounce certain letters.
-
-You may, for example, wish to change how Speakup pronounces the z
-character.  The author of Speakup, Kirk Reiser, is Canadian, and thus
-believes that the z should be pronounced zed.  If you are an American,
-you might wish to use the zee pronunciation instead of zed.  You can
-change the pronunciation of both the upper and lower case z with the
-following two commands:
-
-echo 90 zee >/speakup/characters
-echo 122 zee >/speakup/characters
-
-Let's examine the parts of the two previous commands.  They are issued
-at the shell prompt, and could be placed in a startup script.
-
-The word echo tells the shell that you want to have it display the
-string of characters that follow the word echo.  If you were to just
-type:
-
-echo hello.
-
-You would get the word hello printed on your screen as soon as you
-pressed the enter key.  In this case, we are echoing strings that we
-want to be redirected into the sys system.
-
-The numbers 90 and 122 in the above echo commands are the ascii numeric
-values for the upper and lower case z, the characters we wish to change.
-
-The string zee is the pronunciation that we want Speakup to use for the
-upper and lower case z.
-
-The > symbol redirects the output of the echo command to a file, just
-like in DOS, or at the Windows command prompt.
-
-And finally, /speakup/i18n/characters is the file entry in the sys system
-where we want the output to be directed.  Speakup looks at the numeric
-value of the character we want to change, and inserts the pronunciation
-string into an internal table.
-
-You can look at the whole table with the following command:
-
-cat /speakup/i18n/characters
-
-Speakup will then print out the entire character pronunciation table.  I
-won't display it here, but leave you to look at it at your convenience.
-
-13.  Mapping Keys
-
-Speakup has the capability of allowing you to assign or "map" keys to
-internal Speakup commands.  This section necessarily assumes you have a
-Linux kernel source tree installed, and that it has been patched and
-configured with Speakup.  How you do this is beyond the scope of this
-manual.  For this information, visit the Speakup web site at
-http://linux-speakup.org/.  The reason you'll need the kernel source
-tree patched with Speakup is that the genmap utility you'll need for
-processing keymaps is in the
-/usr/src/linux-<version_number>/drivers/char/speakup directory.  The
-<version_number> in the above directory path is the version number of
-the Linux source tree you are working with.
-
-So ok, you've gone off and gotten your kernel source tree, and patched
-and configured it.  Now you can start manipulating keymaps.
-
-You can either use the
-/usr/src/linux-<version_number>/drivers/char/speakup/speakupmap.map file
-included with the Speakup source, or you can cut and paste the copy in
-section 4 into a separate file.  If you use the one in the Speakup
-source tree, make sure you make a backup of it before you start making
-changes.  You have been warned!
-
-Suppose that you want to swap the key assignments for the Speakup
-say_last_char and the Speakup say_first_char commands.  The
-speakupmap.map lists the key mappings for these two commands as follows:
-
-spk key_pageup = say_first_char
-spk key_pagedown = say_last_char
-
-You can edit your copy of the speakupmap.map file and swap the command
-names on the right side of the = (equals) sign.  You did make a backup,
-right?  The new keymap lines would look like this:
-
-spk key_pageup = say_last_char
-spk key_pagedown = say_first_char
-
-After you edit your copy of the speakupmap.map file, save it under a new
-file name, perhaps newmap.map.  Then exit your editor and return to the
-shell prompt.
-
-You are now ready to load your keymap with your swapped key assignments.
- Assuming that you saved your new keymap as the file newmap.map, you
-would load your keymap into the sys system like this:
-
-/usr/src/linux-<version_number>/drivers/char/speakup/genmap newmap.map
->/speakup/keymap
-
-Remember to substitute your kernel version number for the
-<version_number> in the above command.  Also note that although the
-above command wrapped onto two lines in this document, you should type
-it all on one line.
-
-Your say first and say last characters should now be swapped.  Pressing
-speakup pagedown should read you the first non-whitespace character on
-the line your reading cursor is in, and pressing speakup pageup should
-read you the last character on the line your reading cursor is in.
-
-You should note that these new mappings will only stay in effect until
-you reboot, or until you load another keymap.
-
-One final warning.  If you try to load a partial map, you will quickly
-find that all the mappings you didn't include in your file got deleted
-from the working map.  Be extremely careful, and always make a backup!
-You have been warned!
-
-14.  Internationalizing Speakup
-
-Speakup indicates various conditions to the user by speaking messages.
-For instance, when you move to the left edge of the screen with the
-review keys, Speakup says, "left."
-Prior to version 3.1.0 of Speakup, all of these messages were in English,
-and they could not be changed.  If you used a non-English synthesizer,
-you still heard English messages, such as "left" and "cursoring on."
-In version 3.1.0 or higher, one may load translations for the various
-messages via the /sys filesystem.
-
-The directory /speakup/i18n contains several collections of messages.
-Each group of messages is stored in its own file.
-The following section lists all of these files, along with a brief description
-of each.
-
-14.1.  Files Under the i18n Subdirectory
-
-* announcements:
-This file contains various general announcements, most of which cannot
-be categorized.  You will find messages such as "You killed Speakup",
-"I'm alive", "leaving help", "parked", "unparked", and others.
-You will also find the names of the screen edges and cursor tracking modes
-here.
-
-* characters:
-See section 12 for a description of this file.
-
-* chartab:
-See section 12.  Unlike the rest of the files in the i18n subdirectory,
-this one does not contain messages to be spoken.
-
-* colors:
-When you use the "say attributes" function, Speakup says the name of the
-foreground and background colors.  These names come from the i18n/colors
-file.
-
-* ctl_keys:
-Here, you will find names of control keys.  These are used with Speakup's
-say_control feature.
-
-* formatted:
-This group of messages contains embedded formatting codes, to specify
-the type and width of displayed data.  If you change these, you must
-preserve all of the formatting codes, and they must appear in the order
-used by the default messages.
-
-* function_names:
-Here, you will find a list of names for Speakup functions.  These are used
-by the help system.  For example, suppose that you have activated help mode,
-and you pressed keypad 3.  Speakup says:
-"keypad 3 is character, say next."
-The message "character, say next" names a Speakup function, and it
-comes from this function_names file.
-
-* key_names:
-Again, key_names is used by Speakup's help system.  In the previous
-example, Speakup said that you pressed "keypad 3."
-This name came from the key_names file.
-
-* states:
-This file contains names for key states.
-Again, these are part of the help system.  For instance, if you had pressed
-speakup + keypad 3, you would hear:
-"speakup keypad 3 is go to bottom edge."
-The speakup key is depressed, so the name of the key state is speakup.
-This part of the message comes from the states collection.
-
-14.2.  Loading Your Own Messages
-
-The files under the i18n subdirectory all follow the same format.
-They consist of lines, with one message per line.
-Each message is represented by a number, followed by the text of the message.
-The number is the position of the message in the given collection.
-For example, if you view the file /speakup/i18n/colors, you will see the
-following list:
-
-0      black
-1      blue
-2      green
-3      cyan
-4      red
-5      magenta
-6      yellow
-7      white
-8      grey
-
-You can change one message, or you can change a whole group.
-To load a whole collection of messages from a new source, simply use
-the cp command:
-cp ~/my_colors /speakup/i18n/colors
-You can change an individual message with the echo command,
-as shown in the following example.
-
-The Spanish name for the color blue is azul.
-Looking at the colors file, we see that the name "blue" is at position 1
-within the colors group.  Let's change blue to azul:
-echo '1 azul' > /speakup/i18n/colors
-The next time that Speakup says message 1 from the colors group, it will
-say "azul", rather than "blue."
-
-In the future, translations into various languages will be made available,
-and most users will just load the files necessary for their language.
-
-14.3.  No Support for Non-Western-European Languages
-
-As of the current release, Speakup only supports Western European languages.
-Support for the extended characters used by languages outside of the Western
-European family of languages is a work in progress.
-
-15.  Using Speakup's Windowing Capability
-
-Speakup has the capability of defining and manipulating windows on the
-screen.  Speakup uses the term "Window", to mean a user defined area of
-the screen.  The key strokes for defining and manipulating Speakup
-windows are as follows:
-
-speakup + f2 -- Set the bounds of the window.
-Speakup + f3 -- clear the current window definition.
-speakup + f4 -- Toggle window silence on and off.
-speakup + keypad plus -- Say the currently defined window.
-
-These capabilities are useful for tracking a certain part of the screen
-without rereading the whole screen, or for silencing a part of the
-screen that is constantly changing, such as a clock or status line.
-
-There is no way to save these window settings, and you can only have one
-window defined for each virtual console.  There is also no way to have
-windows automatically defined for specific applications.
-
-In order to define a window, use the review keys to move your reading
-cursor to the beginning of the area you want to define.  Then press
-speakup + f2.  Speakup will tell you that the window starts at the
-indicated row and column position.  Then move the reading cursor to the
-end of the area to be defined as a window, and press speakup + f2 again.
- If there is more than one line in the window, Speakup will tell you
-that the window ends at the indicated row and column position.  If there
-is only one line in the window, then Speakup will tell you that the
-window is the specified line on the screen.  If you are only defining a
-one line window, you can just press speakup + f2 twice after placing the
-reading cursor on the line you want to define as a window.  It is not
-necessary to position the reading cursor at the end of the line in order
-to define the whole line as a window.
-
-16.  Tools for Controlling Speakup
-
-The speakup distribution includes extra tools (in the tools directory)
-which were written to make speakup easier to use.  This section will
-briefly describe the use of these tools.
-
-16.1.  Speakupconf
-
-speakupconf began life as a contribution from Steve Holmes, a member of
-the speakup community.  We would like to thank him for his work on the
-early versions of this project.
-
-This script may be installed as part of your linux distribution, but if
-it isn't, the recommended places to put it are /usr/local/bin or
-/usr/bin.  This script can be run by any user, so it does not require
-root privileges.
-
-Speakupconf allows you to save and load your Speakup settings.  It works
-by reading and writing the /sys files described above.
-
-The directory that speakupconf uses to store your settings depends on
-whether it is run from the root account.  If you execute speakupconf as
-root, it uses the directory /etc/speakup.  Otherwise, it uses the directory
-~/.speakup, where ~ is your home directory.
-Anyone who needs to use Speakup from your console can load his own custom
-settings with this script.
-
-speakupconf takes one required argument: load or save.
-Use the command
-speakupconf save
-to save your Speakup settings, and
-speakupconf load
-to load them into Speakup.
-A second argument may be specified to use an alternate directory to
-load or save the speakup parameters.
-
-16.2.  Talkwith
-
-Charles Hallenbeck, another member of the speakup community, wrote the
-initial versions of this script, and we would also like to thank him for
-his work on it.
-
-This script needs root privileges to run, so if it is not installed as
-part of your linux distribution, the recommended places to install it
-are /usr/local/sbin or /usr/sbin.
-
-Talkwith allows you to switch synthesizers on the fly.  It takes a synthesizer
-name as an argument.  For instance,
-talkwith dectlk
-causes Speakup to use the DecTalk Express.  If you wish to switch to a
-software synthesizer, you must also indicate which daemon you wish to
-use.  There are two possible choices:
-spd and espeakup.  spd is an abbreviation for speechd-up.
-If you wish to use espeakup for software synthesis, give the command
-talkwith soft espeakup
-To use speechd-up, type:
-talkwith soft spd
-Any arguments that follow the name of the daemon are passed to the daemon
-when it is invoked.  For instance:
-talkwith espeakup --default-voice=fr
-causes espeakup to use the French voice.
-Note that talkwith must always be executed with root privileges.
-
-Talkwith does not attempt to load your settings after the new
-synthesizer is activated.  You can use speakupconf to load your settings
-if desired.
-
-                GNU Free Documentation License
-                  Version 1.2, November 2002
-
-
- Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-
-0. PREAMBLE
-
-The purpose of this License is to make a manual, textbook, or other
-functional and useful document "free" in the sense of freedom: to
-assure everyone the effective freedom to copy and redistribute it,
-with or without modifying it, either commercially or noncommercially.
-Secondarily, this License preserves for the author and publisher a way
-to get credit for their work, while not being considered responsible
-for modifications made by others.
-
-This License is a kind of "copyleft", which means that derivative
-works of the document must themselves be free in the same sense.  It
-complements the GNU General Public License, which is a copyleft
-license designed for free software.
-
-We have designed this License in order to use it for manuals for free
-software, because free software needs free documentation: a free
-program should come with manuals providing the same freedoms that the
-software does.  But this License is not limited to software manuals;
-it can be used for any textual work, regardless of subject matter or
-whether it is published as a printed book.  We recommend this License
-principally for works whose purpose is instruction or reference.
-
-
-1. APPLICABILITY AND DEFINITIONS
-
-This License applies to any manual or other work, in any medium, that
-contains a notice placed by the copyright holder saying it can be
-distributed under the terms of this License.  Such a notice grants a
-world-wide, royalty-free license, unlimited in duration, to use that
-work under the conditions stated herein.  The "Document", below,
-refers to any such manual or work.  Any member of the public is a
-licensee, and is addressed as "you".  You accept the license if you
-copy, modify or distribute the work in a way requiring permission
-under copyright law.
-
-A "Modified Version" of the Document means any work containing the
-Document or a portion of it, either copied verbatim, or with
-modifications and/or translated into another language.
-
-A "Secondary Section" is a named appendix or a front-matter section of
-the Document that deals exclusively with the relationship of the
-publishers or authors of the Document to the Document's overall subject
-(or to related matters) and contains nothing that could fall directly
-within that overall subject.  (Thus, if the Document is in part a
-textbook of mathematics, a Secondary Section may not explain any
-mathematics.)  The relationship could be a matter of historical
-connection with the subject or with related matters, or of legal,
-commercial, philosophical, ethical or political position regarding
-them.
-
-The "Invariant Sections" are certain Secondary Sections whose titles
-are designated, as being those of Invariant Sections, in the notice
-that says that the Document is released under this License.  If a
-section does not fit the above definition of Secondary then it is not
-allowed to be designated as Invariant.  The Document may contain zero
-Invariant Sections.  If the Document does not identify any Invariant
-Sections then there are none.
-
-The "Cover Texts" are certain short passages of text that are listed,
-as Front-Cover Texts or Back-Cover Texts, in the notice that says that
-the Document is released under this License.  A Front-Cover Text may
-be at most 5 words, and a Back-Cover Text may be at most 25 words.
-
-A "Transparent" copy of the Document means a machine-readable copy,
-represented in a format whose specification is available to the
-general public, that is suitable for revising the document
-straightforwardly with generic text editors or (for images composed of
-pixels) generic paint programs or (for drawings) some widely available
-drawing editor, and that is suitable for input to text formatters or
-for automatic translation to a variety of formats suitable for input
-to text formatters.  A copy made in an otherwise Transparent file
-format whose markup, or absence of markup, has been arranged to thwart
-or discourage subsequent modification by readers is not Transparent.
-An image format is not Transparent if used for any substantial amount
-of text.  A copy that is not "Transparent" is called "Opaque".
-
-Examples of suitable formats for Transparent copies include plain
-ASCII without markup, Texinfo input format, LaTeX input format, SGML
-or XML using a publicly available DTD, and standard-conforming simple
-HTML, PostScript or PDF designed for human modification.  Examples of
-transparent image formats include PNG, XCF and JPG.  Opaque formats
-include proprietary formats that can be read and edited only by
-proprietary word processors, SGML or XML for which the DTD and/or
-processing tools are not generally available, and the
-machine-generated HTML, PostScript or PDF produced by some word
-processors for output purposes only.
-
-The "Title Page" means, for a printed book, the title page itself,
-plus such following pages as are needed to hold, legibly, the material
-this License requires to appear in the title page.  For works in
-formats which do not have any title page as such, "Title Page" means
-the text near the most prominent appearance of the work's title,
-preceding the beginning of the body of the text.
-
-A section "Entitled XYZ" means a named subunit of the Document whose
-title either is precisely XYZ or contains XYZ in parentheses following
-text that translates XYZ in another language.  (Here XYZ stands for a
-specific section name mentioned below, such as "Acknowledgements",
-"Dedications", "Endorsements", or "History".)  To "Preserve the Title"
-of such a section when you modify the Document means that it remains a
-section "Entitled XYZ" according to this definition.
-
-The Document may include Warranty Disclaimers next to the notice which
-states that this License applies to the Document.  These Warranty
-Disclaimers are considered to be included by reference in this
-License, but only as regards disclaiming warranties: any other
-implication that these Warranty Disclaimers may have is void and has
-no effect on the meaning of this License.
-
-
-2. VERBATIM COPYING
-
-You may copy and distribute the Document in any medium, either
-commercially or noncommercially, provided that this License, the
-copyright notices, and the license notice saying this License applies
-to the Document are reproduced in all copies, and that you add no other
-conditions whatsoever to those of this License.  You may not use
-technical measures to obstruct or control the reading or further
-copying of the copies you make or distribute.  However, you may accept
-compensation in exchange for copies.  If you distribute a large enough
-number of copies you must also follow the conditions in section 3.
-
-You may also lend copies, under the same conditions stated above, and
-you may publicly display copies.
-
-
-3. COPYING IN QUANTITY
-
-If you publish printed copies (or copies in media that commonly have
-printed covers) of the Document, numbering more than 100, and the
-Document's license notice requires Cover Texts, you must enclose the
-copies in covers that carry, clearly and legibly, all these Cover
-Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
-the back cover.  Both covers must also clearly and legibly identify
-you as the publisher of these copies.  The front cover must present
-the full title with all words of the title equally prominent and
-visible.  You may add other material on the covers in addition.
-Copying with changes limited to the covers, as long as they preserve
-the title of the Document and satisfy these conditions, can be treated
-as verbatim copying in other respects.
-
-If the required texts for either cover are too voluminous to fit
-legibly, you should put the first ones listed (as many as fit
-reasonably) on the actual cover, and continue the rest onto adjacent
-pages.
-
-If you publish or distribute Opaque copies of the Document numbering
-more than 100, you must either include a machine-readable Transparent
-copy along with each Opaque copy, or state in or with each Opaque copy
-a computer-network location from which the general network-using
-public has access to download using public-standard network protocols
-a complete Transparent copy of the Document, free of added material.
-If you use the latter option, you must take reasonably prudent steps,
-when you begin distribution of Opaque copies in quantity, to ensure
-that this Transparent copy will remain thus accessible at the stated
-location until at least one year after the last time you distribute an
-Opaque copy (directly or through your agents or retailers) of that
-edition to the public.
-
-It is requested, but not required, that you contact the authors of the
-Document well before redistributing any large number of copies, to give
-them a chance to provide you with an updated version of the Document.
-
-
-4. MODIFICATIONS
-
-You may copy and distribute a Modified Version of the Document under
-the conditions of sections 2 and 3 above, provided that you release
-the Modified Version under precisely this License, with the Modified
-Version filling the role of the Document, thus licensing distribution
-and modification of the Modified Version to whoever possesses a copy
-of it.  In addition, you must do these things in the Modified Version:
-
-A. Use in the Title Page (and on the covers, if any) a title distinct
-   from that of the Document, and from those of previous versions
-   (which should, if there were any, be listed in the History section
-   of the Document).  You may use the same title as a previous version
-   if the original publisher of that version gives permission.
-B. List on the Title Page, as authors, one or more persons or entities
-   responsible for authorship of the modifications in the Modified
-   Version, together with at least five of the principal authors of the
-   Document (all of its principal authors, if it has fewer than five),
-   unless they release you from this requirement.
-C. State on the Title page the name of the publisher of the
-   Modified Version, as the publisher.
-D. Preserve all the copyright notices of the Document.
-E. Add an appropriate copyright notice for your modifications
-   adjacent to the other copyright notices.
-F. Include, immediately after the copyright notices, a license notice
-   giving the public permission to use the Modified Version under the
-   terms of this License, in the form shown in the Addendum below.
-G. Preserve in that license notice the full lists of Invariant Sections
-   and required Cover Texts given in the Document's license notice.
-H. Include an unaltered copy of this License.
-I. Preserve the section Entitled "History", Preserve its Title, and add
-   to it an item stating at least the title, year, new authors, and
-   publisher of the Modified Version as given on the Title Page.  If
-   there is no section Entitled "History" in the Document, create one
-   stating the title, year, authors, and publisher of the Document as
-   given on its Title Page, then add an item describing the Modified
-   Version as stated in the previous sentence.
-J. Preserve the network location, if any, given in the Document for
-   public access to a Transparent copy of the Document, and likewise
-   the network locations given in the Document for previous versions
-   it was based on.  These may be placed in the "History" section.
-   You may omit a network location for a work that was published at
-   least four years before the Document itself, or if the original
-   publisher of the version it refers to gives permission.
-K. For any section Entitled "Acknowledgements" or "Dedications",
-   Preserve the Title of the section, and preserve in the section all
-   the substance and tone of each of the contributor acknowledgements
-   and/or dedications given therein.
-L. Preserve all the Invariant Sections of the Document,
-   unaltered in their text and in their titles.  Section numbers
-   or the equivalent are not considered part of the section titles.
-M. Delete any section Entitled "Endorsements".  Such a section
-   may not be included in the Modified Version.
-N. Do not retitle any existing section to be Entitled "Endorsements"
-   or to conflict in title with any Invariant Section.
-O. Preserve any Warranty Disclaimers.
-
-If the Modified Version includes new front-matter sections or
-appendices that qualify as Secondary Sections and contain no material
-copied from the Document, you may at your option designate some or all
-of these sections as invariant.  To do this, add their titles to the
-list of Invariant Sections in the Modified Version's license notice.
-These titles must be distinct from any other section titles.
-
-You may add a section Entitled "Endorsements", provided it contains
-nothing but endorsements of your Modified Version by various
-parties--for example, statements of peer review or that the text has
-been approved by an organization as the authoritative definition of a
-standard.
-
-You may add a passage of up to five words as a Front-Cover Text, and a
-passage of up to 25 words as a Back-Cover Text, to the end of the list
-of Cover Texts in the Modified Version.  Only one passage of
-Front-Cover Text and one of Back-Cover Text may be added by (or
-through arrangements made by) any one entity.  If the Document already
-includes a cover text for the same cover, previously added by you or
-by arrangement made by the same entity you are acting on behalf of,
-you may not add another; but you may replace the old one, on explicit
-permission from the previous publisher that added the old one.
-
-The author(s) and publisher(s) of the Document do not by this License
-give permission to use their names for publicity for or to assert or
-imply endorsement of any Modified Version.
-
-
-5. COMBINING DOCUMENTS
-
-You may combine the Document with other documents released under this
-License, under the terms defined in section 4 above for modified
-versions, provided that you include in the combination all of the
-Invariant Sections of all of the original documents, unmodified, and
-list them all as Invariant Sections of your combined work in its
-license notice, and that you preserve all their Warranty Disclaimers.
-
-The combined work need only contain one copy of this License, and
-multiple identical Invariant Sections may be replaced with a single
-copy.  If there are multiple Invariant Sections with the same name but
-different contents, make the title of each such section unique by
-adding at the end of it, in parentheses, the name of the original
-author or publisher of that section if known, or else a unique number.
-Make the same adjustment to the section titles in the list of
-Invariant Sections in the license notice of the combined work.
-
-In the combination, you must combine any sections Entitled "History"
-in the various original documents, forming one section Entitled
-"History"; likewise combine any sections Entitled "Acknowledgements",
-and any sections Entitled "Dedications".  You must delete all sections
-Entitled "Endorsements".
-
-
-6. COLLECTIONS OF DOCUMENTS
-
-You may make a collection consisting of the Document and other documents
-released under this License, and replace the individual copies of this
-License in the various documents with a single copy that is included in
-the collection, provided that you follow the rules of this License for
-verbatim copying of each of the documents in all other respects.
-
-You may extract a single document from such a collection, and distribute
-it individually under this License, provided you insert a copy of this
-License into the extracted document, and follow this License in all
-other respects regarding verbatim copying of that document.
-
-
-7. AGGREGATION WITH INDEPENDENT WORKS
-
-A compilation of the Document or its derivatives with other separate
-and independent documents or works, in or on a volume of a storage or
-distribution medium, is called an "aggregate" if the copyright
-resulting from the compilation is not used to limit the legal rights
-of the compilation's users beyond what the individual works permit.
-When the Document is included in an aggregate, this License does not
-apply to the other works in the aggregate which are not themselves
-derivative works of the Document.
-
-If the Cover Text requirement of section 3 is applicable to these
-copies of the Document, then if the Document is less than one half of
-the entire aggregate, the Document's Cover Texts may be placed on
-covers that bracket the Document within the aggregate, or the
-electronic equivalent of covers if the Document is in electronic form.
-Otherwise they must appear on printed covers that bracket the whole
-aggregate.
-
-
-8. TRANSLATION
-
-Translation is considered a kind of modification, so you may
-distribute translations of the Document under the terms of section 4.
-Replacing Invariant Sections with translations requires special
-permission from their copyright holders, but you may include
-translations of some or all Invariant Sections in addition to the
-original versions of these Invariant Sections.  You may include a
-translation of this License, and all the license notices in the
-Document, and any Warranty Disclaimers, provided that you also include
-the original English version of this License and the original versions
-of those notices and disclaimers.  In case of a disagreement between
-the translation and the original version of this License or a notice
-or disclaimer, the original version will prevail.
-
-If a section in the Document is Entitled "Acknowledgements",
-"Dedications", or "History", the requirement (section 4) to Preserve
-its Title (section 1) will typically require changing the actual
-title.
-
-
-9. TERMINATION
-
-You may not copy, modify, sublicense, or distribute the Document except
-as expressly provided for under this License.  Any other attempt to
-copy, modify, sublicense or distribute the Document is void, and will
-automatically terminate your rights under this License.  However,
-parties who have received copies, or rights, from you under this
-License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-
-10. FUTURE REVISIONS OF THIS LICENSE
-
-The Free Software Foundation may publish new, revised versions
-of the GNU Free Documentation License from time to time.  Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.  See
-https://www.gnu.org/copyleft/.
-
-Each version of the License is given a distinguishing version number.
-If the Document specifies that a particular numbered version of this
-License "or any later version" applies to it, you have the option of
-following the terms and conditions either of that specified version or
-of any later version that has been published (not as a draft) by the
-Free Software Foundation.  If the Document does not specify a version
-number of this License, you may choose any version ever published (not
-as a draft) by the Free Software Foundation.
-
-
-ADDENDUM: How to use this License for your documents
-
-To use this License in a document you have written, include a copy of
-the License in the document and put the following copyright and
-license notices just after the title page:
-
-    Copyright (c)  YEAR  YOUR NAME.
-    Permission is granted to copy, distribute and/or modify this document
-    under the terms of the GNU Free Documentation License, Version 1.2
-    or any later version published by the Free Software Foundation;
-    with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
-    A copy of the license is included in the section entitled "GNU
-    Free Documentation License".
-
-If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
-replace the "with...Texts." line with this:
-
-    with the Invariant Sections being LIST THEIR TITLES, with the
-    Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
-
-If you have Invariant Sections without Cover Texts, or some other
-combination of the three, merge those two alternatives to suit the
-situation.
-
-If your document contains nontrivial examples of program code, we
-recommend releasing these examples in parallel under your choice of
-free software license, such as the GNU General Public License,
-to permit their use in free software.
-
-The End.
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c
deleted file mode 100644 (file)
index 3568bfb..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/types.h>
-#include <linux/ctype.h>       /* for isdigit() and friends */
-#include <linux/fs.h>
-#include <linux/mm.h>          /* for verify_area */
-#include <linux/errno.h>       /* for -EBUSY */
-#include <linux/ioport.h>      /* for check_region, request_region */
-#include <linux/interrupt.h>
-#include <linux/delay.h>       /* for loops_per_sec */
-#include <linux/kmod.h>
-#include <linux/jiffies.h>
-#include <linux/uaccess.h>     /* for copy_from_user */
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/kthread.h>
-
-#include "spk_priv.h"
-#include "speakup.h"
-#include "serialio.h"
-
-static LIST_HEAD(synths);
-struct spk_synth *synth;
-char spk_pitch_buff[32] = "";
-static int module_status;
-bool spk_quiet_boot;
-
-struct speakup_info_t speakup_info = {
-       /*
-        * This spinlock is used to protect the entire speakup machinery, and
-        * must be taken at each kernel->speakup transition and released at
-        * each corresponding speakup->kernel transition.
-        *
-        * The progression thread only interferes with the speakup machinery
-        * through the synth buffer, so only needs to take the lock
-        * while tinkering with the buffer.
-        *
-        * We use spin_lock/trylock_irqsave and spin_unlock_irqrestore with this
-        * spinlock because speakup needs to disable the keyboard IRQ.
-        */
-       .spinlock = __SPIN_LOCK_UNLOCKED(speakup_info.spinlock),
-       .flushing = 0,
-};
-EXPORT_SYMBOL_GPL(speakup_info);
-
-static int do_synth_init(struct spk_synth *in_synth);
-
-/*
- * Main loop of the progression thread: keep eating from the buffer
- * and push to the serial port, waiting as needed
- *
- * For devices that have a "full" notification mechanism, the driver can
- * adapt the loop the way they prefer.
- */
-static void _spk_do_catch_up(struct spk_synth *synth, int unicode)
-{
-       u16 ch;
-       unsigned long flags;
-       unsigned long jiff_max;
-       struct var_t *delay_time;
-       struct var_t *full_time;
-       struct var_t *jiffy_delta;
-       int jiffy_delta_val;
-       int delay_time_val;
-       int full_time_val;
-       int ret;
-
-       jiffy_delta = spk_get_var(JIFFY);
-       full_time = spk_get_var(FULL);
-       delay_time = spk_get_var(DELAY);
-
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       jiffy_delta_val = jiffy_delta->u.n.value;
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-
-       jiff_max = jiffies + jiffy_delta_val;
-       while (!kthread_should_stop()) {
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               if (speakup_info.flushing) {
-                       speakup_info.flushing = 0;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       synth->flush(synth);
-                       continue;
-               }
-               if (!unicode)
-                       synth_buffer_skip_nonlatin1();
-               if (synth_buffer_empty()) {
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       break;
-               }
-               ch = synth_buffer_peek();
-               set_current_state(TASK_INTERRUPTIBLE);
-               full_time_val = full_time->u.n.value;
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-               if (ch == '\n')
-                       ch = synth->procspeech;
-               if (unicode)
-                       ret = synth->io_ops->synth_out_unicode(synth, ch);
-               else
-                       ret = synth->io_ops->synth_out(synth, ch);
-               if (!ret) {
-                       schedule_timeout(msecs_to_jiffies(full_time_val));
-                       continue;
-               }
-               if (time_after_eq(jiffies, jiff_max) && (ch == SPACE)) {
-                       spin_lock_irqsave(&speakup_info.spinlock, flags);
-                       jiffy_delta_val = jiffy_delta->u.n.value;
-                       delay_time_val = delay_time->u.n.value;
-                       full_time_val = full_time->u.n.value;
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       if (synth->io_ops->synth_out(synth, synth->procspeech))
-                               schedule_timeout(
-                                       msecs_to_jiffies(delay_time_val));
-                       else
-                               schedule_timeout(
-                                       msecs_to_jiffies(full_time_val));
-                       jiff_max = jiffies + jiffy_delta_val;
-               }
-               set_current_state(TASK_RUNNING);
-               spin_lock_irqsave(&speakup_info.spinlock, flags);
-               synth_buffer_getc();
-               spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       }
-       synth->io_ops->synth_out(synth, synth->procspeech);
-}
-
-void spk_do_catch_up(struct spk_synth *synth)
-{
-       _spk_do_catch_up(synth, 0);
-}
-EXPORT_SYMBOL_GPL(spk_do_catch_up);
-
-void spk_do_catch_up_unicode(struct spk_synth *synth)
-{
-       _spk_do_catch_up(synth, 1);
-}
-EXPORT_SYMBOL_GPL(spk_do_catch_up_unicode);
-
-void spk_synth_flush(struct spk_synth *synth)
-{
-       synth->io_ops->flush_buffer();
-       synth->io_ops->synth_out(synth, synth->clear);
-}
-EXPORT_SYMBOL_GPL(spk_synth_flush);
-
-unsigned char spk_synth_get_index(struct spk_synth *synth)
-{
-       return synth->io_ops->synth_in_nowait();
-}
-EXPORT_SYMBOL_GPL(spk_synth_get_index);
-
-int spk_synth_is_alive_nop(struct spk_synth *synth)
-{
-       synth->alive = 1;
-       return 1;
-}
-EXPORT_SYMBOL_GPL(spk_synth_is_alive_nop);
-
-int spk_synth_is_alive_restart(struct spk_synth *synth)
-{
-       if (synth->alive)
-               return 1;
-       if (spk_wait_for_xmitr(synth) > 0) {
-               /* restart */
-               synth->alive = 1;
-               synth_printf("%s", synth->init);
-               return 2; /* reenabled */
-       }
-       pr_warn("%s: can't restart synth\n", synth->long_name);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(spk_synth_is_alive_restart);
-
-static void thread_wake_up(struct timer_list *unused)
-{
-       wake_up_interruptible_all(&speakup_event);
-}
-
-static DEFINE_TIMER(thread_timer, thread_wake_up);
-
-void synth_start(void)
-{
-       struct var_t *trigger_time;
-
-       if (!synth->alive) {
-               synth_buffer_clear();
-               return;
-       }
-       trigger_time = spk_get_var(TRIGGER);
-       if (!timer_pending(&thread_timer))
-               mod_timer(&thread_timer, jiffies +
-                       msecs_to_jiffies(trigger_time->u.n.value));
-}
-
-void spk_do_flush(void)
-{
-       if (!synth)
-               return;
-
-       speakup_info.flushing = 1;
-       synth_buffer_clear();
-       if (synth->alive) {
-               if (spk_pitch_shift) {
-                       synth_printf("%s", spk_pitch_buff);
-                       spk_pitch_shift = 0;
-               }
-       }
-       wake_up_interruptible_all(&speakup_event);
-       wake_up_process(speakup_task);
-}
-
-void synth_write(const char *buf, size_t count)
-{
-       while (count--)
-               synth_buffer_add(*buf++);
-       synth_start();
-}
-
-void synth_printf(const char *fmt, ...)
-{
-       va_list args;
-       unsigned char buf[160], *p;
-       int r;
-
-       va_start(args, fmt);
-       r = vsnprintf(buf, sizeof(buf), fmt, args);
-       va_end(args);
-       if (r > sizeof(buf) - 1)
-               r = sizeof(buf) - 1;
-
-       p = buf;
-       while (r--)
-               synth_buffer_add(*p++);
-       synth_start();
-}
-EXPORT_SYMBOL_GPL(synth_printf);
-
-void synth_putwc(u16 wc)
-{
-       synth_buffer_add(wc);
-}
-EXPORT_SYMBOL_GPL(synth_putwc);
-
-void synth_putwc_s(u16 wc)
-{
-       synth_buffer_add(wc);
-       synth_start();
-}
-EXPORT_SYMBOL_GPL(synth_putwc_s);
-
-void synth_putws(const u16 *buf)
-{
-       const u16 *p;
-
-       for (p = buf; *p; p++)
-               synth_buffer_add(*p);
-}
-EXPORT_SYMBOL_GPL(synth_putws);
-
-void synth_putws_s(const u16 *buf)
-{
-       synth_putws(buf);
-       synth_start();
-}
-EXPORT_SYMBOL_GPL(synth_putws_s);
-
-static int index_count;
-static int sentence_count;
-
-void spk_reset_index_count(int sc)
-{
-       static int first = 1;
-
-       if (first)
-               first = 0;
-       else
-               synth->get_index(synth);
-       index_count = 0;
-       sentence_count = sc;
-}
-
-int synth_supports_indexing(void)
-{
-       if (synth->get_index)
-               return 1;
-       return 0;
-}
-
-void synth_insert_next_index(int sent_num)
-{
-       int out;
-
-       if (synth->alive) {
-               if (sent_num == 0) {
-                       synth->indexing.currindex++;
-                       index_count++;
-                       if (synth->indexing.currindex >
-                                       synth->indexing.highindex)
-                               synth->indexing.currindex =
-                                       synth->indexing.lowindex;
-               }
-
-               out = synth->indexing.currindex * 10 + sent_num;
-               synth_printf(synth->indexing.command, out, out);
-       }
-}
-
-void spk_get_index_count(int *linecount, int *sentcount)
-{
-       int ind = synth->get_index(synth);
-
-       if (ind) {
-               sentence_count = ind % 10;
-
-               if ((ind / 10) <= synth->indexing.currindex)
-                       index_count = synth->indexing.currindex - (ind / 10);
-               else
-                       index_count = synth->indexing.currindex
-                               - synth->indexing.lowindex
-                               + synth->indexing.highindex - (ind / 10) + 1;
-       }
-       *sentcount = sentence_count;
-       *linecount = index_count;
-}
-
-static struct resource synth_res;
-
-int synth_request_region(unsigned long start, unsigned long n)
-{
-       struct resource *parent = &ioport_resource;
-
-       memset(&synth_res, 0, sizeof(synth_res));
-       synth_res.name = synth->name;
-       synth_res.start = start;
-       synth_res.end = start + n - 1;
-       synth_res.flags = IORESOURCE_BUSY;
-       return request_resource(parent, &synth_res);
-}
-EXPORT_SYMBOL_GPL(synth_request_region);
-
-int synth_release_region(unsigned long start, unsigned long n)
-{
-       return release_resource(&synth_res);
-}
-EXPORT_SYMBOL_GPL(synth_release_region);
-
-struct var_t synth_time_vars[] = {
-       { DELAY, .u.n = {NULL, 100, 100, 2000, 0, 0, NULL } },
-       { TRIGGER, .u.n = {NULL, 20, 10, 2000, 0, 0, NULL } },
-       { JIFFY, .u.n = {NULL, 50, 20, 200, 0, 0, NULL } },
-       { FULL, .u.n = {NULL, 400, 200, 60000, 0, 0, NULL } },
-       V_LAST_VAR
-};
-
-/* called by: speakup_init() */
-int synth_init(char *synth_name)
-{
-       int ret = 0;
-       struct spk_synth *tmp, *synth = NULL;
-
-       if (!synth_name)
-               return 0;
-
-       if (strcmp(synth_name, "none") == 0) {
-               mutex_lock(&spk_mutex);
-               synth_release();
-               mutex_unlock(&spk_mutex);
-               return 0;
-       }
-
-       mutex_lock(&spk_mutex);
-       /* First, check if we already have it loaded. */
-       list_for_each_entry(tmp, &synths, node) {
-               if (strcmp(tmp->name, synth_name) == 0)
-                       synth = tmp;
-       }
-
-       /* If we got one, initialize it now. */
-       if (synth)
-               ret = do_synth_init(synth);
-       else
-               ret = -ENODEV;
-       mutex_unlock(&spk_mutex);
-
-       return ret;
-}
-
-/* called by: synth_add() */
-static int do_synth_init(struct spk_synth *in_synth)
-{
-       struct var_t *var;
-
-       synth_release();
-       if (in_synth->checkval != SYNTH_CHECK)
-               return -EINVAL;
-       synth = in_synth;
-       synth->alive = 0;
-       pr_warn("synth probe\n");
-       if (synth->probe(synth) < 0) {
-               pr_warn("%s: device probe failed\n", in_synth->name);
-               synth = NULL;
-               return -ENODEV;
-       }
-       synth_time_vars[0].u.n.value =
-               synth_time_vars[0].u.n.default_val = synth->delay;
-       synth_time_vars[1].u.n.value =
-               synth_time_vars[1].u.n.default_val = synth->trigger;
-       synth_time_vars[2].u.n.value =
-               synth_time_vars[2].u.n.default_val = synth->jiffies;
-       synth_time_vars[3].u.n.value =
-               synth_time_vars[3].u.n.default_val = synth->full;
-       synth_printf("%s", synth->init);
-       for (var = synth->vars;
-               (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
-               speakup_register_var(var);
-       if (!spk_quiet_boot)
-               synth_printf("%s found\n", synth->long_name);
-       if (synth->attributes.name &&
-           sysfs_create_group(speakup_kobj, &synth->attributes) < 0)
-               return -ENOMEM;
-       synth_flags = synth->flags;
-       wake_up_interruptible_all(&speakup_event);
-       if (speakup_task)
-               wake_up_process(speakup_task);
-       return 0;
-}
-
-void synth_release(void)
-{
-       struct var_t *var;
-       unsigned long flags;
-
-       if (!synth)
-               return;
-       spin_lock_irqsave(&speakup_info.spinlock, flags);
-       pr_info("releasing synth %s\n", synth->name);
-       synth->alive = 0;
-       del_timer(&thread_timer);
-       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-       if (synth->attributes.name)
-               sysfs_remove_group(speakup_kobj, &synth->attributes);
-       for (var = synth->vars; var->var_id != MAXVARS; var++)
-               speakup_unregister_var(var->var_id);
-       synth->release();
-       synth = NULL;
-}
-
-/* called by: all_driver_init() */
-int synth_add(struct spk_synth *in_synth)
-{
-       int status = 0;
-       struct spk_synth *tmp;
-
-       mutex_lock(&spk_mutex);
-
-       list_for_each_entry(tmp, &synths, node) {
-               if (tmp == in_synth) {
-                       mutex_unlock(&spk_mutex);
-                       return 0;
-               }
-       }
-
-       if (in_synth->startup)
-               status = do_synth_init(in_synth);
-
-       if (!status)
-               list_add_tail(&in_synth->node, &synths);
-
-       mutex_unlock(&spk_mutex);
-       return status;
-}
-EXPORT_SYMBOL_GPL(synth_add);
-
-void synth_remove(struct spk_synth *in_synth)
-{
-       mutex_lock(&spk_mutex);
-       if (synth == in_synth)
-               synth_release();
-       list_del(&in_synth->node);
-       module_status = 0;
-       mutex_unlock(&spk_mutex);
-}
-EXPORT_SYMBOL_GPL(synth_remove);
-
-struct spk_synth *synth_current(void)
-{
-       return synth;
-}
-EXPORT_SYMBOL_GPL(synth_current);
-
-short spk_punc_masks[] = { 0, SOME, MOST, PUNC, PUNC | B_SYM };
diff --git a/drivers/staging/speakup/sysfs-driver-speakup b/drivers/staging/speakup/sysfs-driver-speakup
deleted file mode 100644 (file)
index c6a32c4..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-What:          /sys/accessibility/speakup/attrib_bleep
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Beeps the PC speaker when there is an attribute change such as
-               foreground or background color when using speakup review
-               commands. One = on, zero = off.
-
-What:          /sys/accessibility/speakup/bell_pos
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This works much like a typewriter bell. If for example 72 is
-               echoed to bell_pos, it will beep the PC speaker when typing on
-               a line past character 72.
-
-What:          /sys/accessibility/speakup/bleeps
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This controls whether one hears beeps through the PC speaker
-               when using speakup's review commands.
-               TODO: what values does it accept?
-
-What:          /sys/accessibility/speakup/bleep_time
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This controls the duration of the PC speaker beeps speakup
-               produces.
-               TODO: What are the units? Jiffies?
-
-What:          /sys/accessibility/speakup/cursor_time
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This controls cursor delay when using arrow keys. When a
-               connection is very slow, with the default setting, when moving
-               with  the arrows, or backspacing etc. speakup says the incorrect
-               characters. Set this to a higher value to adjust for the delay
-               and better synchronisation between cursor position and speech.
-
-What:          /sys/accessibility/speakup/delimiters
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Delimit a word from speakup.
-               TODO: add more info
-
-What:          /sys/accessibility/speakup/ex_num
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   TODO:
-
-What:          /sys/accessibility/speakup/key_echo
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Controls if speakup speaks keys when they are typed. One = on,
-               zero = off or don't echo keys.
-
-What:          /sys/accessibility/speakup/keymap
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Speakup keymap remaps keys to Speakup functions.
-               It uses a binary
-               format. A special program called genmap is needed to compile a
-               textual  keymap into the binary format which is then loaded into
-               /sys/accessibility/speakup/keymap.
-
-What:          /sys/accessibility/speakup/no_interrupt
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Controls if typing interrupts output from speakup. With
-               no_interrupt set to zero, typing on the keyboard will interrupt
-               speakup if for example
-               the say screen command is used before the
-               entire screen  is read.
-               With no_interrupt set to one, if the say
-               screen command is used, and one then types on the keyboard,
-               speakup will continue to say the whole screen regardless until
-               it finishes.
-
-What:          /sys/accessibility/speakup/punc_all
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This is a list of all the punctuation speakup should speak when
-               punc_level is set to four.
-
-What:          /sys/accessibility/speakup/punc_level
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Controls the level of punctuation spoken as the screen is
-               displayed, not reviewed. Levels range from zero no punctuation,
-               to four, all punctuation. One corresponds to punc_some, two
-               corresponds to punc_most, and three as well as four both
-               correspond to punc_all. Some hardware synthesizers may have
-               different levels each corresponding to  three and four for
-               punc_level. Also note that if punc_level is set to zero, and
-               key_echo is set to one, typed punctuation is still spoken as it
-               is typed.
-
-What:          /sys/accessibility/speakup/punc_most
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This is a list of all the punctuation speakup should speak when
-               punc_level is set to two.
-
-What:          /sys/accessibility/speakup/punc_some
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This is a list of all the punctuation speakup should speak when
-               punc_level is set to one.
-
-What:          /sys/accessibility/speakup/reading_punc
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Almost the same as punc_level, the differences being that
-               reading_punc controls the level of punctuation when reviewing
-               the screen with speakup's screen review commands. The other
-               difference is that reading_punc set to three speaks punc_all,
-               and reading_punc set to four speaks all punctuation, including
-               spaces.
-
-What:          /sys/accessibility/speakup/repeats
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   A list of characters speakup repeats. Normally, when there are
-               more than three characters in a row, speakup
-               just reads three of
-               those characters. For example, "......" would be read as dot,
-               dot, dot. If a . is added to the list of characters in repeats,
-               "......" would be read as dot, dot, dot, times six.
-
-What:          /sys/accessibility/speakup/say_control
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   If set to one, speakup speaks shift, alt and control when those
-               keys are pressed. If say_control is set to zero, shift, ctrl,
-               and alt are not spoken when they are pressed.
-
-What:          /sys/accessibility/speakup/say_word_ctl
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   TODO:
-
-What:          /sys/accessibility/speakup/silent
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   TODO:
-
-What:          /sys/accessibility/speakup/spell_delay
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This controls how fast a word is spelled
-               when speakup's say word
-               review command is pressed twice quickly to speak the current
-               word being reviewed. Zero just speaks the letters one after
-               another, while values one through four
-               seem to introduce more of
-               a pause between the spelling of each letter by speakup.
-
-What:          /sys/accessibility/speakup/synth
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Gets or sets the synthesizer driver currently in use. Reading
-               synth returns the synthesizer driver currently in use. Writing
-               synth switches to the given synthesizer driver, provided it is
-               either built into the kernel, or already loaded as a module.
-
-What:          /sys/accessibility/speakup/synth_direct
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Sends whatever is written to synth_direct
-               directly to the speech synthesizer in use, bypassing speakup.
-               This could be used to make the synthesizer speak
-               a string, or to
-               send control sequences to the synthesizer to change how the
-               synthesizer behaves.
-
-What:          /sys/accessibility/speakup/version
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Reading version returns the version of speakup, and the version
-               of the synthesizer driver currently in use.
-
-What:          /sys/accessibility/speakup/i18n/announcements
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This file contains various general announcements, most of which
-               cannot be categorized.  You will find messages such as "You
-               killed Speakup", "I'm alive", "leaving help", "parked",
-               "unparked", and others. You will also find the names of the
-               screen edges and cursor tracking modes here.
-
-What:          /sys/accessibility/speakup/i18n/chartab
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   TODO
-
-What:          /sys/accessibility/speakup/i18n/ctl_keys
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Here, you will find names of control keys.  These are used with
-               Speakup's say_control feature.
-
-What:          /sys/accessibility/speakup/i18n/function_names
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Here, you will find a list of names for Speakup functions.
-               These are used by the help system.  For example, suppose that
-               you have activated help mode, and you pressed
-               keypad 3.  Speakup
-               says: "keypad 3 is character, say next."
-               The message "character, say next" names a Speakup function, and
-               it comes from this function_names file.
-
-What:          /sys/accessibility/speakup/i18n/states
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This file contains names for key states.
-               Again, these are part of the help system.  For instance, if you
-               had pressed speakup + keypad 3, you would hear:
-               "speakup keypad 3 is go to bottom edge."
-               The speakup key is depressed, so the name of the key state is
-               speakup.
-               This part of the message comes from the states collection.
-
-What:          /sys/accessibility/speakup/i18n/characters
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Through this sys entry, Speakup gives you the ability to change
-               how Speakup pronounces a given character. You could, for
-               example, change how some punctuation characters are spoken. You
-               can even change how Speakup will pronounce certain letters. For
-               further details see '12.  Changing the Pronunciation of
-               Characters' in Speakup User's Guide (file spkguide.txt in
-               source).
-
-What:          /sys/accessibility/speakup/i18n/colors
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   When you use the "say attributes" function, Speakup says the
-               name of the foreground and background colors.  These names come
-               from the i18n/colors file.
-
-What:          /sys/accessibility/speakup/i18n/formatted
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This group of messages contains embedded formatting codes, to
-               specify the type and width of displayed data.  If you change
-               these, you must preserve all of the formatting codes, and they
-               must appear in the order used by the default messages.
-
-What:          /sys/accessibility/speakup/i18n/key_names
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Again, key_names is used by Speakup's help system.  In the
-               previous example, Speakup said that you pressed "keypad 3."
-               This name came from the key_names file.
-
-What:          /sys/accessibility/speakup/<synth-name>/
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   In `/sys/accessibility/speakup` is a directory corresponding to
-               the synthesizer driver currently in use (E.G) `soft` for the
-               soft driver. This directory contains files which control the
-               speech synthesizer itself,
-               as opposed to controlling the speakup
-               screen reader. The parameters in this directory have the same
-               names and functions across all
-               supported synthesizers. The range
-               of values for freq, pitch, rate, and vol is the same for all
-               supported synthesizers, with the given range being internally
-               mapped by the driver to  more or less fit the range of values
-               supported for a given parameter by the individual synthesizer.
-               Below is a description of values and  parameters for soft
-               synthesizer, which is currently the most commonly used.
-
-What:          /sys/accessibility/speakup/soft/caps_start
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This is the string that is sent to the synthesizer to cause it
-               to start speaking uppercase letters. For the soft synthesizer
-               and most others, this causes the pitch of the voice to rise
-               above the currently set pitch.
-
-What:          /sys/accessibility/speakup/soft/caps_stop
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This is the string sent to the synthesizer to cause it to stop
-               speaking uppercase letters. In the case of the soft synthesizer
-               and most others, this returns the pitch of the voice
-               down to the
-               currently set pitch.
-
-What:          /sys/accessibility/speakup/soft/delay_time
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   TODO:
-
-What:          /sys/accessibility/speakup/soft/direct
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Controls if punctuation is spoken by speakup, or by the
-               synthesizer.
-               For example, speakup speaks ">" as "greater", while
-               the espeak synthesizer used by the soft driver speaks "greater
-               than". Zero lets speakup speak the punctuation. One lets the
-               synthesizer itself speak punctuation.
-
-What:          /sys/accessibility/speakup/soft/freq
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Gets or sets the frequency of the speech synthesizer. Range is
-               0-9.
-
-What:          /sys/accessibility/speakup/soft/full_time
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   TODO:
-
-What:          /sys/accessibility/speakup/soft/jiffy_delta
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   This controls how many jiffys the kernel gives to the
-               synthesizer. Setting this too high can make a system unstable,
-               or even crash it.
-
-What:          /sys/accessibility/speakup/soft/pitch
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Gets or sets the pitch of the synthesizer. The range is 0-9.
-
-What:          /sys/accessibility/speakup/soft/inflection
-KernelVersion: 5.8
-Contact:       speakup@linux-speakup.org
-Description:   Gets or sets the inflection of the synthesizer, i.e. the pitch
-               range. The range is 0-9.
-
-What:          /sys/accessibility/speakup/soft/punct
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Gets or sets the amount of punctuation spoken by the
-               synthesizer. The range for the soft driver seems to be 0-2.
-               TODO: How is this related to speakup's punc_level, or
-               reading_punc.
-
-What:          /sys/accessibility/speakup/soft/rate
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Gets or sets the rate of the synthesizer. Range is from zero
-               slowest, to nine fastest.
-
-What:          /sys/accessibility/speakup/soft/tone
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Gets or sets the tone of the speech synthesizer. The range for
-               the soft driver seems to be 0-2. This seems to make no
-               difference if using espeak and the espeakup connector.
-               TODO: does espeakup support different tonalities?
-
-What:          /sys/accessibility/speakup/soft/trigger_time
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   TODO:
-
-What:          /sys/accessibility/speakup/soft/voice
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Gets or sets the voice used by the synthesizer if the
-               synthesizer can speak in more than one voice. The range for the
-               soft driver is 0-7. Note that while espeak supports multiple
-               voices, this parameter will not set the voice when the espeakup
-               connector is used  between speakup and espeak.
-
-What:          /sys/accessibility/speakup/soft/vol
-KernelVersion: 2.6
-Contact:       speakup@linux-speakup.org
-Description:   Gets or sets the volume of the speech synthesizer. Range is 0-9,
-               with zero being the softest, and nine being the loudest.
-
diff --git a/drivers/staging/speakup/thread.c b/drivers/staging/speakup/thread.c
deleted file mode 100644 (file)
index 2fc75e6..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kthread.h>
-#include <linux/wait.h>
-
-#include "spk_types.h"
-#include "speakup.h"
-#include "spk_priv.h"
-
-DECLARE_WAIT_QUEUE_HEAD(speakup_event);
-EXPORT_SYMBOL_GPL(speakup_event);
-
-int speakup_thread(void *data)
-{
-       unsigned long flags;
-       int should_break;
-       struct bleep our_sound;
-
-       our_sound.active = 0;
-       our_sound.freq = 0;
-       our_sound.jiffies = 0;
-
-       mutex_lock(&spk_mutex);
-       while (1) {
-               DEFINE_WAIT(wait);
-
-               while (1) {
-                       spin_lock_irqsave(&speakup_info.spinlock, flags);
-                       our_sound = spk_unprocessed_sound;
-                       spk_unprocessed_sound.active = 0;
-                       prepare_to_wait(&speakup_event, &wait,
-                                       TASK_INTERRUPTIBLE);
-                       should_break = kthread_should_stop() ||
-                               our_sound.active ||
-                               (synth && synth->catch_up && synth->alive &&
-                                       (speakup_info.flushing ||
-                                       !synth_buffer_empty()));
-                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
-                       if (should_break)
-                               break;
-                       mutex_unlock(&spk_mutex);
-                       schedule();
-                       mutex_lock(&spk_mutex);
-               }
-               finish_wait(&speakup_event, &wait);
-               if (kthread_should_stop())
-                       break;
-
-               if (our_sound.active)
-                       kd_mksound(our_sound.freq, our_sound.jiffies);
-               if (synth && synth->catch_up && synth->alive) {
-                       /*
-                        * It is up to the callee to take the lock, so that it
-                        * can sleep whenever it likes
-                        */
-                       synth->catch_up(synth);
-               }
-
-               speakup_start_ttys();
-       }
-       mutex_unlock(&spk_mutex);
-       return 0;
-}
diff --git a/drivers/staging/speakup/varhandlers.c b/drivers/staging/speakup/varhandlers.c
deleted file mode 100644 (file)
index d7f6bec..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/ctype.h>
-#include "spk_types.h"
-#include "spk_priv.h"
-#include "speakup.h"
-
-static struct st_var_header var_headers[] = {
-       { "version", VERSION, VAR_PROC, NULL, NULL },
-       { "synth_name", SYNTH, VAR_PROC, NULL, NULL },
-       { "keymap", KEYMAP, VAR_PROC, NULL, NULL },
-       { "silent", SILENT, VAR_PROC, NULL, NULL },
-       { "punc_some", PUNC_SOME, VAR_PROC, NULL, NULL },
-       { "punc_most", PUNC_MOST, VAR_PROC, NULL, NULL },
-       { "punc_all", PUNC_ALL, VAR_PROC, NULL, NULL },
-       { "delimiters", DELIM, VAR_PROC, NULL, NULL },
-       { "repeats", REPEATS, VAR_PROC, NULL, NULL },
-       { "ex_num", EXNUMBER, VAR_PROC, NULL, NULL },
-       { "characters", CHARS, VAR_PROC, NULL, NULL },
-       { "synth_direct", SYNTH_DIRECT, VAR_PROC, NULL, NULL },
-       { "caps_start", CAPS_START, VAR_STRING, spk_str_caps_start, NULL },
-       { "caps_stop", CAPS_STOP, VAR_STRING, spk_str_caps_stop, NULL },
-       { "delay_time", DELAY, VAR_TIME, NULL, NULL },
-       { "trigger_time", TRIGGER, VAR_TIME, NULL, NULL },
-       { "jiffy_delta", JIFFY, VAR_TIME, NULL, NULL },
-       { "full_time", FULL, VAR_TIME, NULL, NULL },
-       { "spell_delay", SPELL_DELAY, VAR_NUM, &spk_spell_delay, NULL },
-       { "bleeps", BLEEPS, VAR_NUM, &spk_bleeps, NULL },
-       { "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, &spk_attrib_bleep, NULL },
-       { "bleep_time", BLEEP_TIME, VAR_TIME, &spk_bleep_time, NULL },
-       { "cursor_time", CURSOR_TIME, VAR_TIME, NULL, NULL },
-       { "punc_level", PUNC_LEVEL, VAR_NUM, &spk_punc_level, NULL },
-       { "reading_punc", READING_PUNC, VAR_NUM, &spk_reading_punc, NULL },
-       { "say_control", SAY_CONTROL, VAR_NUM, &spk_say_ctrl, NULL },
-       { "say_word_ctl", SAY_WORD_CTL, VAR_NUM, &spk_say_word_ctl, NULL },
-       { "no_interrupt", NO_INTERRUPT, VAR_NUM, &spk_no_intr, NULL },
-       { "key_echo", KEY_ECHO, VAR_NUM, &spk_key_echo, NULL },
-       { "bell_pos", BELL_POS, VAR_NUM, &spk_bell_pos, NULL },
-       { "rate", RATE, VAR_NUM, NULL, NULL },
-       { "pitch", PITCH, VAR_NUM, NULL, NULL },
-       { "inflection", INFLECTION, VAR_NUM, NULL, NULL },
-       { "vol", VOL, VAR_NUM, NULL, NULL },
-       { "tone", TONE, VAR_NUM, NULL, NULL },
-       { "punct", PUNCT, VAR_NUM, NULL, NULL   },
-       { "voice", VOICE, VAR_NUM, NULL, NULL },
-       { "freq", FREQUENCY, VAR_NUM, NULL, NULL },
-       { "lang", LANG, VAR_NUM, NULL, NULL },
-       { "chartab", CHARTAB, VAR_PROC, NULL, NULL },
-       { "direct", DIRECT, VAR_NUM, NULL, NULL },
-       { "pause", PAUSE, VAR_STRING, spk_str_pause, NULL },
-};
-
-static struct st_var_header *var_ptrs[MAXVARS] = { NULL, NULL, NULL };
-
-static struct punc_var_t punc_vars[] = {
-       { PUNC_SOME, 1 },
-       { PUNC_MOST, 2 },
-       { PUNC_ALL, 3 },
-       { DELIM, 4 },
-       { REPEATS, 5 },
-       { EXNUMBER, 6 },
-       { -1, -1 },
-};
-
-int spk_chartab_get_value(char *keyword)
-{
-       int value = 0;
-
-       if (!strcmp(keyword, "ALPHA"))
-               value = ALPHA;
-       else if (!strcmp(keyword, "B_CTL"))
-               value = B_CTL;
-       else if (!strcmp(keyword, "WDLM"))
-               value = WDLM;
-       else if (!strcmp(keyword, "A_PUNC"))
-               value = A_PUNC;
-       else if (!strcmp(keyword, "PUNC"))
-               value = PUNC;
-       else if (!strcmp(keyword, "NUM"))
-               value = NUM;
-       else if (!strcmp(keyword, "A_CAP"))
-               value = A_CAP;
-       else if (!strcmp(keyword, "B_CAPSYM"))
-               value = B_CAPSYM;
-       else if (!strcmp(keyword, "B_SYM"))
-               value = B_SYM;
-       return value;
-}
-
-void speakup_register_var(struct var_t *var)
-{
-       static char nothing[2] = "\0";
-       int i;
-       struct st_var_header *p_header;
-
-       BUG_ON(!var || var->var_id < 0 || var->var_id >= MAXVARS);
-       if (!var_ptrs[0]) {
-               for (i = 0; i < MAXVARS; i++) {
-                       p_header = &var_headers[i];
-                       var_ptrs[p_header->var_id] = p_header;
-                       p_header->data = NULL;
-               }
-       }
-       p_header = var_ptrs[var->var_id];
-       if (p_header->data)
-               return;
-       p_header->data = var;
-       switch (p_header->var_type) {
-       case VAR_STRING:
-               spk_set_string_var(nothing, p_header, 0);
-               break;
-       case VAR_NUM:
-       case VAR_TIME:
-               spk_set_num_var(0, p_header, E_DEFAULT);
-               break;
-       default:
-               break;
-       }
-}
-
-void speakup_unregister_var(enum var_id_t var_id)
-{
-       struct st_var_header *p_header;
-
-       BUG_ON(var_id < 0 || var_id >= MAXVARS);
-       p_header = var_ptrs[var_id];
-       p_header->data = NULL;
-}
-
-struct st_var_header *spk_get_var_header(enum var_id_t var_id)
-{
-       struct st_var_header *p_header;
-
-       if (var_id < 0 || var_id >= MAXVARS)
-               return NULL;
-       p_header = var_ptrs[var_id];
-       if (!p_header->data)
-               return NULL;
-       return p_header;
-}
-
-struct st_var_header *spk_var_header_by_name(const char *name)
-{
-       int i;
-
-       if (!name)
-               return NULL;
-
-       for (i = 0; i < MAXVARS; i++) {
-               if (strcmp(name, var_ptrs[i]->name) == 0)
-                       return var_ptrs[i];
-       }
-       return NULL;
-}
-
-struct var_t *spk_get_var(enum var_id_t var_id)
-{
-       BUG_ON(var_id < 0 || var_id >= MAXVARS);
-       BUG_ON(!var_ptrs[var_id]);
-       return var_ptrs[var_id]->data;
-}
-EXPORT_SYMBOL_GPL(spk_get_var);
-
-struct punc_var_t *spk_get_punc_var(enum var_id_t var_id)
-{
-       struct punc_var_t *rv = NULL;
-       struct punc_var_t *where;
-
-       where = punc_vars;
-       while ((where->var_id != -1) && (!rv)) {
-               if (where->var_id == var_id)
-                       rv = where;
-               else
-                       where++;
-       }
-       return rv;
-}
-
-/* handlers for setting vars */
-int spk_set_num_var(int input, struct st_var_header *var, int how)
-{
-       int val;
-       int *p_val = var->p_val;
-       char buf[32];
-       char *cp;
-       struct var_t *var_data = var->data;
-
-       if (!var_data)
-               return -ENODATA;
-
-       val = var_data->u.n.value;
-       switch (how) {
-       case E_NEW_DEFAULT:
-               if (input < var_data->u.n.low || input > var_data->u.n.high)
-                       return -ERANGE;
-               var_data->u.n.default_val = input;
-               return 0;
-       case E_DEFAULT:
-               val = var_data->u.n.default_val;
-               break;
-       case E_SET:
-               val = input;
-               break;
-       case E_INC:
-               val += input;
-               break;
-       case E_DEC:
-               val -= input;
-               break;
-       }
-
-       if (val < var_data->u.n.low || val > var_data->u.n.high)
-               return -ERANGE;
-
-       var_data->u.n.value = val;
-       if (var->var_type == VAR_TIME && p_val) {
-               *p_val = msecs_to_jiffies(val);
-               return 0;
-       }
-       if (p_val)
-               *p_val = val;
-       if (var->var_id == PUNC_LEVEL) {
-               spk_punc_mask = spk_punc_masks[val];
-               return 0;
-       }
-       if (var_data->u.n.multiplier != 0)
-               val *= var_data->u.n.multiplier;
-       val += var_data->u.n.offset;
-       if (var->var_id < FIRST_SYNTH_VAR || !synth)
-               return 0;
-       if (synth->synth_adjust)
-               return synth->synth_adjust(var);
-
-       if (!var_data->u.n.synth_fmt)
-               return 0;
-       if (var->var_id == PITCH)
-               cp = spk_pitch_buff;
-       else
-               cp = buf;
-       if (!var_data->u.n.out_str)
-               sprintf(cp, var_data->u.n.synth_fmt, (int)val);
-       else
-               sprintf(cp, var_data->u.n.synth_fmt,
-                       var_data->u.n.out_str[val]);
-       synth_printf("%s", cp);
-       return 0;
-}
-
-int spk_set_string_var(const char *page, struct st_var_header *var, int len)
-{
-       struct var_t *var_data = var->data;
-
-       if (!var_data)
-               return -ENODATA;
-       if (len > MAXVARLEN)
-               return -E2BIG;
-       if (!len) {
-               if (!var_data->u.s.default_val)
-                       return 0;
-               if (!var->p_val)
-                       var->p_val = var_data->u.s.default_val;
-               if (var->p_val != var_data->u.s.default_val)
-                       strcpy((char *)var->p_val, var_data->u.s.default_val);
-               return -ERESTART;
-       } else if (var->p_val) {
-               strcpy((char *)var->p_val, page);
-       } else {
-               return -E2BIG;
-       }
-       return 0;
-}
-
-/*
- * spk_set_mask_bits sets or clears the punc/delim/repeat bits,
- * if input is null uses the defaults.
- * values for how: 0 clears bits of chars supplied,
- * 1 clears allk, 2 sets bits for chars
- */
-int spk_set_mask_bits(const char *input, const int which, const int how)
-{
-       u_char *cp;
-       short mask = spk_punc_info[which].mask;
-
-       if (how & 1) {
-               for (cp = (u_char *)spk_punc_info[3].value; *cp; cp++)
-                       spk_chartab[*cp] &= ~mask;
-       }
-       cp = (u_char *)input;
-       if (!cp) {
-               cp = spk_punc_info[which].value;
-       } else {
-               for (; *cp; cp++) {
-                       if (*cp < SPACE)
-                               break;
-                       if (mask < PUNC) {
-                               if (!(spk_chartab[*cp] & PUNC))
-                                       break;
-                       } else if (spk_chartab[*cp] & B_NUM) {
-                               break;
-                       }
-               }
-               if (*cp)
-                       return -EINVAL;
-               cp = (u_char *)input;
-       }
-       if (how & 2) {
-               for (; *cp; cp++)
-                       if (*cp > SPACE)
-                               spk_chartab[*cp] |= mask;
-       } else {
-               for (; *cp; cp++)
-                       if (*cp > SPACE)
-                               spk_chartab[*cp] &= ~mask;
-       }
-       return 0;
-}
-
-char *spk_strlwr(char *s)
-{
-       char *p;
-
-       if (!s)
-               return NULL;
-
-       for (p = s; *p; p++)
-               *p = tolower(*p);
-       return s;
-}
-
-char *spk_s2uchar(char *start, char *dest)
-{
-       int val;
-
-       /* Do not replace with kstrtoul: here we need start to be updated */
-       val = simple_strtoul(skip_spaces(start), &start, 10);
-       if (*start == ',')
-               start++;
-       *dest = (u_char)val;
-       return start;
-}